From 1b10e97e5e62b3b62dc78270650effdb3905a81c Mon Sep 17 00:00:00 2001 From: thiagoralves Date: Thu, 14 Jun 2018 10:43:51 -0700 Subject: [PATCH] First commit. OpenPLC v3 beta 1 --- README.md | 26 +- install.sh | 253 + utils/apt-cyg/apt-cyg | 673 + utils/apt-cyg/wget.exe | Bin 0 -> 252416 bytes utils/dnp3_src/CHANGELOG.markdown | 209 + utils/dnp3_src/CMakeLists.txt | 260 + utils/dnp3_src/NOTICE | 19 + utils/dnp3_src/README.md | 31 + utils/dnp3_src/appveyor.yml | 42 + utils/dnp3_src/build-dotnet.bat | 43 + utils/dnp3_src/cmake/inc/msvc.cmake | 24 + utils/dnp3_src/cmake/inc/posix.cmake | 52 + utils/dnp3_src/cmake/settings.cmake | 6 + utils/dnp3_src/config/APACHE_LICENSE_HEADER | 19 + utils/dnp3_src/config/astyle.cfg | 9 + utils/dnp3_src/config/doxygen.config | 2460 + .../config/doxygen_files/img/opendnp3.png | Bin 0 -> 4244 bytes .../config/doxygen_files/mainpage.dox | 21 + utils/dnp3_src/config/formatHeaders.xml | 49 + utils/dnp3_src/config/gecapache.licenseheader | 23 + utils/dnp3_src/config/src-footer.inc | 2 + utils/dnp3_src/config/src-header.inc | 17 + utils/dnp3_src/cpp/examples/decoder/main.cpp | 92 + .../cpp/examples/master-gprs/main.cpp | 77 + utils/dnp3_src/cpp/examples/master/main.cpp | 165 + .../dnp3_src/cpp/examples/outstation/main.cpp | 166 + .../cpp/examples/tls/master-gprs/main.cpp | 104 + .../dnp3_src/cpp/examples/tls/master/main.cpp | 178 + .../cpp/examples/tls/outstation/main.cpp | 196 + .../cpp/libs/include/asiodnp3/ConsoleLogger.h | 61 + .../cpp/libs/include/asiodnp3/DNP3Manager.h | 221 + .../libs/include/asiodnp3/DatabaseConfig.h | 83 + .../include/asiodnp3/DefaultListenCallbacks.h | 62 + .../asiodnp3/DefaultMasterApplication.h | 63 + .../cpp/libs/include/asiodnp3/ErrorCodes.h | 79 + .../cpp/libs/include/asiodnp3/IChannel.h | 105 + .../libs/include/asiodnp3/IChannelListener.h | 47 + .../libs/include/asiodnp3/IListenCallbacks.h | 94 + .../cpp/libs/include/asiodnp3/IMaster.h | 44 + .../libs/include/asiodnp3/IMasterOperations.h | 124 + .../cpp/libs/include/asiodnp3/IMasterScan.h | 43 + .../libs/include/asiodnp3/IMasterSession.h | 47 + .../cpp/libs/include/asiodnp3/IOutstation.h | 63 + .../libs/include/asiodnp3/ISessionAcceptor.h | 54 + .../cpp/libs/include/asiodnp3/IStack.h | 60 + .../libs/include/asiodnp3/MasterStackConfig.h | 48 + .../libs/include/asiodnp3/MasterTCPServer.h | 89 + .../include/asiodnp3/OutstationStackConfig.h | 63 + .../asiodnp3/PrintingChannelListener.h | 57 + .../asiodnp3/PrintingCommandCallback.h | 41 + .../include/asiodnp3/PrintingSOEHandler.h | 126 + .../cpp/libs/include/asiodnp3/UpdateBuilder.h | 58 + .../cpp/libs/include/asiodnp3/Updates.h | 66 + .../cpp/libs/include/asiodnp3/X509Info.h | 62 + .../libs/include/asiopal/ASIOSerialHelpers.h | 37 + .../cpp/libs/include/asiopal/ChannelRetry.h | 72 + .../cpp/libs/include/asiopal/Executor.h | 120 + .../cpp/libs/include/asiopal/IAsyncChannel.h | 168 + .../libs/include/asiopal/IChannelCallbacks.h | 40 + .../cpp/libs/include/asiopal/IListener.h | 43 + utils/dnp3_src/cpp/libs/include/asiopal/IO.h | 46 + .../libs/include/asiopal/IOpenDelayStrategy.h | 63 + .../cpp/libs/include/asiopal/IPEndpoint.h | 55 + .../libs/include/asiopal/IResourceManager.h | 57 + .../asiopal/LoggingConnectionCondition.h | 57 + .../libs/include/asiopal/ResourceManager.h | 77 + .../cpp/libs/include/asiopal/SerialChannel.h | 59 + .../cpp/libs/include/asiopal/SerialTypes.h | 74 + .../cpp/libs/include/asiopal/SocketChannel.h | 55 + .../cpp/libs/include/asiopal/SocketHelpers.h | 59 + .../cpp/libs/include/asiopal/SteadyClock.h | 82 + .../cpp/libs/include/asiopal/Synchronized.h | 78 + .../cpp/libs/include/asiopal/TCPClient.h | 84 + .../cpp/libs/include/asiopal/TCPServer.h | 86 + .../cpp/libs/include/asiopal/TLSConfig.h | 98 + .../cpp/libs/include/asiopal/ThreadPool.h | 81 + .../libs/include/asiopal/TimeConversions.h | 48 + .../dnp3_src/cpp/libs/include/asiopal/Timer.h | 59 + .../cpp/libs/include/asiopal/UTCTimeSource.h | 48 + .../cpp/libs/include/dnp3decode/Decoder.h | 55 + .../include/dnp3decode/IDecoderCallbacks.h | 41 + .../cpp/libs/include/opendnp3/LogLevels.h | 77 + .../libs/include/opendnp3/StackStatistics.h | 97 + .../include/opendnp3/app/AnalogCommandEvent.h | 53 + .../libs/include/opendnp3/app/AnalogOutput.h | 127 + .../libs/include/opendnp3/app/AppConstants.h | 38 + .../opendnp3/app/BaseMeasurementTypes.h | 77 + .../include/opendnp3/app/BinaryCommandEvent.h | 69 + .../libs/include/opendnp3/app/ClassField.h | 93 + .../opendnp3/app/ControlRelayOutputBlock.h | 89 + .../cpp/libs/include/opendnp3/app/DNPTime.h | 34 + .../libs/include/opendnp3/app/EventCells.h | 80 + .../libs/include/opendnp3/app/EventTriggers.h | 47 + .../cpp/libs/include/opendnp3/app/EventType.h | 52 + .../cpp/libs/include/opendnp3/app/Flags.h | 112 + .../include/opendnp3/app/GroupVariationID.h | 48 + .../cpp/libs/include/opendnp3/app/IINField.h | 198 + .../libs/include/opendnp3/app/ITransactable.h | 102 + .../cpp/libs/include/opendnp3/app/Indexed.h | 56 + .../include/opendnp3/app/MeasurementInfo.h | 175 + .../opendnp3/app/MeasurementTypeSpecs.h | 155 + .../include/opendnp3/app/MeasurementTypes.h | 200 + .../cpp/libs/include/opendnp3/app/OctetData.h | 59 + .../libs/include/opendnp3/app/OctetString.h | 52 + .../libs/include/opendnp3/app/QualityMasks.h | 44 + .../libs/include/opendnp3/app/SecurityStat.h | 60 + .../opendnp3/app/parsing/ICollection.h | 115 + .../opendnp3/gen/AnalogOutputStatusQuality.h | 54 + .../libs/include/opendnp3/gen/AnalogQuality.h | 54 + .../include/opendnp3/gen/AssignClassType.h | 45 + .../libs/include/opendnp3/gen/Attributes.h | 35 + .../libs/include/opendnp3/gen/AuthErrorCode.h | 63 + .../opendnp3/gen/BinaryOutputStatusQuality.h | 54 + .../libs/include/opendnp3/gen/BinaryQuality.h | 54 + .../include/opendnp3/gen/CertificateType.h | 47 + .../include/opendnp3/gen/ChallengeReason.h | 45 + .../libs/include/opendnp3/gen/ChannelState.h | 47 + .../include/opendnp3/gen/CommandPointState.h | 51 + .../libs/include/opendnp3/gen/CommandStatus.h | 84 + .../include/opendnp3/gen/ConfigAuthMode.h | 42 + .../libs/include/opendnp3/gen/ControlCode.h | 72 + .../include/opendnp3/gen/CounterQuality.h | 54 + .../cpp/libs/include/opendnp3/gen/DoubleBit.h | 49 + .../opendnp3/gen/DoubleBitBinaryQuality.h | 54 + .../gen/EventAnalogOutputStatusVariation.h | 43 + .../opendnp3/gen/EventAnalogVariation.h | 43 + .../gen/EventBinaryOutputStatusVariation.h | 37 + .../opendnp3/gen/EventBinaryVariation.h | 38 + .../opendnp3/gen/EventCounterVariation.h | 39 + .../opendnp3/gen/EventDoubleBinaryVariation.h | 38 + .../gen/EventFrozenCounterVariation.h | 39 + .../cpp/libs/include/opendnp3/gen/EventMode.h | 44 + .../opendnp3/gen/EventSecurityStatVariation.h | 37 + .../cpp/libs/include/opendnp3/gen/FlagsType.h | 48 + .../libs/include/opendnp3/gen/FlowControl.h | 44 + .../opendnp3/gen/FrozenCounterQuality.h | 54 + .../libs/include/opendnp3/gen/FunctionCode.h | 115 + .../include/opendnp3/gen/GroupVariation.h | 174 + .../cpp/libs/include/opendnp3/gen/HMACType.h | 55 + .../cpp/libs/include/opendnp3/gen/IndexMode.h | 42 + .../libs/include/opendnp3/gen/IntervalUnits.h | 65 + .../include/opendnp3/gen/KeyChangeMethod.h | 50 + .../cpp/libs/include/opendnp3/gen/KeyStatus.h | 50 + .../include/opendnp3/gen/KeyWrapAlgorithm.h | 46 + .../libs/include/opendnp3/gen/LinkFunction.h | 51 + .../libs/include/opendnp3/gen/LinkStatus.h | 43 + .../include/opendnp3/gen/MasterTaskType.h | 48 + .../libs/include/opendnp3/gen/OperateType.h | 44 + .../cpp/libs/include/opendnp3/gen/Parity.h | 44 + .../libs/include/opendnp3/gen/PointClass.h | 46 + .../libs/include/opendnp3/gen/QualifierCode.h | 50 + .../libs/include/opendnp3/gen/RestartMode.h | 44 + .../libs/include/opendnp3/gen/RestartType.h | 42 + .../include/opendnp3/gen/SecurityStatIndex.h | 74 + .../gen/StaticAnalogOutputStatusVariation.h | 39 + .../opendnp3/gen/StaticAnalogVariation.h | 41 + .../gen/StaticBinaryOutputStatusVariation.h | 36 + .../opendnp3/gen/StaticBinaryVariation.h | 37 + .../opendnp3/gen/StaticCounterVariation.h | 39 + .../gen/StaticDoubleBinaryVariation.h | 36 + .../gen/StaticFrozenCounterVariation.h | 41 + .../gen/StaticSecurityStatVariation.h | 36 + .../gen/StaticTimeAndIntervalVariation.h | 36 + .../include/opendnp3/gen/StaticTypeBitmask.h | 46 + .../cpp/libs/include/opendnp3/gen/StopBits.h | 45 + .../include/opendnp3/gen/TaskCompletion.h | 57 + .../libs/include/opendnp3/gen/TimeSyncMode.h | 42 + .../libs/include/opendnp3/gen/TimestampMode.h | 44 + .../libs/include/opendnp3/gen/UserOperation.h | 45 + .../cpp/libs/include/opendnp3/gen/UserRole.h | 50 + .../include/opendnp3/link/ILinkListener.h | 52 + .../libs/include/opendnp3/link/LinkConfig.h | 94 + .../include/opendnp3/link/LinkHeaderFields.h | 46 + .../include/opendnp3/link/LinkStatistics.h | 94 + .../opendnp3/master/CommandCallbackT.h | 35 + .../opendnp3/master/CommandPointResult.h | 69 + .../libs/include/opendnp3/master/CommandSet.h | 156 + .../libs/include/opendnp3/master/HeaderInfo.h | 80 + .../include/opendnp3/master/HeaderTypes.h | 139 + .../opendnp3/master/ICommandCollection.h | 40 + .../opendnp3/master/ICommandProcessor.h | 96 + .../opendnp3/master/ICommandTaskResult.h | 55 + .../opendnp3/master/IMasterApplication.h | 81 + .../include/opendnp3/master/ISOEHandler.h | 72 + .../include/opendnp3/master/ITaskCallback.h | 48 + .../include/opendnp3/master/MasterParams.h | 82 + .../opendnp3/master/RestartOperationResult.h | 57 + .../libs/include/opendnp3/master/TaskConfig.h | 67 + .../cpp/libs/include/opendnp3/master/TaskId.h | 65 + .../libs/include/opendnp3/master/TaskInfo.h | 58 + .../opendnp3/outstation/ApplicationIIN.h | 55 + .../libs/include/opendnp3/outstation/Cell.h | 60 + .../opendnp3/outstation/DatabaseSizes.h | 116 + .../opendnp3/outstation/EventBufferConfig.h | 98 + .../opendnp3/outstation/ICommandHandler.h | 144 + .../outstation/IOutstationApplication.h | 158 + .../opendnp3/outstation/IUpdateHandler.h | 124 + .../opendnp3/outstation/MeasurementConfig.h | 70 + .../opendnp3/outstation/OutstationConfig.h | 55 + .../opendnp3/outstation/OutstationParams.h | 77 + .../outstation/SimpleCommandHandler.h | 112 + .../opendnp3/outstation/StaticTypeBitfield.h | 64 + .../cpp/libs/include/openpal/Configure.h | 83 + .../include/openpal/channel/IPhysicalLayer.h | 150 + .../openpal/channel/IPhysicalLayerCallbacks.h | 57 + .../libs/include/openpal/container/Array.h | 124 + .../include/openpal/container/ArrayView.h | 96 + .../libs/include/openpal/container/Buffer.h | 67 + .../libs/include/openpal/container/HasSize.h | 59 + .../include/openpal/container/LinkedList.h | 401 + .../cpp/libs/include/openpal/container/Pair.h | 42 + .../libs/include/openpal/container/Queue.h | 123 + .../libs/include/openpal/container/RSlice.h | 72 + .../include/openpal/container/RingBuffer.h | 127 + .../include/openpal/container/SecureBuffer.h | 50 + .../libs/include/openpal/container/Settable.h | 117 + .../include/openpal/container/StaticBuffer.h | 85 + .../libs/include/openpal/container/WSlice.h | 74 + .../libs/include/openpal/executor/IExecutor.h | 62 + .../openpal/executor/IMonotonicTimeSource.h | 41 + .../libs/include/openpal/executor/ITimer.h | 42 + .../include/openpal/executor/IUTCTimeSource.h | 63 + .../openpal/executor/MonotonicTimestamp.h | 62 + .../include/openpal/executor/TimeDuration.h | 104 + .../libs/include/openpal/executor/TimerRef.h | 133 + .../include/openpal/executor/UTCTimestamp.h | 48 + .../include/openpal/logging/ILogHandler.h | 48 + .../libs/include/openpal/logging/Location.h | 33 + .../libs/include/openpal/logging/LogEntry.h | 58 + .../libs/include/openpal/logging/LogFilters.h | 65 + .../libs/include/openpal/logging/LogLevels.h | 61 + .../libs/include/openpal/logging/LogMacros.h | 91 + .../cpp/libs/include/openpal/logging/Logger.h | 108 + .../openpal/logging/StringFormatting.h | 42 + .../openpal/serialization/ByteSerialization.h | 69 + .../openpal/serialization/DoubleFloat.h | 54 + .../openpal/serialization/FloatByteOrder.h | 53 + .../include/openpal/serialization/Format.h | 62 + .../include/openpal/serialization/Parse.h | 63 + .../openpal/serialization/Serialization.h | 44 + .../serialization/SerializationTemplatesLE.h | 131 + .../openpal/serialization/Serializer.h | 81 + .../openpal/serialization/SingleFloat.h | 54 + .../include/openpal/serialization/UInt48LE.h | 63 + .../openpal/serialization/UInt48Type.h | 50 + .../libs/include/openpal/util/Comparisons.h | 61 + .../cpp/libs/include/openpal/util/Finally.h | 67 + .../cpp/libs/include/openpal/util/Limits.h | 35 + .../libs/include/openpal/util/SequenceNum.h | 82 + .../cpp/libs/include/openpal/util/ToHex.h | 33 + .../libs/include/openpal/util/Uncopyable.h | 54 + .../cpp/libs/src/asiodnp3/ConsoleLogger.cpp | 57 + .../cpp/libs/src/asiodnp3/Conversions.cpp | 46 + .../cpp/libs/src/asiodnp3/Conversions.h | 38 + .../cpp/libs/src/asiodnp3/DNP3Channel.cpp | 150 + .../cpp/libs/src/asiodnp3/DNP3Channel.h | 97 + .../cpp/libs/src/asiodnp3/DNP3Manager.cpp | 129 + .../cpp/libs/src/asiodnp3/DNP3ManagerImpl.cpp | 275 + .../cpp/libs/src/asiodnp3/DNP3ManagerImpl.h | 135 + .../src/asiodnp3/DefaultListenCallbacks.cpp | 82 + .../src/asiodnp3/DefaultMasterApplication.cpp | 36 + .../cpp/libs/src/asiodnp3/ErrorCodes.cpp | 48 + .../cpp/libs/src/asiodnp3/IOHandler.cpp | 352 + .../cpp/libs/src/asiodnp3/IOHandler.h | 227 + .../cpp/libs/src/asiodnp3/LinkSession.cpp | 202 + .../cpp/libs/src/asiodnp3/LinkSession.h | 123 + .../cpp/libs/src/asiodnp3/MasterScan.cpp | 45 + .../cpp/libs/src/asiodnp3/MasterScan.h | 68 + .../libs/src/asiodnp3/MasterSessionStack.cpp | 231 + .../libs/src/asiodnp3/MasterSessionStack.h | 117 + .../cpp/libs/src/asiodnp3/MasterStack.cpp | 227 + .../cpp/libs/src/asiodnp3/MasterStack.h | 147 + .../cpp/libs/src/asiodnp3/MasterTCPServer.cpp | 103 + .../cpp/libs/src/asiodnp3/OutstationStack.cpp | 126 + .../cpp/libs/src/asiodnp3/OutstationStack.h | 123 + .../src/asiodnp3/PrintingCommandCallback.cpp | 48 + .../libs/src/asiodnp3/PrintingSOEHandler.cpp | 141 + .../cpp/libs/src/asiodnp3/SerialIOHandler.cpp | 97 + .../cpp/libs/src/asiodnp3/SerialIOHandler.h | 82 + .../cpp/libs/src/asiodnp3/StackBase.h | 97 + .../libs/src/asiodnp3/TCPClientIOHandler.cpp | 115 + .../libs/src/asiodnp3/TCPClientIOHandler.h | 87 + .../libs/src/asiodnp3/TCPServerIOHandler.cpp | 103 + .../libs/src/asiodnp3/TCPServerIOHandler.h | 104 + .../cpp/libs/src/asiodnp3/UpdateBuilder.cpp | 107 + .../libs/src/asiodnp3/tls/MasterTLSServer.cpp | 137 + .../libs/src/asiodnp3/tls/MasterTLSServer.h | 98 + .../src/asiodnp3/tls/TLSClientIOHandler.cpp | 125 + .../src/asiodnp3/tls/TLSClientIOHandler.h | 92 + .../src/asiodnp3/tls/TLSServerIOHandler.cpp | 97 + .../src/asiodnp3/tls/TLSServerIOHandler.h | 116 + .../libs/src/asiopal/ASIOSerialHelpers.cpp | 131 + .../cpp/libs/src/asiopal/ChannelRetry.cpp | 45 + .../cpp/libs/src/asiopal/Executor.cpp | 118 + .../libs/src/asiopal/IOpenDelayStrategy.cpp | 42 + .../cpp/libs/src/asiopal/ResourceManager.cpp | 54 + .../cpp/libs/src/asiopal/SerialChannel.cpp | 77 + .../cpp/libs/src/asiopal/SocketChannel.cpp | 59 + .../cpp/libs/src/asiopal/TCPClient.cpp | 153 + .../cpp/libs/src/asiopal/TCPServer.cpp | 132 + .../cpp/libs/src/asiopal/ThreadPool.cpp | 98 + .../cpp/libs/src/asiopal/TimeConversions.cpp | 39 + utils/dnp3_src/cpp/libs/src/asiopal/Timer.cpp | 47 + .../cpp/libs/src/asiopal/UTCTimeSource.cpp | 43 + .../cpp/libs/src/asiopal/tls/SSLContext.cpp | 118 + .../cpp/libs/src/asiopal/tls/SSLContext.h | 57 + .../cpp/libs/src/asiopal/tls/TLSClient.cpp | 221 + .../cpp/libs/src/asiopal/tls/TLSClient.h | 101 + .../cpp/libs/src/asiopal/tls/TLSContext.h | 50 + .../cpp/libs/src/asiopal/tls/TLSServer.cpp | 148 + .../cpp/libs/src/asiopal/tls/TLSServer.h | 88 + .../libs/src/asiopal/tls/TLSStreamChannel.cpp | 62 + .../libs/src/asiopal/tls/TLSStreamChannel.h | 54 + .../cpp/libs/src/dnp3decode/Decoder.cpp | 54 + .../cpp/libs/src/dnp3decode/DecoderImpl.cpp | 173 + .../cpp/libs/src/dnp3decode/DecoderImpl.h | 64 + .../dnp3_src/cpp/libs/src/dnp3decode/Indent.h | 54 + .../libs/src/dnp3decode/LoggingHandler.cpp | 604 + .../cpp/libs/src/dnp3decode/LoggingHandler.h | 304 + .../cpp/libs/src/opendnp3/LayerInterfaces.h | 127 + .../cpp/libs/src/opendnp3/LogLevels.cpp | 85 + utils/dnp3_src/cpp/libs/src/opendnp3/Route.h | 52 + .../libs/src/opendnp3/app/APDUBuilders.cpp | 123 + .../cpp/libs/src/opendnp3/app/APDUBuilders.h | 57 + .../cpp/libs/src/opendnp3/app/APDUHeader.cpp | 45 + .../cpp/libs/src/opendnp3/app/APDUHeader.h | 71 + .../cpp/libs/src/opendnp3/app/APDULogging.cpp | 123 + .../cpp/libs/src/opendnp3/app/APDULogging.h | 61 + .../cpp/libs/src/opendnp3/app/APDURequest.cpp | 40 + .../cpp/libs/src/opendnp3/app/APDURequest.h | 49 + .../libs/src/opendnp3/app/APDUResponse.cpp | 48 + .../cpp/libs/src/opendnp3/app/APDUResponse.h | 48 + .../cpp/libs/src/opendnp3/app/APDUWrapper.cpp | 93 + .../cpp/libs/src/opendnp3/app/APDUWrapper.h | 75 + .../src/opendnp3/app/AnalogCommandEvent.cpp | 68 + .../libs/src/opendnp3/app/AnalogOutput.cpp | 85 + .../libs/src/opendnp3/app/AppControlField.cpp | 85 + .../libs/src/opendnp3/app/AppControlField.h | 67 + .../cpp/libs/src/opendnp3/app/AppSeqNum.h | 35 + .../src/opendnp3/app/BinaryCommandEvent.cpp | 95 + .../opendnp3/app/BitfieldRangeWriteIterator.h | 121 + .../cpp/libs/src/opendnp3/app/ClassField.cpp | 136 + .../opendnp3/app/ControlRelayOutputBlock.cpp | 51 + .../src/opendnp3/app/CountWriteIterator.h | 96 + .../libs/src/opendnp3/app/DNP3Serializer.h | 54 + .../cpp/libs/src/opendnp3/app/DownSampling.h | 68 + .../libs/src/opendnp3/app/EventTriggers.cpp | 50 + .../cpp/libs/src/opendnp3/app/Functions.cpp | 59 + .../cpp/libs/src/opendnp3/app/Functions.h | 60 + .../src/opendnp3/app/GroupVariationRecord.cpp | 177 + .../src/opendnp3/app/GroupVariationRecord.h | 147 + .../libs/src/opendnp3/app/HeaderWriter.cpp | 94 + .../cpp/libs/src/opendnp3/app/HeaderWriter.h | 241 + .../cpp/libs/src/opendnp3/app/IINField.cpp | 204 + .../cpp/libs/src/opendnp3/app/IINValue.h | 41 + .../libs/src/opendnp3/app/IVariableLength.h | 53 + .../src/opendnp3/app/MeasurementFactory.h | 223 + .../src/opendnp3/app/MeasurementTypes.cpp | 183 + .../cpp/libs/src/opendnp3/app/OctetData.cpp | 49 + .../src/opendnp3/app/PrefixedWriteIterator.h | 104 + .../libs/src/opendnp3/app/QualityFlags.cpp | 45 + .../cpp/libs/src/opendnp3/app/QualityFlags.h | 47 + .../cpp/libs/src/opendnp3/app/Range.h | 129 + .../src/opendnp3/app/RangeWriteIterator.h | 101 + .../libs/src/opendnp3/app/SecurityStat.cpp | 64 + .../cpp/libs/src/opendnp3/app/SequenceInfo.h | 34 + .../cpp/libs/src/opendnp3/app/TxBuffer.h | 72 + .../opendnp3/app/WriteConversionTemplates.h | 190 + .../libs/src/opendnp3/app/WriteConversions.h | 293 + .../opendnp3/app/parsing/APDUHeaderParser.cpp | 66 + .../opendnp3/app/parsing/APDUHeaderParser.h | 47 + .../src/opendnp3/app/parsing/APDUParser.cpp | 166 + .../src/opendnp3/app/parsing/APDUParser.h | 65 + .../src/opendnp3/app/parsing/BitReader.cpp | 59 + .../libs/src/opendnp3/app/parsing/BitReader.h | 39 + .../opendnp3/app/parsing/BufferedCollection.h | 71 + .../src/opendnp3/app/parsing/Collections.h | 101 + .../opendnp3/app/parsing/CountIndexParser.cpp | 261 + .../opendnp3/app/parsing/CountIndexParser.h | 132 + .../src/opendnp3/app/parsing/CountParser.cpp | 127 + .../src/opendnp3/app/parsing/CountParser.h | 99 + .../opendnp3/app/parsing/FreeFormatParser.cpp | 159 + .../opendnp3/app/parsing/FreeFormatParser.h | 69 + .../libs/src/opendnp3/app/parsing/Functions.h | 56 + .../src/opendnp3/app/parsing/IAPDUHandler.cpp | 579 + .../src/opendnp3/app/parsing/IAPDUHandler.h | 236 + .../src/opendnp3/app/parsing/IWhiteList.h | 45 + .../src/opendnp3/app/parsing/NumParser.cpp | 125 + .../libs/src/opendnp3/app/parsing/NumParser.h | 69 + .../app/parsing/ObjectHeaderParser.cpp | 68 + .../opendnp3/app/parsing/ObjectHeaderParser.h | 58 + .../src/opendnp3/app/parsing/ParseResult.h | 57 + .../src/opendnp3/app/parsing/ParserSettings.h | 71 + .../src/opendnp3/app/parsing/PrefixFields.h | 142 + .../src/opendnp3/app/parsing/RangeParser.cpp | 204 + .../src/opendnp3/app/parsing/RangeParser.h | 199 + .../cpp/libs/src/opendnp3/gen/Attributes.cpp | 316 + .../libs/src/opendnp3/gen/AuthErrorCode.cpp | 86 + .../libs/src/opendnp3/gen/CertificateType.cpp | 54 + .../libs/src/opendnp3/gen/ChallengeReason.cpp | 50 + .../libs/src/opendnp3/gen/ChannelState.cpp | 40 + .../src/opendnp3/gen/CommandPointState.cpp | 46 + .../libs/src/opendnp3/gen/CommandStatus.cpp | 126 + .../cpp/libs/src/opendnp3/gen/ControlCode.cpp | 102 + .../cpp/libs/src/opendnp3/gen/DoubleBit.cpp | 58 + .../cpp/libs/src/opendnp3/gen/FlagsType.cpp | 70 + .../cpp/libs/src/opendnp3/gen/FlowControl.cpp | 54 + .../libs/src/opendnp3/gen/FunctionCode.cpp | 190 + .../libs/src/opendnp3/gen/GroupVariation.cpp | 574 + .../cpp/libs/src/opendnp3/gen/HMACType.cpp | 70 + .../libs/src/opendnp3/gen/IntervalUnits.cpp | 90 + .../libs/src/opendnp3/gen/KeyChangeMethod.cpp | 78 + .../cpp/libs/src/opendnp3/gen/KeyStatus.cpp | 62 + .../src/opendnp3/gen/KeyWrapAlgorithm.cpp | 54 + .../libs/src/opendnp3/gen/LinkFunction.cpp | 82 + .../cpp/libs/src/opendnp3/gen/LinkStatus.cpp | 38 + .../libs/src/opendnp3/gen/MasterTaskType.cpp | 52 + .../cpp/libs/src/opendnp3/gen/Parity.cpp | 54 + .../libs/src/opendnp3/gen/QualifierCode.cpp | 78 + .../cpp/libs/src/opendnp3/gen/StopBits.cpp | 58 + .../libs/src/opendnp3/gen/TaskCompletion.cpp | 50 + .../libs/src/opendnp3/gen/UserOperation.cpp | 58 + .../cpp/libs/src/opendnp3/gen/UserRole.cpp | 78 + .../cpp/libs/src/opendnp3/link/CRC.cpp | 94 + .../dnp3_src/cpp/libs/src/opendnp3/link/CRC.h | 51 + .../cpp/libs/src/opendnp3/link/IFrameSink.h | 47 + .../cpp/libs/src/opendnp3/link/ILinkLayer.h | 47 + .../cpp/libs/src/opendnp3/link/ILinkSession.h | 43 + .../cpp/libs/src/opendnp3/link/ILinkTx.h | 50 + .../src/opendnp3/link/ITransportSegment.h | 47 + .../libs/src/opendnp3/link/LinkContext.cpp | 431 + .../cpp/libs/src/opendnp3/link/LinkContext.h | 155 + .../cpp/libs/src/opendnp3/link/LinkFrame.cpp | 200 + .../cpp/libs/src/opendnp3/link/LinkFrame.h | 99 + .../cpp/libs/src/opendnp3/link/LinkHeader.cpp | 95 + .../cpp/libs/src/opendnp3/link/LinkHeader.h | 114 + .../src/opendnp3/link/LinkHeaderFields.cpp | 45 + .../cpp/libs/src/opendnp3/link/LinkLayer.cpp | 102 + .../cpp/libs/src/opendnp3/link/LinkLayer.h | 62 + .../src/opendnp3/link/LinkLayerConstants.h | 65 + .../src/opendnp3/link/LinkLayerParser.cpp | 342 + .../libs/src/opendnp3/link/LinkLayerParser.h | 107 + .../src/opendnp3/link/PriLinkLayerStates.cpp | 359 + .../src/opendnp3/link/PriLinkLayerStates.h | 186 + .../src/opendnp3/link/SecLinkLayerStates.cpp | 139 + .../src/opendnp3/link/SecLinkLayerStates.h | 152 + .../src/opendnp3/link/ShiftableBuffer.cpp | 88 + .../libs/src/opendnp3/link/ShiftableBuffer.h | 104 + .../cpp/libs/src/opendnp3/link/Singleton.h | 39 + .../src/opendnp3/master/AssignClassTask.cpp | 79 + .../src/opendnp3/master/AssignClassTask.h | 82 + .../src/opendnp3/master/ClearRestartTask.cpp | 86 + .../src/opendnp3/master/ClearRestartTask.h | 84 + .../libs/src/opendnp3/master/CommandSet.cpp | 107 + .../src/opendnp3/master/CommandSetOps.cpp | 150 + .../libs/src/opendnp3/master/CommandSetOps.h | 105 + .../libs/src/opendnp3/master/CommandTask.cpp | 126 + .../libs/src/opendnp3/master/CommandTask.h | 111 + .../src/opendnp3/master/CommandTaskResult.cpp | 73 + .../src/opendnp3/master/CommandTaskResult.h | 56 + .../master/DisableUnsolicitedTask.cpp | 71 + .../opendnp3/master/DisableUnsolicitedTask.h | 83 + .../src/opendnp3/master/EmptyResponseTask.cpp | 44 + .../src/opendnp3/master/EmptyResponseTask.h | 58 + .../opendnp3/master/EnableUnsolicitedTask.cpp | 76 + .../opendnp3/master/EnableUnsolicitedTask.h | 93 + .../src/opendnp3/master/EventScanTask.cpp | 95 + .../libs/src/opendnp3/master/EventScanTask.h | 81 + .../libs/src/opendnp3/master/HeaderBuilder.h | 36 + .../libs/src/opendnp3/master/HeaderTypes.cpp | 112 + .../libs/src/opendnp3/master/ICommandHeader.h | 85 + .../libs/src/opendnp3/master/IMasterTask.cpp | 202 + .../libs/src/opendnp3/master/IMasterTask.h | 244 + .../src/opendnp3/master/IScheduleCallback.h | 36 + .../libs/src/opendnp3/master/ITaskFilter.h | 47 + .../libs/src/opendnp3/master/ITaskLock.cpp | 34 + .../cpp/libs/src/opendnp3/master/ITaskLock.h | 72 + .../src/opendnp3/master/MasterContext.cpp | 630 + .../libs/src/opendnp3/master/MasterContext.h | 222 + .../src/opendnp3/master/MasterScheduler.cpp | 140 + .../src/opendnp3/master/MasterScheduler.h | 85 + .../libs/src/opendnp3/master/MasterTasks.cpp | 61 + .../libs/src/opendnp3/master/MasterTasks.h | 74 + .../opendnp3/master/MeasurementHandler.cpp | 254 + .../src/opendnp3/master/MeasurementHandler.h | 178 + .../src/opendnp3/master/MultidropTaskLock.cpp | 96 + .../src/opendnp3/master/MultidropTaskLock.h | 65 + .../libs/src/opendnp3/master/PollTaskBase.cpp | 96 + .../libs/src/opendnp3/master/PollTaskBase.h | 63 + .../opendnp3/master/RestartOperationTask.cpp | 132 + .../opendnp3/master/RestartOperationTask.h | 63 + .../cpp/libs/src/opendnp3/master/ScanResult.h | 40 + .../opendnp3/master/SerialTimeSyncTask.cpp | 125 + .../src/opendnp3/master/SerialTimeSyncTask.h | 93 + .../opendnp3/master/SimpleRequestTaskBase.cpp | 50 + .../opendnp3/master/SimpleRequestTaskBase.h | 83 + .../opendnp3/master/StartupIntegrityPoll.cpp | 75 + .../opendnp3/master/StartupIntegrityPoll.h | 82 + .../src/opendnp3/master/TaskComparison.cpp | 103 + .../libs/src/opendnp3/master/TaskComparison.h | 56 + .../libs/src/opendnp3/master/TaskPriority.h | 57 + .../src/opendnp3/master/TimeSyncHandler.h | 95 + .../src/opendnp3/master/TypedCommandHeader.h | 211 + .../libs/src/opendnp3/master/UserPollTask.cpp | 70 + .../libs/src/opendnp3/master/UserPollTask.h | 98 + .../cpp/libs/src/opendnp3/objects/Group1.cpp | 67 + .../cpp/libs/src/opendnp3/objects/Group1.h | 68 + .../cpp/libs/src/opendnp3/objects/Group10.cpp | 67 + .../cpp/libs/src/opendnp3/objects/Group10.h | 68 + .../cpp/libs/src/opendnp3/objects/Group11.cpp | 101 + .../cpp/libs/src/opendnp3/objects/Group11.h | 83 + .../cpp/libs/src/opendnp3/objects/Group110.h | 37 + .../cpp/libs/src/opendnp3/objects/Group111.h | 37 + .../cpp/libs/src/opendnp3/objects/Group112.h | 37 + .../cpp/libs/src/opendnp3/objects/Group113.h | 37 + .../cpp/libs/src/opendnp3/objects/Group12.cpp | 67 + .../cpp/libs/src/opendnp3/objects/Group12.h | 65 + .../libs/src/opendnp3/objects/Group120.cpp | 820 + .../cpp/libs/src/opendnp3/objects/Group120.h | 439 + .../libs/src/opendnp3/objects/Group121.cpp | 67 + .../cpp/libs/src/opendnp3/objects/Group121.h | 65 + .../libs/src/opendnp3/objects/Group122.cpp | 101 + .../cpp/libs/src/opendnp3/objects/Group122.h | 89 + .../cpp/libs/src/opendnp3/objects/Group13.cpp | 101 + .../cpp/libs/src/opendnp3/objects/Group13.h | 75 + .../cpp/libs/src/opendnp3/objects/Group2.cpp | 135 + .../cpp/libs/src/opendnp3/objects/Group2.h | 104 + .../cpp/libs/src/opendnp3/objects/Group20.cpp | 169 + .../cpp/libs/src/opendnp3/objects/Group20.h | 128 + .../cpp/libs/src/opendnp3/objects/Group21.cpp | 237 + .../cpp/libs/src/opendnp3/objects/Group21.h | 174 + .../cpp/libs/src/opendnp3/objects/Group22.cpp | 169 + .../cpp/libs/src/opendnp3/objects/Group22.h | 132 + .../cpp/libs/src/opendnp3/objects/Group23.cpp | 169 + .../cpp/libs/src/opendnp3/objects/Group23.h | 132 + .../cpp/libs/src/opendnp3/objects/Group3.cpp | 67 + .../cpp/libs/src/opendnp3/objects/Group3.h | 68 + .../cpp/libs/src/opendnp3/objects/Group30.cpp | 237 + .../cpp/libs/src/opendnp3/objects/Group30.h | 172 + .../cpp/libs/src/opendnp3/objects/Group32.cpp | 305 + .../cpp/libs/src/opendnp3/objects/Group32.h | 222 + .../cpp/libs/src/opendnp3/objects/Group4.cpp | 135 + .../cpp/libs/src/opendnp3/objects/Group4.h | 104 + .../cpp/libs/src/opendnp3/objects/Group40.cpp | 169 + .../cpp/libs/src/opendnp3/objects/Group40.h | 130 + .../cpp/libs/src/opendnp3/objects/Group41.cpp | 169 + .../cpp/libs/src/opendnp3/objects/Group41.h | 126 + .../cpp/libs/src/opendnp3/objects/Group42.cpp | 305 + .../cpp/libs/src/opendnp3/objects/Group42.h | 222 + .../cpp/libs/src/opendnp3/objects/Group43.cpp | 305 + .../cpp/libs/src/opendnp3/objects/Group43.h | 208 + .../cpp/libs/src/opendnp3/objects/Group50.cpp | 82 + .../cpp/libs/src/opendnp3/objects/Group50.h | 72 + .../cpp/libs/src/opendnp3/objects/Group51.cpp | 61 + .../cpp/libs/src/opendnp3/objects/Group51.h | 62 + .../cpp/libs/src/opendnp3/objects/Group52.cpp | 61 + .../cpp/libs/src/opendnp3/objects/Group52.h | 62 + .../cpp/libs/src/opendnp3/objects/Group60.h | 55 + .../cpp/libs/src/opendnp3/objects/Group70.h | 79 + .../cpp/libs/src/opendnp3/objects/Group80.h | 37 + .../opendnp3/outstation/ApplicationIIN.cpp | 39 + .../outstation/AssignClassHandler.cpp | 177 + .../opendnp3/outstation/AssignClassHandler.h | 75 + .../outstation/ClassBasedRequestHandler.cpp | 45 + .../outstation/ClassBasedRequestHandler.h | 62 + .../outstation/CommandActionAdapter.cpp | 77 + .../outstation/CommandActionAdapter.h | 74 + .../outstation/CommandResponseHandler.cpp | 136 + .../outstation/CommandResponseHandler.h | 163 + .../outstation/ConstantCommandAction.h | 58 + .../src/opendnp3/outstation/ControlState.h | 100 + .../libs/src/opendnp3/outstation/Database.cpp | 221 + .../libs/src/opendnp3/outstation/Database.h | 106 + .../opendnp3/outstation/DatabaseBuffers.cpp | 326 + .../src/opendnp3/outstation/DatabaseBuffers.h | 280 + .../outstation/DatabaseConfigView.cpp | 48 + .../opendnp3/outstation/DatabaseConfigView.h | 74 + .../opendnp3/outstation/DeferredRequest.cpp | 54 + .../src/opendnp3/outstation/DeferredRequest.h | 81 + .../cpp/libs/src/opendnp3/outstation/Event.h | 67 + .../src/opendnp3/outstation/EventBuffer.cpp | 318 + .../src/opendnp3/outstation/EventBuffer.h | 223 + .../opendnp3/outstation/EventBufferConfig.cpp | 92 + .../src/opendnp3/outstation/EventCount.cpp | 133 + .../libs/src/opendnp3/outstation/EventCount.h | 76 + .../src/opendnp3/outstation/EventWriter.cpp | 239 + .../src/opendnp3/outstation/EventWriter.h | 182 + .../src/opendnp3/outstation/IClassAssigner.h | 54 + .../src/opendnp3/outstation/ICommandAction.h | 53 + .../libs/src/opendnp3/outstation/IDatabase.h | 52 + .../src/opendnp3/outstation/IEventReceiver.h | 60 + .../src/opendnp3/outstation/IEventRecorder.h | 40 + .../src/opendnp3/outstation/IEventSelector.h | 42 + .../src/opendnp3/outstation/IINHelpers.cpp | 39 + .../libs/src/opendnp3/outstation/IINHelpers.h | 34 + .../outstation/IOutstationApplication.cpp | 26 + .../src/opendnp3/outstation/IResponseLoader.h | 52 + .../src/opendnp3/outstation/IStaticSelector.h | 47 + .../src/opendnp3/outstation/IndexSearch.h | 172 + .../outstation/OutstationChannelStates.h | 66 + .../opendnp3/outstation/OutstationContext.cpp | 736 + .../opendnp3/outstation/OutstationContext.h | 194 + .../opendnp3/outstation/OutstationSeqNum.h | 48 + .../opendnp3/outstation/OutstationStates.cpp | 217 + .../opendnp3/outstation/OutstationStates.h | 184 + .../src/opendnp3/outstation/ReadHandler.cpp | 58 + .../src/opendnp3/outstation/ReadHandler.h | 65 + .../opendnp3/outstation/RequestHistory.cpp | 69 + .../src/opendnp3/outstation/RequestHistory.h | 67 + .../opendnp3/outstation/ResponseContext.cpp | 65 + .../src/opendnp3/outstation/ResponseContext.h | 65 + .../src/opendnp3/outstation/SOERecord.cpp | 220 + .../libs/src/opendnp3/outstation/SOERecord.h | 130 + .../opendnp3/outstation/SelectedRanges.cpp | 99 + .../src/opendnp3/outstation/SelectedRanges.h | 85 + .../outstation/SimpleCommandHandler.cpp | 108 + .../src/opendnp3/outstation/StaticBuffers.cpp | 110 + .../src/opendnp3/outstation/StaticBuffers.h | 76 + .../outstation/StaticLoadFunctions.cpp | 133 + .../opendnp3/outstation/StaticLoadFunctions.h | 170 + .../src/opendnp3/outstation/WriteHandler.cpp | 106 + .../src/opendnp3/outstation/WriteHandler.h | 65 + .../opendnp3/transport/TransportConstants.h | 45 + .../src/opendnp3/transport/TransportLayer.cpp | 187 + .../src/opendnp3/transport/TransportLayer.h | 83 + .../src/opendnp3/transport/TransportRx.cpp | 146 + .../libs/src/opendnp3/transport/TransportRx.h | 73 + .../src/opendnp3/transport/TransportSeqNum.h | 34 + .../src/opendnp3/transport/TransportStack.cpp | 35 + .../src/opendnp3/transport/TransportStack.h | 44 + .../src/opendnp3/transport/TransportTx.cpp | 111 + .../libs/src/opendnp3/transport/TransportTx.h | 82 + .../cpp/libs/src/openpal/container/Buffer.cpp | 59 + .../cpp/libs/src/openpal/container/RSlice.cpp | 96 + .../cpp/libs/src/openpal/container/WSlice.cpp | 78 + .../openpal/executor/MonotonicTimestamp.cpp | 78 + .../src/openpal/executor/TimeDuration.cpp | 78 + .../libs/src/openpal/executor/TimerRef.cpp | 107 + .../cpp/libs/src/openpal/logging/Logger.cpp | 53 + .../src/openpal/logging/StringFormatting.cpp | 87 + .../serialization/ByteSerialization.cpp | 33 + .../src/openpal/serialization/DoubleFloat.cpp | 80 + .../openpal/serialization/FloatByteOrder.cpp | 68 + .../libs/src/openpal/serialization/Format.cpp | 82 + .../libs/src/openpal/serialization/Parse.cpp | 82 + .../src/openpal/serialization/SingleFloat.cpp | 81 + .../src/openpal/serialization/UInt48LE.cpp | 53 + .../cpp/libs/src/openpal/util/Limits.cpp | 127 + .../cpp/libs/src/openpal/util/ToHex.cpp | 32 + utils/dnp3_src/cpp/tests/afl-fuzzer/main.cpp | 129 + .../cpp/tests/asiodnp3/src/CatchTestStart.cpp | 22 + .../tests/asiodnp3/src/TestDNP3Manager.cpp | 138 + .../asiodnp3/src/TestEventIntegration.cpp | 94 + .../asiodnp3/src/TestMasterServerSmoke.cpp | 98 + .../cpp/tests/asiodnp3/src/TestPerfomance.cpp | 98 + .../asiodnp3/src/mocks/CountingSOEHandler.h | 127 + .../tests/asiodnp3/src/mocks/ExpectedValue.h | 101 + .../src/mocks/PerformanceStackPair.cpp | 180 + .../asiodnp3/src/mocks/PerformanceStackPair.h | 80 + .../src/mocks/QueuedChannelListener.h | 62 + .../asiodnp3/src/mocks/QueuingSOEHandler.h | 116 + .../tests/asiodnp3/src/mocks/StackPair.cpp | 241 + .../cpp/tests/asiodnp3/src/mocks/StackPair.h | 87 + .../asiodnp3/src/mocks/SynchronizedQueue.h | 89 + .../tests/asiodnp3/src/mocks/TestTypedefs.h | 39 + .../cpp/tests/asiopal/src/CatchTestStart.cpp | 22 + .../cpp/tests/asiopal/src/TestASIO.cpp | 65 + .../tests/asiopal/src/TestStrandExecutor.cpp | 165 + .../tests/asiopal/src/TestTCPClientServer.cpp | 68 + .../cpp/tests/asiopal/src/mocks/MockIO.cpp | 142 + .../cpp/tests/asiopal/src/mocks/MockIO.h | 77 + .../src/mocks/MockTCPClientHandler.cpp | 60 + .../asiopal/src/mocks/MockTCPClientHandler.h | 57 + .../tests/asiopal/src/mocks/MockTCPPair.cpp | 80 + .../cpp/tests/asiopal/src/mocks/MockTCPPair.h | 67 + .../tests/asiopal/src/mocks/MockTCPServer.h | 94 + .../asiopal/src/tls/TestTLSClientServer.cpp | 99 + .../src/tls/mocks/MockTLSClientHandler.h | 77 + .../asiopal/src/tls/mocks/MockTLSPair.cpp | 84 + .../tests/asiopal/src/tls/mocks/MockTLSPair.h | 68 + .../asiopal/src/tls/mocks/MockTLSServer.h | 107 + .../tests/asiopal/tls-certs/entity1_cert.pem | 20 + .../tests/asiopal/tls-certs/entity1_key.pem | 28 + .../tests/asiopal/tls-certs/entity2_cert.pem | 20 + .../tests/asiopal/tls-certs/entity2_key.pem | 28 + utils/dnp3_src/cpp/tests/libs/src/catch.hpp | 9416 ++ .../libs/src/dnp3mocks/APDUHexBuilders.cpp | 452 + .../libs/src/dnp3mocks/APDUHexBuilders.h | 182 + .../tests/libs/src/dnp3mocks/CallbackQueue.h | 50 + .../libs/src/dnp3mocks/CommandCallbackQueue.h | 111 + .../libs/src/dnp3mocks/MockCommandHandler.h | 114 + .../libs/src/dnp3mocks/MockFrameSink.cpp | 99 + .../tests/libs/src/dnp3mocks/MockFrameSink.h | 81 + .../libs/src/dnp3mocks/MockLinkListener.h | 70 + .../libs/src/dnp3mocks/MockLowerLayer.cpp | 116 + .../tests/libs/src/dnp3mocks/MockLowerLayer.h | 61 + .../src/dnp3mocks/MockMasterApplication.h | 107 + .../src/dnp3mocks/MockOutstationApplication.h | 141 + .../tests/libs/src/dnp3mocks/MockSOEHandler.h | 197 + .../libs/src/dnp3mocks/MockTaskCallback.h | 60 + .../libs/src/dnp3mocks/MockUpperLayer.cpp | 92 + .../tests/libs/src/dnp3mocks/MockUpperLayer.h | 116 + .../libs/src/dnp3mocks/NullSOEHandler.cpp | 29 + .../tests/libs/src/dnp3mocks/NullSOEHandler.h | 70 + .../tests/libs/src/dnp3mocks/ProtocolUtil.cpp | 36 + .../tests/libs/src/dnp3mocks/ProtocolUtil.h | 36 + .../tests/libs/src/testlib/BufferHelpers.cpp | 124 + .../tests/libs/src/testlib/BufferHelpers.h | 63 + .../libs/src/testlib/BufferTestObject.cpp | 125 + .../tests/libs/src/testlib/BufferTestObject.h | 78 + .../tests/libs/src/testlib/CopyableBuffer.cpp | 118 + .../tests/libs/src/testlib/CopyableBuffer.h | 92 + .../tests/libs/src/testlib/HexConversions.cpp | 99 + .../tests/libs/src/testlib/HexConversions.h | 48 + .../tests/libs/src/testlib/MockExecutor.cpp | 208 + .../cpp/tests/libs/src/testlib/MockExecutor.h | 126 + .../tests/libs/src/testlib/MockLogHandler.cpp | 83 + .../tests/libs/src/testlib/MockLogHandler.h | 91 + .../libs/src/testlib/MockUTCTimeSource.h | 49 + .../cpp/tests/libs/src/testlib/Random.h | 67 + .../cpp/tests/libs/src/testlib/RandomDouble.h | 51 + .../libs/src/testlib/RandomizedBuffer.cpp | 39 + .../tests/libs/src/testlib/RandomizedBuffer.h | 47 + .../cpp/tests/libs/src/testlib/StopWatch.cpp | 43 + .../cpp/tests/libs/src/testlib/StopWatch.h | 52 + .../cpp/tests/libs/src/testlib/Timeout.cpp | 44 + .../cpp/tests/libs/src/testlib/Timeout.h | 69 + .../cpp/tests/opendnp3/src/CatchTestStart.cpp | 22 + .../tests/opendnp3/src/TestAPDUParsing.cpp | 463 + .../tests/opendnp3/src/TestAPDUWriting.cpp | 297 + .../opendnp3/src/TestAuthRequestParser.cpp | 106 + .../cpp/tests/opendnp3/src/TestCRC.cpp | 46 + .../opendnp3/src/TestCastLongLongDouble.cpp | 81 + .../opendnp3/src/TestCollectionTransform.cpp | 51 + .../cpp/tests/opendnp3/src/TestDatabase.cpp | 182 + .../tests/opendnp3/src/TestGroup120Var1.cpp | 104 + .../tests/opendnp3/src/TestGroup120Var2.cpp | 72 + .../tests/opendnp3/src/TestGroup120Var5.cpp | 125 + .../tests/opendnp3/src/TestIndexSearch.cpp | 156 + .../cpp/tests/opendnp3/src/TestLinkFrame.cpp | 179 + .../cpp/tests/opendnp3/src/TestLinkLayer.cpp | 502 + .../opendnp3/src/TestLinkLayerKeepAlive.cpp | 167 + .../tests/opendnp3/src/TestLinkReceiver.cpp | 310 + .../cpp/tests/opendnp3/src/TestLinkRoute.cpp | 40 + .../cpp/tests/opendnp3/src/TestLog.cpp | 51 + .../cpp/tests/opendnp3/src/TestMaster.cpp | 639 + .../opendnp3/src/TestMasterAssignClass.cpp | 77 + .../src/TestMasterCommandRequests.cpp | 440 + .../src/TestMasterMultiCommandRequests.cpp | 136 + .../opendnp3/src/TestMasterMultidrop.cpp | 104 + .../opendnp3/src/TestMasterUnsolBehaviors.cpp | 59 + .../opendnp3/src/TestMeasurementHandler.cpp | 144 + .../cpp/tests/opendnp3/src/TestOutstation.cpp | 743 + .../src/TestOutstationAssignClass.cpp | 155 + .../src/TestOutstationCommandResponses.cpp | 408 + .../src/TestOutstationEventResponses.cpp | 388 + .../src/TestOutstationStateMachine.cpp | 73 + .../TestOutstationUnsolicitedResponses.cpp | 379 + .../opendnp3/src/TestShiftableBuffer.cpp | 161 + .../tests/opendnp3/src/TestTransportLayer.cpp | 273 + .../opendnp3/src/TestTypedCommandHeader.cpp | 101 + .../cpp/tests/opendnp3/src/TestTypes.cpp | 86 + .../cpp/tests/opendnp3/src/TestUtil.cpp | 67 + .../opendnp3/src/TestWriteConversions.cpp | 58 + .../tests/opendnp3/src/mocks/APDUHelpers.cpp | 45 + .../tests/opendnp3/src/mocks/APDUHelpers.h | 43 + .../opendnp3/src/mocks/BufferSegment.cpp | 74 + .../tests/opendnp3/src/mocks/BufferSegment.h | 55 + .../tests/opendnp3/src/mocks/DNPHelpers.cpp | 75 + .../cpp/tests/opendnp3/src/mocks/DNPHelpers.h | 39 + .../opendnp3/src/mocks/DatabaseTestObject.h | 100 + .../opendnp3/src/mocks/FanoutDataObserver.h | 91 + .../cpp/tests/opendnp3/src/mocks/LinkHex.cpp | 106 + .../cpp/tests/opendnp3/src/mocks/LinkHex.h | 63 + .../opendnp3/src/mocks/LinkLayerTest.cpp | 83 + .../tests/opendnp3/src/mocks/LinkLayerTest.h | 73 + .../opendnp3/src/mocks/LinkReceiverTest.h | 72 + .../opendnp3/src/mocks/MasterTestObject.cpp | 57 + .../opendnp3/src/mocks/MasterTestObject.h | 59 + .../src/mocks/MeasurementComparisons.h | 64 + .../src/mocks/MockAPDUHeaderHandler.h | 245 + .../tests/opendnp3/src/mocks/MockLinkLayer.h | 75 + .../opendnp3/src/mocks/MockTransportLayer.cpp | 84 + .../opendnp3/src/mocks/MockTransportLayer.h | 109 + .../src/mocks/OutstationTestObject.cpp | 93 + .../opendnp3/src/mocks/OutstationTestObject.h | 88 + .../tests/opendnp3/src/mocks/TestHelpers.h | 32 + .../src/mocks/TransportTestObject.cpp | 90 + .../opendnp3/src/mocks/TransportTestObject.h | 62 + .../cpp/tests/openpal/src/CatchTestStart.cpp | 22 + .../tests/openpal/src/LinkedListTestSuite.cpp | 241 + .../cpp/tests/openpal/src/QueueTestSuite.cpp | 45 + .../openpal/src/TestFloatSerialization.cpp | 135 + .../openpal/src/TestIntegerSerialization.cpp | 196 + .../tests/openpal/src/TestStaticBuffer.cpp | 64 + .../cpp/tests/openpal/src/TestTime.cpp | 54 + utils/dnp3_src/deps/asio/asio/COPYING | 4 + utils/dnp3_src/deps/asio/asio/INSTALL | 5 + utils/dnp3_src/deps/asio/asio/LICENSE_1_0.txt | 23 + utils/dnp3_src/deps/asio/asio/Makefile.am | 19 + utils/dnp3_src/deps/asio/asio/README | 4 + utils/dnp3_src/deps/asio/asio/asio.manifest | 4358 + utils/dnp3_src/deps/asio/asio/autogen.sh | 55 + .../deps/asio/asio/boost_asio.manifest | 4661 + utils/dnp3_src/deps/asio/asio/boostify.pl | 580 + utils/dnp3_src/deps/asio/asio/configure.ac | 265 + .../deps/asio/asio/include/Makefile.am | 411 + .../dnp3_src/deps/asio/asio/include/asio.hpp | 122 + .../asio/asio/include/asio/async_result.hpp | 94 + .../include/asio/basic_datagram_socket.hpp | 949 + .../include/asio/basic_deadline_timer.hpp | 518 + .../asio/include/asio/basic_io_object.hpp | 241 + .../asio/include/asio/basic_raw_socket.hpp | 940 + .../include/asio/basic_seq_packet_socket.hpp | 565 + .../asio/include/asio/basic_serial_port.hpp | 695 + .../asio/include/asio/basic_signal_set.hpp | 384 + .../asio/asio/include/asio/basic_socket.hpp | 1518 + .../include/asio/basic_socket_acceptor.hpp | 1136 + .../include/asio/basic_socket_iostream.hpp | 286 + .../include/asio/basic_socket_streambuf.hpp | 567 + .../asio/include/asio/basic_stream_socket.hpp | 852 + .../asio/include/asio/basic_streambuf.hpp | 369 + .../asio/include/asio/basic_streambuf_fwd.hpp | 33 + .../include/asio/basic_waitable_timer.hpp | 519 + .../deps/asio/asio/include/asio/buffer.hpp | 2239 + .../include/asio/buffered_read_stream.hpp | 244 + .../include/asio/buffered_read_stream_fwd.hpp | 25 + .../asio/include/asio/buffered_stream.hpp | 258 + .../asio/include/asio/buffered_stream_fwd.hpp | 25 + .../include/asio/buffered_write_stream.hpp | 236 + .../asio/buffered_write_stream_fwd.hpp | 25 + .../asio/include/asio/buffers_iterator.hpp | 481 + .../include/asio/completion_condition.hpp | 218 + .../deps/asio/asio/include/asio/connect.hpp | 823 + .../deps/asio/asio/include/asio/coroutine.hpp | 328 + .../include/asio/datagram_socket_service.hpp | 432 + .../asio/asio/include/asio/deadline_timer.hpp | 38 + .../include/asio/deadline_timer_service.hpp | 171 + .../asio/include/asio/detail/addressof.hpp | 38 + .../asio/asio/include/asio/detail/array.hpp | 38 + .../asio/include/asio/detail/array_fwd.hpp | 34 + .../asio/asio/include/asio/detail/assert.hpp | 32 + .../asio/include/asio/detail/atomic_count.hpp | 45 + .../asio/detail/base_from_completion_cond.hpp | 68 + .../asio/include/asio/detail/bind_handler.hpp | 489 + .../asio/detail/buffer_resize_guard.hpp | 66 + .../asio/detail/buffer_sequence_adapter.hpp | 383 + .../asio/detail/buffered_stream_storage.hpp | 126 + .../asio/include/asio/detail/call_stack.hpp | 125 + .../asio/detail/chrono_time_traits.hpp | 190 + .../asio/detail/completion_handler.hpp | 81 + .../asio/asio/include/asio/detail/config.hpp | 998 + .../include/asio/detail/consuming_buffers.hpp | 292 + .../asio/asio/include/asio/detail/cstdint.hpp | 46 + .../include/asio/detail/date_time_fwd.hpp | 34 + .../asio/detail/deadline_timer_service.hpp | 227 + .../include/asio/detail/dependent_type.hpp | 36 + .../include/asio/detail/descriptor_ops.hpp | 117 + .../asio/detail/descriptor_read_op.hpp | 119 + .../asio/detail/descriptor_write_op.hpp | 119 + .../include/asio/detail/dev_poll_reactor.hpp | 206 + .../include/asio/detail/epoll_reactor.hpp | 242 + .../asio/asio/include/asio/detail/event.hpp | 48 + .../detail/eventfd_select_interrupter.hpp | 83 + .../include/asio/detail/fd_set_adapter.hpp | 39 + .../asio/include/asio/detail/fenced_block.hpp | 76 + .../asio/include/asio/detail/function.hpp | 38 + .../asio/detail/gcc_arm_fenced_block.hpp | 89 + .../asio/detail/gcc_hppa_fenced_block.hpp | 66 + .../asio/detail/gcc_sync_fenced_block.hpp | 63 + .../asio/detail/gcc_x86_fenced_block.hpp | 97 + .../asio/detail/handler_alloc_helpers.hpp | 82 + .../asio/detail/handler_cont_helpers.hpp | 45 + .../asio/detail/handler_invoke_helpers.hpp | 57 + .../include/asio/detail/handler_tracking.hpp | 159 + .../asio/detail/handler_type_requirements.hpp | 498 + .../asio/include/asio/detail/hash_map.hpp | 331 + .../detail/impl/buffer_sequence_adapter.ipp | 118 + .../asio/detail/impl/descriptor_ops.ipp | 451 + .../asio/detail/impl/dev_poll_reactor.hpp | 78 + .../asio/detail/impl/dev_poll_reactor.ipp | 430 + .../asio/detail/impl/epoll_reactor.hpp | 76 + .../asio/detail/impl/epoll_reactor.ipp | 662 + .../impl/eventfd_select_interrupter.ipp | 165 + .../asio/detail/impl/handler_tracking.ipp | 305 + .../asio/detail/impl/kqueue_reactor.hpp | 80 + .../asio/detail/impl/kqueue_reactor.ipp | 496 + .../detail/impl/pipe_select_interrupter.ipp | 124 + .../include/asio/detail/impl/posix_event.ipp | 47 + .../include/asio/detail/impl/posix_mutex.ipp | 46 + .../include/asio/detail/impl/posix_thread.ipp | 74 + .../asio/detail/impl/posix_tss_ptr.ipp | 46 + .../impl/reactive_descriptor_service.ipp | 208 + .../impl/reactive_serial_port_service.ipp | 151 + .../impl/reactive_socket_service_base.ipp | 267 + .../detail/impl/resolver_service_base.ipp | 130 + .../asio/detail/impl/select_reactor.hpp | 87 + .../asio/detail/impl/select_reactor.ipp | 313 + .../asio/detail/impl/service_registry.hpp | 88 + .../asio/detail/impl/service_registry.ipp | 188 + .../asio/detail/impl/signal_set_service.ipp | 647 + .../include/asio/detail/impl/socket_ops.ipp | 3437 + .../detail/impl/socket_select_interrupter.ipp | 176 + .../asio/detail/impl/strand_service.hpp | 118 + .../asio/detail/impl/strand_service.ipp | 176 + .../asio/detail/impl/task_io_service.hpp | 78 + .../asio/detail/impl/task_io_service.ipp | 474 + .../include/asio/detail/impl/throw_error.ipp | 60 + .../asio/detail/impl/timer_queue_ptime.ipp | 84 + .../asio/detail/impl/timer_queue_set.ipp | 101 + .../include/asio/detail/impl/win_event.ipp | 75 + .../detail/impl/win_iocp_handle_service.ipp | 525 + .../asio/detail/impl/win_iocp_io_service.hpp | 130 + .../asio/detail/impl/win_iocp_io_service.ipp | 538 + .../impl/win_iocp_serial_port_service.ipp | 180 + .../impl/win_iocp_socket_service_base.ipp | 734 + .../include/asio/detail/impl/win_mutex.ipp | 83 + .../detail/impl/win_object_handle_service.ipp | 445 + .../asio/detail/impl/win_static_mutex.ipp | 136 + .../include/asio/detail/impl/win_thread.ipp | 143 + .../include/asio/detail/impl/win_tss_ptr.ipp | 57 + .../impl/winrt_ssocket_service_base.ipp | 612 + .../detail/impl/winrt_timer_scheduler.hpp | 79 + .../detail/impl/winrt_timer_scheduler.ipp | 122 + .../include/asio/detail/impl/winsock_init.ipp | 82 + .../asio/include/asio/detail/io_control.hpp | 134 + .../include/asio/detail/keyword_tss_ptr.hpp | 70 + .../include/asio/detail/kqueue_reactor.hpp | 220 + .../asio/asio/include/asio/detail/limits.hpp | 26 + .../asio/detail/local_free_on_block_exit.hpp | 59 + .../asio/detail/macos_fenced_block.hpp | 61 + .../asio/asio/include/asio/detail/mutex.hpp | 48 + .../asio/include/asio/detail/noncopyable.hpp | 43 + .../asio/include/asio/detail/null_event.hpp | 88 + .../include/asio/detail/null_fenced_block.hpp | 45 + .../asio/include/asio/detail/null_mutex.hpp | 64 + .../asio/include/asio/detail/null_reactor.hpp | 67 + .../asio/detail/null_signal_blocker.hpp | 69 + .../asio/detail/null_socket_service.hpp | 497 + .../include/asio/detail/null_static_mutex.hpp | 60 + .../asio/include/asio/detail/null_thread.hpp | 61 + .../asio/include/asio/detail/null_tss_ptr.hpp | 68 + .../asio/include/asio/detail/object_pool.hpp | 146 + .../asio/detail/old_win_sdk_compat.hpp | 214 + .../asio/include/asio/detail/op_queue.hpp | 156 + .../asio/include/asio/detail/operation.hpp | 38 + .../asio/detail/pipe_select_interrupter.hpp | 89 + .../asio/include/asio/detail/pop_options.hpp | 131 + .../asio/include/asio/detail/posix_event.hpp | 126 + .../asio/detail/posix_fd_set_adapter.hpp | 118 + .../asio/include/asio/detail/posix_mutex.hpp | 76 + .../asio/detail/posix_signal_blocker.hpp | 85 + .../asio/detail/posix_static_mutex.hpp | 64 + .../asio/include/asio/detail/posix_thread.hpp | 105 + .../include/asio/detail/posix_tss_ptr.hpp | 79 + .../asio/include/asio/detail/push_options.hpp | 166 + .../detail/reactive_descriptor_service.hpp | 322 + .../asio/detail/reactive_null_buffers_op.hpp | 88 + .../detail/reactive_serial_port_service.hpp | 234 + .../asio/detail/reactive_socket_accept_op.hpp | 136 + .../detail/reactive_socket_connect_op.hpp | 106 + .../asio/detail/reactive_socket_recv_op.hpp | 123 + .../detail/reactive_socket_recvfrom_op.hpp | 133 + .../detail/reactive_socket_recvmsg_op.hpp | 125 + .../asio/detail/reactive_socket_send_op.hpp | 120 + .../asio/detail/reactive_socket_sendto_op.hpp | 123 + .../asio/detail/reactive_socket_service.hpp | 457 + .../detail/reactive_socket_service_base.hpp | 450 + .../asio/asio/include/asio/detail/reactor.hpp | 32 + .../asio/include/asio/detail/reactor_fwd.hpp | 40 + .../asio/include/asio/detail/reactor_op.hpp | 61 + .../include/asio/detail/reactor_op_queue.hpp | 168 + .../asio/include/asio/detail/regex_fwd.hpp | 35 + .../asio/detail/resolve_endpoint_op.hpp | 121 + .../asio/include/asio/detail/resolve_op.hpp | 131 + .../include/asio/detail/resolver_service.hpp | 129 + .../asio/detail/resolver_service_base.hpp | 129 + .../asio/include/asio/detail/scoped_lock.hpp | 101 + .../asio/include/asio/detail/scoped_ptr.hpp | 79 + .../asio/detail/select_interrupter.hpp | 46 + .../include/asio/detail/select_reactor.hpp | 219 + .../include/asio/detail/service_registry.hpp | 144 + .../asio/include/asio/detail/shared_ptr.hpp | 38 + .../include/asio/detail/signal_blocker.hpp | 44 + .../include/asio/detail/signal_handler.hpp | 82 + .../asio/include/asio/detail/signal_init.hpp | 47 + .../asio/include/asio/detail/signal_op.hpp | 49 + .../asio/detail/signal_set_service.hpp | 216 + .../include/asio/detail/socket_holder.hpp | 98 + .../asio/include/asio/detail/socket_ops.hpp | 334 + .../include/asio/detail/socket_option.hpp | 316 + .../asio/detail/socket_select_interrupter.hpp | 91 + .../asio/include/asio/detail/socket_types.hpp | 408 + .../asio/detail/solaris_fenced_block.hpp | 61 + .../asio/include/asio/detail/static_mutex.hpp | 52 + .../asio/include/asio/detail/std_event.hpp | 176 + .../asio/include/asio/detail/std_mutex.hpp | 73 + .../include/asio/detail/std_static_mutex.hpp | 81 + .../asio/include/asio/detail/std_thread.hpp | 65 + .../include/asio/detail/strand_service.hpp | 142 + .../include/asio/detail/task_io_service.hpp | 201 + .../asio/detail/task_io_service_operation.hpp | 76 + .../detail/task_io_service_thread_info.hpp | 40 + .../asio/asio/include/asio/detail/thread.hpp | 56 + .../include/asio/detail/thread_info_base.hpp | 91 + .../asio/include/asio/detail/throw_error.hpp | 53 + .../include/asio/detail/throw_exception.hpp | 51 + .../asio/include/asio/detail/timer_queue.hpp | 331 + .../include/asio/detail/timer_queue_base.hpp | 68 + .../include/asio/detail/timer_queue_ptime.hpp | 93 + .../include/asio/detail/timer_queue_set.hpp | 66 + .../include/asio/detail/timer_scheduler.hpp | 35 + .../asio/detail/timer_scheduler_fwd.hpp | 40 + .../asio/asio/include/asio/detail/tss_ptr.hpp | 69 + .../asio/include/asio/detail/type_traits.hpp | 58 + .../asio/detail/variadic_templates.hpp | 63 + .../asio/include/asio/detail/wait_handler.hpp | 83 + .../asio/asio/include/asio/detail/wait_op.hpp | 45 + .../asio/include/asio/detail/weak_ptr.hpp | 38 + .../asio/include/asio/detail/win_event.hpp | 130 + .../asio/detail/win_fd_set_adapter.hpp | 149 + .../include/asio/detail/win_fenced_block.hpp | 89 + .../asio/detail/win_iocp_handle_read_op.hpp | 109 + .../asio/detail/win_iocp_handle_service.hpp | 322 + .../asio/detail/win_iocp_handle_write_op.hpp | 101 + .../asio/detail/win_iocp_io_service.hpp | 315 + .../asio/detail/win_iocp_null_buffers_op.hpp | 119 + .../asio/detail/win_iocp_operation.hpp | 95 + .../asio/detail/win_iocp_overlapped_op.hpp | 88 + .../asio/detail/win_iocp_overlapped_ptr.hpp | 144 + .../detail/win_iocp_serial_port_service.hpp | 228 + .../asio/detail/win_iocp_socket_accept_op.hpp | 165 + .../detail/win_iocp_socket_connect_op.hpp | 124 + .../asio/detail/win_iocp_socket_recv_op.hpp | 115 + .../detail/win_iocp_socket_recvfrom_op.hpp | 123 + .../detail/win_iocp_socket_recvmsg_op.hpp | 116 + .../asio/detail/win_iocp_socket_send_op.hpp | 109 + .../asio/detail/win_iocp_socket_service.hpp | 525 + .../detail/win_iocp_socket_service_base.hpp | 524 + .../asio/detail/win_iocp_thread_info.hpp | 34 + .../asio/include/asio/detail/win_mutex.hpp | 78 + .../asio/detail/win_object_handle_service.hpp | 183 + .../include/asio/detail/win_static_mutex.hpp | 74 + .../asio/include/asio/detail/win_thread.hpp | 143 + .../asio/include/asio/detail/win_tss_ptr.hpp | 79 + .../include/asio/detail/winapi_thread.hpp | 122 + .../asio/detail/winrt_async_manager.hpp | 294 + .../include/asio/detail/winrt_async_op.hpp | 65 + .../include/asio/detail/winrt_resolve_op.hpp | 117 + .../asio/detail/winrt_resolver_service.hpp | 183 + .../asio/detail/winrt_socket_connect_op.hpp | 90 + .../asio/detail/winrt_socket_recv_op.hpp | 110 + .../asio/detail/winrt_socket_send_op.hpp | 101 + .../asio/detail/winrt_ssocket_service.hpp | 232 + .../detail/winrt_ssocket_service_base.hpp | 355 + .../asio/detail/winrt_timer_scheduler.hpp | 131 + .../asio/include/asio/detail/winrt_utils.hpp | 106 + .../asio/include/asio/detail/winsock_init.hpp | 128 + .../include/asio/detail/wrapped_handler.hpp | 291 + .../deps/asio/asio/include/asio/error.hpp | 336 + .../asio/asio/include/asio/error_code.hpp | 188 + .../include/asio/generic/basic_endpoint.hpp | 193 + .../asio/generic/datagram_protocol.hpp | 123 + .../include/asio/generic/detail/endpoint.hpp | 133 + .../asio/generic/detail/impl/endpoint.ipp | 109 + .../include/asio/generic/raw_protocol.hpp | 121 + .../asio/generic/seq_packet_protocol.hpp | 122 + .../include/asio/generic/stream_protocol.hpp | 127 + .../asio/include/asio/handler_alloc_hook.hpp | 81 + .../asio/handler_continuation_hook.hpp | 54 + .../asio/include/asio/handler_invoke_hook.hpp | 85 + .../asio/asio/include/asio/handler_type.hpp | 112 + .../include/asio/high_resolution_timer.hpp | 63 + .../asio/impl/buffered_read_stream.hpp | 358 + .../asio/impl/buffered_write_stream.hpp | 338 + .../asio/asio/include/asio/impl/connect.hpp | 430 + .../asio/asio/include/asio/impl/error.ipp | 128 + .../asio/include/asio/impl/error_code.ipp | 126 + .../include/asio/impl/handler_alloc_hook.ipp | 77 + .../asio/include/asio/impl/io_service.hpp | 152 + .../asio/include/asio/impl/io_service.ipp | 155 + .../deps/asio/asio/include/asio/impl/read.hpp | 753 + .../asio/asio/include/asio/impl/read_at.hpp | 810 + .../asio/include/asio/impl/read_until.hpp | 1147 + .../include/asio/impl/serial_port_base.hpp | 59 + .../include/asio/impl/serial_port_base.ipp | 554 + .../asio/asio/include/asio/impl/spawn.hpp | 353 + .../deps/asio/asio/include/asio/impl/src.cpp | 25 + .../deps/asio/asio/include/asio/impl/src.hpp | 74 + .../asio/include/asio/impl/use_future.hpp | 176 + .../asio/asio/include/asio/impl/write.hpp | 765 + .../asio/asio/include/asio/impl/write_at.hpp | 825 + .../asio/asio/include/asio/io_service.hpp | 770 + .../asio/asio/include/asio/ip/address.hpp | 200 + .../asio/asio/include/asio/ip/address_v4.hpp | 241 + .../asio/asio/include/asio/ip/address_v6.hpp | 246 + .../asio/include/asio/ip/basic_endpoint.hpp | 263 + .../asio/include/asio/ip/basic_resolver.hpp | 268 + .../include/asio/ip/basic_resolver_entry.hpp | 94 + .../asio/ip/basic_resolver_iterator.hpp | 260 + .../include/asio/ip/basic_resolver_query.hpp | 244 + .../asio/include/asio/ip/detail/endpoint.hpp | 139 + .../include/asio/ip/detail/impl/endpoint.ipp | 204 + .../include/asio/ip/detail/socket_option.hpp | 569 + .../asio/asio/include/asio/ip/host_name.hpp | 42 + .../deps/asio/asio/include/asio/ip/icmp.hpp | 115 + .../asio/include/asio/ip/impl/address.hpp | 53 + .../asio/include/asio/ip/impl/address.ipp | 226 + .../asio/include/asio/ip/impl/address_v4.hpp | 53 + .../asio/include/asio/ip/impl/address_v4.ipp | 178 + .../asio/include/asio/ip/impl/address_v6.hpp | 53 + .../asio/include/asio/ip/impl/address_v6.ipp | 298 + .../include/asio/ip/impl/basic_endpoint.hpp | 55 + .../asio/include/asio/ip/impl/host_name.ipp | 54 + .../asio/asio/include/asio/ip/multicast.hpp | 191 + .../include/asio/ip/resolver_query_base.hpp | 130 + .../asio/include/asio/ip/resolver_service.hpp | 176 + .../deps/asio/asio/include/asio/ip/tcp.hpp | 155 + .../deps/asio/asio/include/asio/ip/udp.hpp | 111 + .../asio/asio/include/asio/ip/unicast.hpp | 70 + .../asio/asio/include/asio/ip/v6_only.hpp | 69 + .../asio/include/asio/is_read_buffered.hpp | 59 + .../asio/include/asio/is_write_buffered.hpp | 59 + .../include/asio/local/basic_endpoint.hpp | 239 + .../asio/include/asio/local/connect_pair.hpp | 104 + .../include/asio/local/datagram_protocol.hpp | 80 + .../include/asio/local/detail/endpoint.hpp | 133 + .../asio/local/detail/impl/endpoint.ipp | 128 + .../include/asio/local/stream_protocol.hpp | 90 + .../asio/asio/include/asio/placeholders.hpp | 123 + .../include/asio/posix/basic_descriptor.hpp | 490 + .../asio/posix/basic_stream_descriptor.hpp | 362 + .../include/asio/posix/descriptor_base.hpp | 97 + .../include/asio/posix/stream_descriptor.hpp | 37 + .../asio/posix/stream_descriptor_service.hpp | 260 + .../asio/include/asio/raw_socket_service.hpp | 432 + .../deps/asio/asio/include/asio/read.hpp | 631 + .../deps/asio/asio/include/asio/read_at.hpp | 664 + .../asio/asio/include/asio/read_until.hpp | 923 + .../asio/seq_packet_socket_service.hpp | 380 + .../asio/asio/include/asio/serial_port.hpp | 36 + .../asio/include/asio/serial_port_base.hpp | 167 + .../asio/include/asio/serial_port_service.hpp | 253 + .../asio/asio/include/asio/signal_set.hpp | 28 + .../asio/include/asio/signal_set_service.hpp | 134 + .../include/asio/socket_acceptor_service.hpp | 302 + .../asio/asio/include/asio/socket_base.hpp | 520 + .../deps/asio/asio/include/asio/spawn.hpp | 265 + .../deps/asio/asio/include/asio/ssl.hpp | 30 + .../asio/include/asio/ssl/basic_context.hpp | 40 + .../asio/asio/include/asio/ssl/context.hpp | 787 + .../asio/include/asio/ssl/context_base.hpp | 183 + .../asio/include/asio/ssl/context_service.hpp | 40 + .../asio/ssl/detail/buffered_handshake_op.hpp | 110 + .../asio/include/asio/ssl/detail/engine.hpp | 164 + .../include/asio/ssl/detail/handshake_op.hpp | 68 + .../include/asio/ssl/detail/impl/engine.ipp | 325 + .../asio/ssl/detail/impl/openssl_init.ipp | 163 + .../asio/asio/include/asio/ssl/detail/io.hpp | 349 + .../include/asio/ssl/detail/openssl_init.hpp | 101 + .../include/asio/ssl/detail/openssl_types.hpp | 30 + .../asio/ssl/detail/password_callback.hpp | 72 + .../asio/include/asio/ssl/detail/read_op.hpp | 73 + .../include/asio/ssl/detail/shutdown_op.hpp | 60 + .../include/asio/ssl/detail/stream_core.hpp | 126 + .../asio/ssl/detail/verify_callback.hpp | 68 + .../asio/include/asio/ssl/detail/write_op.hpp | 73 + .../deps/asio/asio/include/asio/ssl/error.hpp | 108 + .../asio/include/asio/ssl/impl/context.hpp | 71 + .../asio/include/asio/ssl/impl/context.ipp | 1049 + .../asio/asio/include/asio/ssl/impl/error.ipp | 100 + .../asio/ssl/impl/rfc2818_verification.ipp | 166 + .../asio/asio/include/asio/ssl/impl/src.hpp | 28 + .../include/asio/ssl/old/basic_context.hpp | 434 + .../include/asio/ssl/old/context_service.hpp | 174 + .../old/detail/openssl_context_service.hpp | 394 + .../asio/ssl/old/detail/openssl_operation.hpp | 524 + .../ssl/old/detail/openssl_stream_service.hpp | 571 + .../asio/asio/include/asio/ssl/old/stream.hpp | 501 + .../include/asio/ssl/old/stream_service.hpp | 184 + .../include/asio/ssl/rfc2818_verification.hpp | 100 + .../asio/asio/include/asio/ssl/stream.hpp | 756 + .../asio/include/asio/ssl/stream_base.hpp | 52 + .../asio/include/asio/ssl/stream_service.hpp | 40 + .../asio/include/asio/ssl/verify_context.hpp | 73 + .../asio/include/asio/ssl/verify_mode.hpp | 63 + .../asio/asio/include/asio/steady_timer.hpp | 61 + .../deps/asio/asio/include/asio/strand.hpp | 252 + .../include/asio/stream_socket_service.hpp | 376 + .../deps/asio/asio/include/asio/streambuf.hpp | 33 + .../asio/asio/include/asio/system_error.hpp | 131 + .../asio/asio/include/asio/system_timer.hpp | 57 + .../deps/asio/asio/include/asio/thread.hpp | 92 + .../asio/asio/include/asio/time_traits.hpp | 86 + .../deps/asio/asio/include/asio/unyield.hpp | 21 + .../asio/asio/include/asio/use_future.hpp | 92 + .../deps/asio/asio/include/asio/version.hpp | 23 + .../asio/asio/include/asio/wait_traits.hpp | 41 + .../include/asio/waitable_timer_service.hpp | 168 + .../include/asio/windows/basic_handle.hpp | 281 + .../asio/windows/basic_object_handle.hpp | 178 + .../windows/basic_random_access_handle.hpp | 376 + .../asio/windows/basic_stream_handle.hpp | 359 + .../include/asio/windows/object_handle.hpp | 38 + .../asio/windows/object_handle_service.hpp | 177 + .../include/asio/windows/overlapped_ptr.hpp | 116 + .../asio/windows/random_access_handle.hpp | 37 + .../windows/random_access_handle_service.hpp | 220 + .../include/asio/windows/stream_handle.hpp | 37 + .../asio/windows/stream_handle_service.hpp | 218 + .../deps/asio/asio/include/asio/write.hpp | 618 + .../deps/asio/asio/include/asio/write_at.hpp | 670 + .../deps/asio/asio/include/asio/yield.hpp | 23 + utils/dnp3_src/deps/asio/asio/release.pl | 439 + utils/dnp3_src/deps/asio/asio/src/Makefile.am | 15 + .../dnp3_src/deps/asio/asio/src/Makefile.mgw | 213 + .../dnp3_src/deps/asio/asio/src/Makefile.msc | 449 + utils/dnp3_src/deps/asio/asio/src/asio.cpp | 11 + .../dnp3_src/deps/asio/asio/src/asio_ssl.cpp | 11 + .../deps/asio/asio/src/doc/Jamfile.v2 | 62 + .../dnp3_src/deps/asio/asio/src/doc/asio.png | Bin 0 -> 3164 bytes .../dnp3_src/deps/asio/asio/src/doc/asio.qbk | 112 + .../deps/asio/asio/src/doc/asioref.sty | 90 + .../deps/asio/asio/src/doc/asioref.xsl | 94 + .../deps/asio/asio/src/doc/boost_bind_dox.txt | 5 + .../deps/asio/asio/src/doc/doxy2qbk.pl | 22 + .../deps/asio/asio/src/doc/examples.qbk | 419 + .../deps/asio/asio/src/doc/history.qbk | 1169 + .../dnp3_src/deps/asio/asio/src/doc/index.xml | 13 + .../deps/asio/asio/src/doc/makepdf.pl | 26 + .../asio/asio/src/doc/noncopyable_dox.txt | 3 + .../deps/asio/asio/src/doc/overview.qbk | 97 + .../asio/asio/src/doc/overview/allocation.qbk | 58 + .../deps/asio/asio/src/doc/overview/async.qbk | 185 + .../asio/asio/src/doc/overview/async_op1.dot | 78 + .../asio/asio/src/doc/overview/async_op1.png | Bin 0 -> 24084 bytes .../asio/asio/src/doc/overview/async_op2.dot | 78 + .../asio/asio/src/doc/overview/async_op2.png | Bin 0 -> 25260 bytes .../asio/asio/src/doc/overview/basics.qbk | 106 + .../asio/src/doc/overview/bsd_sockets.qbk | 270 + .../asio/asio/src/doc/overview/buffers.qbk | 163 + .../asio/asio/src/doc/overview/coroutine.qbk | 51 + .../asio/asio/src/doc/overview/cpp2011.qbk | 275 + .../src/doc/overview/handler_tracking.qbk | 102 + .../asio/src/doc/overview/implementation.qbk | 305 + .../asio/asio/src/doc/overview/iostreams.qbk | 72 + .../asio/asio/src/doc/overview/line_based.qbk | 118 + .../asio/src/doc/overview/other_protocols.qbk | 94 + .../deps/asio/asio/src/doc/overview/posix.qbk | 146 + .../asio/asio/src/doc/overview/proactor.dot | 100 + .../asio/asio/src/doc/overview/proactor.png | Bin 0 -> 30877 bytes .../asio/asio/src/doc/overview/protocols.qbk | 149 + .../asio/asio/src/doc/overview/rationale.qbk | 54 + .../asio/asio/src/doc/overview/reactor.qbk | 44 + .../asio/src/doc/overview/serial_ports.qbk | 47 + .../asio/asio/src/doc/overview/signals.qbk | 44 + .../deps/asio/asio/src/doc/overview/spawn.qbk | 102 + .../deps/asio/asio/src/doc/overview/ssl.qbk | 123 + .../asio/asio/src/doc/overview/strands.qbk | 62 + .../asio/asio/src/doc/overview/streams.qbk | 62 + .../asio/asio/src/doc/overview/sync_op.dot | 67 + .../asio/asio/src/doc/overview/sync_op.png | Bin 0 -> 22703 bytes .../asio/asio/src/doc/overview/threads.qbk | 66 + .../asio/asio/src/doc/overview/timers.qbk | 53 + .../asio/asio/src/doc/overview/windows.qbk | 132 + .../deps/asio/asio/src/doc/project-root.jam | 1 + .../deps/asio/asio/src/doc/quickref.xml | 483 + .../deps/asio/asio/src/doc/reference.dox | 241 + .../deps/asio/asio/src/doc/reference.qbk | 106372 +++++++++++++++ .../deps/asio/asio/src/doc/reference.xsl | 1701 + .../asio/asio/src/doc/release_checklist.htm | 68 + .../src/doc/requirements/AcceptHandler.qbk | 50 + .../AsyncRandomAccessReadDevice.qbk | 57 + .../AsyncRandomAccessWriteDevice.qbk | 58 + .../src/doc/requirements/AsyncReadStream.qbk | 56 + .../src/doc/requirements/AsyncWriteStream.qbk | 55 + .../requirements/BufferedHandshakeHandler.qbk | 54 + .../doc/requirements/CompletionHandler.qbk | 45 + .../requirements/ComposedConnectHandler.qbk | 56 + .../src/doc/requirements/ConnectHandler.qbk | 50 + .../doc/requirements/ConstBufferSequence.qbk | 102 + .../requirements/ConvertibleToConstBuffer.qbk | 96 + .../ConvertibleToMutableBuffer.qbk | 96 + .../requirements/DatagramSocketService.qbk | 227 + .../doc/requirements/DescriptorService.qbk | 142 + .../asio/src/doc/requirements/Endpoint.qbk | 93 + .../requirements/GettableSerialPortOption.qbk | 33 + .../doc/requirements/GettableSocketOption.qbk | 62 + .../src/doc/requirements/HandleService.qbk | 132 + .../asio/src/doc/requirements/Handler.qbk | 64 + .../src/doc/requirements/HandshakeHandler.qbk | 50 + .../src/doc/requirements/InternetProtocol.qbk | 46 + .../src/doc/requirements/IoControlCommand.qbk | 31 + .../src/doc/requirements/IoObjectService.qbk | 62 + .../requirements/MutableBufferSequence.qbk | 102 + .../doc/requirements/ObjectHandleService.qbk | 46 + .../asio/src/doc/requirements/Protocol.qbk | 49 + .../RandomAccessHandleService.qbk | 133 + .../src/doc/requirements/RawSocketService.qbk | 227 + .../asio/src/doc/requirements/ReadHandler.qbk | 54 + .../src/doc/requirements/ResolveHandler.qbk | 57 + .../src/doc/requirements/ResolverService.qbk | 108 + .../requirements/SeqPacketSocketService.qbk | 127 + .../doc/requirements/SerialPortService.qbk | 301 + .../asio/src/doc/requirements/Service.qbk | 33 + .../requirements/SettableSerialPortOption.qbk | 33 + .../doc/requirements/SettableSocketOption.qbk | 52 + .../src/doc/requirements/ShutdownHandler.qbk | 50 + .../src/doc/requirements/SignalHandler.qbk | 54 + .../src/doc/requirements/SignalSetService.qbk | 91 + .../requirements/SocketAcceptorService.qbk | 270 + .../src/doc/requirements/SocketService.qbk | 312 + .../requirements/StreamDescriptorService.qbk | 138 + .../doc/requirements/StreamHandleService.qbk | 138 + .../doc/requirements/StreamSocketService.qbk | 139 + .../SyncRandomAccessReadDevice.qbk | 49 + .../SyncRandomAccessWriteDevice.qbk | 49 + .../src/doc/requirements/SyncReadStream.qbk | 48 + .../src/doc/requirements/SyncWriteStream.qbk | 47 + .../asio/src/doc/requirements/TimeTraits.qbk | 72 + .../src/doc/requirements/TimerService.qbk | 105 + .../asio/src/doc/requirements/WaitHandler.qbk | 50 + .../asio/src/doc/requirements/WaitTraits.qbk | 26 + .../doc/requirements/WaitableTimerService.qbk | 104 + .../src/doc/requirements/WriteHandler.qbk | 54 + .../requirements/asynchronous_operations.qbk | 217 + .../asio/asio/src/doc/std_exception_dox.txt | 7 + .../deps/asio/asio/src/doc/tutorial.dox | 226 + .../deps/asio/asio/src/doc/tutorial.qbk | 2402 + .../deps/asio/asio/src/doc/tutorial.xsl | 437 + .../dnp3_src/deps/asio/asio/src/doc/using.qbk | 316 + .../asio/asio/src/examples/cpp03/Makefile.am | 249 + .../src/examples/cpp03/allocation/server.cpp | 238 + .../cpp03/buffers/reference_counted.cpp | 131 + .../src/examples/cpp03/chat/chat_client.cpp | 176 + .../src/examples/cpp03/chat/chat_message.hpp | 93 + .../src/examples/cpp03/chat/chat_server.cpp | 247 + .../examples/cpp03/chat/posix_chat_client.cpp | 205 + .../cpp03/echo/async_tcp_echo_server.cpp | 137 + .../cpp03/echo/async_udp_echo_server.cpp | 92 + .../cpp03/echo/blocking_tcp_echo_client.cpp | 59 + .../cpp03/echo/blocking_tcp_echo_server.cpp | 79 + .../cpp03/echo/blocking_udp_echo_client.cpp | 59 + .../cpp03/echo/blocking_udp_echo_server.cpp | 53 + .../asio/src/examples/cpp03/fork/daemon.cpp | 189 + .../cpp03/fork/process_per_connection.cpp | 160 + .../cpp03/http/client/async_client.cpp | 205 + .../cpp03/http/client/sync_client.cpp | 107 + .../examples/cpp03/http/doc_root/data_1K.html | 28 + .../examples/cpp03/http/doc_root/data_2K.html | 49 + .../examples/cpp03/http/doc_root/data_4K.html | 91 + .../examples/cpp03/http/doc_root/data_8K.html | 175 + .../examples/cpp03/http/server/connection.cpp | 99 + .../examples/cpp03/http/server/connection.hpp | 83 + .../cpp03/http/server/connection_manager.cpp | 38 + .../cpp03/http/server/connection_manager.hpp | 44 + .../src/examples/cpp03/http/server/header.hpp | 28 + .../src/examples/cpp03/http/server/main.cpp | 44 + .../examples/cpp03/http/server/mime_types.cpp | 46 + .../examples/cpp03/http/server/mime_types.hpp | 27 + .../src/examples/cpp03/http/server/reply.cpp | 256 + .../src/examples/cpp03/http/server/reply.hpp | 64 + .../examples/cpp03/http/server/request.hpp | 34 + .../cpp03/http/server/request_handler.cpp | 122 + .../cpp03/http/server/request_handler.hpp | 46 + .../cpp03/http/server/request_parser.cpp | 315 + .../cpp03/http/server/request_parser.hpp | 95 + .../src/examples/cpp03/http/server/server.cpp | 94 + .../src/examples/cpp03/http/server/server.hpp | 69 + .../cpp03/http/server2/connection.cpp | 93 + .../cpp03/http/server2/connection.hpp | 75 + .../examples/cpp03/http/server2/header.hpp | 28 + .../cpp03/http/server2/io_service_pool.cpp | 70 + .../cpp03/http/server2/io_service_pool.hpp | 56 + .../src/examples/cpp03/http/server2/main.cpp | 46 + .../cpp03/http/server2/mime_types.cpp | 46 + .../cpp03/http/server2/mime_types.hpp | 27 + .../src/examples/cpp03/http/server2/reply.cpp | 256 + .../src/examples/cpp03/http/server2/reply.hpp | 64 + .../examples/cpp03/http/server2/request.hpp | 34 + .../cpp03/http/server2/request_handler.cpp | 122 + .../cpp03/http/server2/request_handler.hpp | 46 + .../cpp03/http/server2/request_parser.cpp | 315 + .../cpp03/http/server2/request_parser.hpp | 95 + .../examples/cpp03/http/server2/server.cpp | 77 + .../examples/cpp03/http/server2/server.hpp | 68 + .../cpp03/http/server3/connection.cpp | 98 + .../cpp03/http/server3/connection.hpp | 78 + .../examples/cpp03/http/server3/header.hpp | 28 + .../src/examples/cpp03/http/server3/main.cpp | 46 + .../cpp03/http/server3/mime_types.cpp | 46 + .../cpp03/http/server3/mime_types.hpp | 27 + .../src/examples/cpp03/http/server3/reply.cpp | 256 + .../src/examples/cpp03/http/server3/reply.hpp | 64 + .../examples/cpp03/http/server3/request.hpp | 34 + .../cpp03/http/server3/request_handler.cpp | 122 + .../cpp03/http/server3/request_handler.hpp | 46 + .../cpp03/http/server3/request_parser.cpp | 315 + .../cpp03/http/server3/request_parser.hpp | 95 + .../examples/cpp03/http/server3/server.cpp | 89 + .../examples/cpp03/http/server3/server.hpp | 70 + .../cpp03/http/server4/file_handler.cpp | 122 + .../cpp03/http/server4/file_handler.hpp | 44 + .../examples/cpp03/http/server4/header.hpp | 28 + .../src/examples/cpp03/http/server4/main.cpp | 58 + .../cpp03/http/server4/mime_types.cpp | 46 + .../cpp03/http/server4/mime_types.hpp | 27 + .../src/examples/cpp03/http/server4/reply.cpp | 256 + .../src/examples/cpp03/http/server4/reply.hpp | 64 + .../examples/cpp03/http/server4/request.hpp | 46 + .../cpp03/http/server4/request_parser.cpp | 226 + .../cpp03/http/server4/request_parser.hpp | 78 + .../examples/cpp03/http/server4/server.cpp | 121 + .../examples/cpp03/http/server4/server.hpp | 73 + .../src/examples/cpp03/icmp/icmp_header.hpp | 94 + .../src/examples/cpp03/icmp/ipv4_header.hpp | 102 + .../asio/src/examples/cpp03/icmp/ping.cpp | 162 + .../cpp03/invocation/prioritised_handlers.cpp | 162 + .../cpp03/iostreams/daytime_client.cpp | 44 + .../cpp03/iostreams/daytime_server.cpp | 51 + .../examples/cpp03/iostreams/http_client.cpp | 91 + .../src/examples/cpp03/local/connect_pair.cpp | 141 + .../examples/cpp03/local/iostream_client.cpp | 62 + .../examples/cpp03/local/stream_client.cpp | 61 + .../examples/cpp03/local/stream_server.cpp | 141 + .../src/examples/cpp03/multicast/receiver.cpp | 93 + .../src/examples/cpp03/multicast/sender.cpp | 99 + .../cpp03/nonblocking/third_party_lib.cpp | 242 + .../src/examples/cpp03/porthopper/client.cpp | 193 + .../examples/cpp03/porthopper/protocol.hpp | 156 + .../src/examples/cpp03/porthopper/server.cpp | 187 + .../examples/cpp03/serialization/client.cpp | 125 + .../cpp03/serialization/connection.hpp | 188 + .../examples/cpp03/serialization/server.cpp | 123 + .../examples/cpp03/serialization/stock.hpp | 50 + .../examples/cpp03/services/basic_logger.hpp | 83 + .../cpp03/services/daytime_client.cpp | 85 + .../src/examples/cpp03/services/logger.hpp | 24 + .../cpp03/services/logger_service.cpp | 17 + .../cpp03/services/logger_service.hpp | 144 + .../cpp03/services/stream_socket_service.hpp | 351 + .../asio/src/examples/cpp03/socks4/socks4.hpp | 144 + .../src/examples/cpp03/socks4/sync_client.cpp | 95 + .../src/examples/cpp03/spawn/echo_server.cpp | 122 + .../asio/asio/src/examples/cpp03/ssl/README | 8 + .../asio/asio/src/examples/cpp03/ssl/ca.pem | 49 + .../asio/src/examples/cpp03/ssl/client.cpp | 156 + .../asio/src/examples/cpp03/ssl/dh2048.pem | 8 + .../asio/src/examples/cpp03/ssl/server.cpp | 170 + .../asio/src/examples/cpp03/ssl/server.pem | 71 + .../cpp03/timeouts/async_tcp_client.cpp | 306 + .../cpp03/timeouts/blocking_tcp_client.cpp | 242 + .../cpp03/timeouts/blocking_udp_client.cpp | 182 + .../src/examples/cpp03/timeouts/server.cpp | 427 + .../cpp03/timers/tick_count_timer.cpp | 123 + .../examples/cpp03/timers/time_t_timer.cpp | 93 + .../cpp03/tutorial/daytime1/client.cpp | 57 + .../cpp03/tutorial/daytime2/server.cpp | 50 + .../cpp03/tutorial/daytime3/server.cpp | 117 + .../cpp03/tutorial/daytime4/client.cpp | 52 + .../cpp03/tutorial/daytime5/server.cpp | 58 + .../cpp03/tutorial/daytime6/server.cpp | 89 + .../cpp03/tutorial/daytime7/server.cpp | 158 + .../examples/cpp03/tutorial/daytime_dox.txt | 502 + .../src/examples/cpp03/tutorial/index_dox.txt | 48 + .../examples/cpp03/tutorial/timer1/timer.cpp | 25 + .../examples/cpp03/tutorial/timer2/timer.cpp | 30 + .../examples/cpp03/tutorial/timer3/timer.cpp | 44 + .../examples/cpp03/tutorial/timer4/timer.cpp | 55 + .../examples/cpp03/tutorial/timer5/timer.cpp | 74 + .../src/examples/cpp03/tutorial/timer_dox.txt | 380 + .../examples/cpp03/windows/transmit_file.cpp | 171 + .../asio/asio/src/examples/cpp11/Makefile.am | 74 + .../src/examples/cpp11/allocation/server.cpp | 215 + .../cpp11/buffers/reference_counted.cpp | 123 + .../src/examples/cpp11/chat/chat_client.cpp | 167 + .../src/examples/cpp11/chat/chat_message.hpp | 91 + .../src/examples/cpp11/chat/chat_server.cpp | 229 + .../cpp11/echo/async_tcp_echo_server.cpp | 116 + .../cpp11/echo/async_udp_echo_server.cpp | 82 + .../cpp11/echo/blocking_tcp_echo_client.cpp | 55 + .../cpp11/echo/blocking_tcp_echo_server.cpp | 76 + .../cpp11/echo/blocking_udp_echo_client.cpp | 57 + .../cpp11/echo/blocking_udp_echo_server.cpp | 52 + .../examples/cpp11/futures/daytime_client.cpp | 94 + .../examples/cpp11/http/server/connection.cpp | 94 + .../examples/cpp11/http/server/connection.hpp | 79 + .../cpp11/http/server/connection_manager.cpp | 40 + .../cpp11/http/server/connection_manager.hpp | 48 + .../src/examples/cpp11/http/server/header.hpp | 28 + .../src/examples/cpp11/http/server/main.cpp | 43 + .../examples/cpp11/http/server/mime_types.cpp | 45 + .../examples/cpp11/http/server/mime_types.hpp | 27 + .../src/examples/cpp11/http/server/reply.cpp | 255 + .../src/examples/cpp11/http/server/reply.hpp | 64 + .../examples/cpp11/http/server/request.hpp | 34 + .../cpp11/http/server/request_handler.cpp | 121 + .../cpp11/http/server/request_handler.hpp | 47 + .../cpp11/http/server/request_parser.cpp | 315 + .../cpp11/http/server/request_parser.hpp | 96 + .../src/examples/cpp11/http/server/server.cpp | 94 + .../src/examples/cpp11/http/server/server.hpp | 67 + .../src/examples/cpp11/spawn/echo_server.cpp | 108 + .../deps/asio/asio/src/tests/Makefile.am | 359 + .../asio/asio/src/tests/latency/allocator.hpp | 52 + .../asio/asio/src/tests/latency/coroutine.hpp | 87 + .../asio/src/tests/latency/high_res_clock.hpp | 53 + .../asio/src/tests/latency/tcp_client.cpp | 125 + .../asio/src/tests/latency/tcp_server.cpp | 114 + .../asio/src/tests/latency/udp_client.cpp | 105 + .../asio/src/tests/latency/udp_server.cpp | 125 + .../asio/asio/src/tests/latency/unyield.hpp | 21 + .../asio/asio/src/tests/latency/yield.hpp | 23 + .../asio/src/tests/performance/client.cpp | 285 + .../tests/performance/handler_allocator.hpp | 112 + .../asio/src/tests/performance/server.cpp | 233 + .../tests/unit/archetypes/async_result.hpp | 71 + .../archetypes/gettable_socket_option.hpp | 54 + .../unit/archetypes/io_control_command.hpp | 32 + .../archetypes/settable_socket_option.hpp | 49 + .../src/tests/unit/basic_datagram_socket.cpp | 25 + .../src/tests/unit/basic_deadline_timer.cpp | 25 + .../asio/src/tests/unit/basic_raw_socket.cpp | 25 + .../tests/unit/basic_seq_packet_socket.cpp | 25 + .../asio/src/tests/unit/basic_serial_port.cpp | 26 + .../asio/src/tests/unit/basic_signal_set.cpp | 25 + .../src/tests/unit/basic_socket_acceptor.cpp | 25 + .../src/tests/unit/basic_stream_socket.cpp | 25 + .../asio/src/tests/unit/basic_streambuf.cpp | 25 + .../src/tests/unit/basic_waitable_timer.cpp | 25 + .../deps/asio/asio/src/tests/unit/buffer.cpp | 246 + .../src/tests/unit/buffered_read_stream.cpp | 338 + .../asio/src/tests/unit/buffered_stream.cpp | 364 + .../src/tests/unit/buffered_write_stream.cpp | 353 + .../asio/src/tests/unit/buffers_iterator.cpp | 292 + .../src/tests/unit/completion_condition.cpp | 25 + .../deps/asio/asio/src/tests/unit/connect.cpp | 25 + .../asio/asio/src/tests/unit/coroutine.cpp | 112 + .../tests/unit/datagram_socket_service.cpp | 25 + .../asio/src/tests/unit/deadline_timer.cpp | 356 + .../src/tests/unit/deadline_timer_service.cpp | 25 + .../deps/asio/asio/src/tests/unit/error.cpp | 89 + .../src/tests/unit/generic/basic_endpoint.cpp | 25 + .../tests/unit/generic/datagram_protocol.cpp | 259 + .../src/tests/unit/generic/raw_protocol.cpp | 259 + .../unit/generic/seq_packet_protocol.cpp | 201 + .../tests/unit/generic/stream_protocol.cpp | 244 + .../src/tests/unit/high_resolution_timer.cpp | 30 + .../asio/asio/src/tests/unit/io_service.cpp | 359 + .../asio/asio/src/tests/unit/ip/address.cpp | 124 + .../asio/src/tests/unit/ip/address_v4.cpp | 268 + .../asio/src/tests/unit/ip/address_v6.cpp | 373 + .../asio/src/tests/unit/ip/basic_endpoint.cpp | 25 + .../asio/src/tests/unit/ip/basic_resolver.cpp | 25 + .../tests/unit/ip/basic_resolver_entry.cpp | 25 + .../tests/unit/ip/basic_resolver_iterator.cpp | 25 + .../tests/unit/ip/basic_resolver_query.cpp | 25 + .../asio/asio/src/tests/unit/ip/host_name.cpp | 55 + .../deps/asio/asio/src/tests/unit/ip/icmp.cpp | 465 + .../asio/asio/src/tests/unit/ip/multicast.cpp | 367 + .../src/tests/unit/ip/resolver_query_base.cpp | 25 + .../src/tests/unit/ip/resolver_service.cpp | 25 + .../deps/asio/asio/src/tests/unit/ip/tcp.cpp | 931 + .../deps/asio/asio/src/tests/unit/ip/udp.cpp | 542 + .../asio/asio/src/tests/unit/ip/unicast.cpp | 171 + .../asio/asio/src/tests/unit/ip/v6_only.cpp | 135 + .../asio/src/tests/unit/is_read_buffered.cpp | 125 + .../asio/src/tests/unit/is_write_buffered.cpp | 125 + .../src/tests/unit/local/basic_endpoint.cpp | 25 + .../src/tests/unit/local/connect_pair.cpp | 77 + .../tests/unit/local/datagram_protocol.cpp | 231 + .../src/tests/unit/local/stream_protocol.cpp | 208 + .../asio/asio/src/tests/unit/placeholders.cpp | 25 + .../src/tests/unit/posix/basic_descriptor.cpp | 25 + .../unit/posix/basic_stream_descriptor.cpp | 25 + .../src/tests/unit/posix/descriptor_base.cpp | 25 + .../tests/unit/posix/stream_descriptor.cpp | 173 + .../unit/posix/stream_descriptor_service.cpp | 25 + .../src/tests/unit/raw_socket_service.cpp | 25 + .../deps/asio/asio/src/tests/unit/read.cpp | 3919 + .../deps/asio/asio/src/tests/unit/read_at.cpp | 7483 + .../asio/asio/src/tests/unit/read_until.cpp | 884 + .../tests/unit/seq_packet_socket_service.cpp | 25 + .../asio/asio/src/tests/unit/serial_port.cpp | 152 + .../asio/src/tests/unit/serial_port_base.cpp | 99 + .../src/tests/unit/serial_port_service.cpp | 26 + .../asio/asio/src/tests/unit/signal_set.cpp | 89 + .../src/tests/unit/signal_set_service.cpp | 25 + .../tests/unit/socket_acceptor_service.cpp | 25 + .../asio/asio/src/tests/unit/socket_base.cpp | 654 + .../asio/src/tests/unit/ssl/basic_context.cpp | 25 + .../asio/asio/src/tests/unit/ssl/context.cpp | 25 + .../asio/src/tests/unit/ssl/context_base.cpp | 25 + .../src/tests/unit/ssl/context_service.cpp | 25 + .../tests/unit/ssl/rfc2818_verification.cpp | 25 + .../asio/asio/src/tests/unit/ssl/stream.cpp | 214 + .../asio/src/tests/unit/ssl/stream_base.cpp | 25 + .../src/tests/unit/ssl/stream_service.cpp | 25 + .../asio/asio/src/tests/unit/steady_timer.cpp | 30 + .../deps/asio/asio/src/tests/unit/strand.cpp | 217 + .../src/tests/unit/stream_socket_service.cpp | 25 + .../asio/asio/src/tests/unit/streambuf.cpp | 62 + .../asio/asio/src/tests/unit/system_timer.cpp | 359 + .../deps/asio/asio/src/tests/unit/thread.cpp | 25 + .../asio/asio/src/tests/unit/time_traits.cpp | 25 + .../asio/asio/src/tests/unit/unit_test.hpp | 175 + .../asio/asio/src/tests/unit/wait_traits.cpp | 25 + .../src/tests/unit/waitable_timer_service.cpp | 25 + .../src/tests/unit/windows/basic_handle.cpp | 26 + .../unit/windows/basic_object_handle.cpp | 26 + .../windows/basic_random_access_handle.cpp | 26 + .../unit/windows/basic_stream_handle.cpp | 26 + .../src/tests/unit/windows/object_handle.cpp | 121 + .../unit/windows/object_handle_service.cpp | 26 + .../src/tests/unit/windows/overlapped_ptr.cpp | 95 + .../unit/windows/random_access_handle.cpp | 149 + .../windows/random_access_handle_service.cpp | 26 + .../src/tests/unit/windows/stream_handle.cpp | 142 + .../unit/windows/stream_handle_service.cpp | 26 + .../deps/asio/asio/src/tests/unit/write.cpp | 3914 + .../asio/asio/src/tests/unit/write_at.cpp | 7544 + .../deps/asio/asio/src/tools/handlerviz.pl | 299 + utils/dnp3_src/dotnet/bindings.sln | 169 + .../bindings/CLRAdapter/AssemblyInfo.cpp | 38 + .../bindings/CLRAdapter/CLRAdapter.vcxproj | 219 + .../CLRAdapter/CLRAdapter.vcxproj.filters | 172 + .../dotnet/bindings/CLRAdapter/ReadMe.txt | 38 + .../dotnet/bindings/CLRAdapter/app.ico | Bin 0 -> 11001 bytes .../dotnet/bindings/CLRAdapter/app.rc | Bin 0 -> 2558 bytes .../dotnet/bindings/CLRAdapter/resource.h | 3 + .../CLRAdapter/src/CallbackAdapters.cpp | 43 + .../CLRAdapter/src/CallbackAdapters.h | 36 + .../CLRAdapter/src/ChangeSetAdapter.cpp | 67 + .../CLRAdapter/src/ChangeSetAdapter.h | 46 + .../CLRAdapter/src/ChannelAdapter.cpp | 79 + .../bindings/CLRAdapter/src/ChannelAdapter.h | 57 + .../CLRAdapter/src/ChannelListenerAdapter.h | 39 + .../CLRAdapter/src/CollectionAdapter.h | 51 + .../CLRAdapter/src/CommandSetBuilder.cpp | 68 + .../CLRAdapter/src/CommandSetBuilder.h | 38 + .../bindings/CLRAdapter/src/Conversions.cpp | 484 + .../bindings/CLRAdapter/src/Conversions.h | 217 + .../CLRAdapter/src/DNP3ManagerAdapter.cpp | 166 + .../CLRAdapter/src/DNP3ManagerAdapter.h | 79 + .../bindings/CLRAdapter/src/EventConverter.h | 59 + .../CLRAdapter/src/ICommandHeaderWorkAround.h | 13 + .../CLRAdapter/src/ListenCallbacksAdapter.cpp | 49 + .../CLRAdapter/src/ListenCallbacksAdapter.h | 39 + .../bindings/CLRAdapter/src/ListenerAdapter.h | 49 + .../dotnet/bindings/CLRAdapter/src/Lock.h | 20 + .../bindings/CLRAdapter/src/LogAdapter.cpp | 36 + .../bindings/CLRAdapter/src/LogAdapter.h | 40 + .../bindings/CLRAdapter/src/MasterAdapter.cpp | 46 + .../bindings/CLRAdapter/src/MasterAdapter.h | 41 + .../CLRAdapter/src/MasterApplicationAdapter.h | 115 + .../CLRAdapter/src/MasterConversions.cpp | 163 + .../CLRAdapter/src/MasterConversions.h | 57 + .../src/MasterOperationsAdapter.cpp | 182 + .../CLRAdapter/src/MasterOperationsAdapter.h | 77 + .../CLRAdapter/src/MasterScanAdapter.h | 50 + .../CLRAdapter/src/MasterSessionAdapter.cpp | 25 + .../CLRAdapter/src/MasterSessionAdapter.h | 52 + .../CLRAdapter/src/OutstationAdapter.cpp | 64 + .../CLRAdapter/src/OutstationAdapter.h | 48 + .../src/OutstationApplicationAdapter.cpp | 107 + .../src/OutstationApplicationAdapter.h | 65 + .../src/OutstationCommandHandlerAdapter.cpp | 81 + .../src/OutstationCommandHandlerAdapter.h | 50 + .../CLRAdapter/src/SOEHandlerAdapter.cpp | 112 + .../CLRAdapter/src/SOEHandlerAdapter.h | 52 + .../CLRAdapter/src/SessionAcceptorAdapter.cpp | 40 + .../CLRAdapter/src/SessionAcceptorAdapter.h | 40 + .../CLRAdapter/src/StdIOWorkaround.cpp | 13 + .../bindings/CLRAdapter/src/StdIOWorkaround.h | 13 + .../CLRAdapter/src/TaskCallbackAdapter.h | 61 + .../bindings/CLRInterface/ApplicationIIN.cs | 19 + .../CLRInterface/BaseMeasurementTypes.cs | 127 + .../dotnet/bindings/CLRInterface/ChangeSet.cs | 116 + .../bindings/CLRInterface/ChannelRetry.cs | 59 + .../CLRInterface/ChannelStatistics.cs | 130 + .../bindings/CLRInterface/ClassAssignment.cs | 61 + .../bindings/CLRInterface/ClassField.cs | 146 + .../CLRInterface/CommandResultTypes.cs | 110 + .../bindings/CLRInterface/CommandSet.cs | 119 + .../bindings/CLRInterface/CommandTypes.cs | 116 + .../bindings/CLRInterface/Conversions.cs | 73 + .../CLRInterface/DNP3CLRInterface.csproj | 201 + .../CLRInterface/DefaultListenCallbacks.cs | 70 + .../bindings/CLRInterface/Extensions.cs | 25 + .../dotnet/bindings/CLRInterface/Header.cs | 141 + .../dotnet/bindings/CLRInterface/IChannel.cs | 79 + .../bindings/CLRInterface/IChannelListener.cs | 45 + .../CLRInterface/IChannelStatistics.cs | 58 + .../bindings/CLRInterface/ICommandHandler.cs | 131 + .../CLRInterface/ICommandProcessor.cs | 142 + .../bindings/CLRInterface/IDNP3Manager.cs | 129 + .../dotnet/bindings/CLRInterface/IDatabase.cs | 108 + .../bindings/CLRInterface/ILinkListener.cs | 42 + .../bindings/CLRInterface/IListenCallbacks.cs | 77 + .../dotnet/bindings/CLRInterface/IListener.cs | 37 + .../bindings/CLRInterface/ILogHandler.cs | 100 + .../dotnet/bindings/CLRInterface/IMaster.cs | 38 + .../CLRInterface/IMasterApplication.cs | 152 + .../CLRInterface/IMasterOperations.cs | 118 + .../bindings/CLRInterface/IMasterScan.cs | 19 + .../bindings/CLRInterface/IMasterSession.cs | 37 + .../bindings/CLRInterface/IOutstation.cs | 61 + .../CLRInterface/IOutstationApplication.cs | 180 + .../bindings/CLRInterface/IPEndpoint.cs | 33 + .../bindings/CLRInterface/IQualityBitInfo.cs | 122 + .../bindings/CLRInterface/ISOEHandler.cs | 128 + .../bindings/CLRInterface/ISessionAcceptor.cs | 16 + .../dotnet/bindings/CLRInterface/IStack.cs | 51 + .../bindings/CLRInterface/IStackStatistics.cs | 28 + .../bindings/CLRInterface/ITaskCallback.cs | 51 + .../bindings/CLRInterface/LinkHeader.cs | 57 + .../dotnet/bindings/CLRInterface/LogLevels.cs | 158 + .../bindings/CLRInterface/MeasurementTypes.cs | 432 + .../bindings/CLRInterface/NamespaceDoc.cs | 56 + .../CLRInterface/PrintingSOEHandler.cs | 217 + .../CLRInterface/Properties/AssemblyInfo.cs | 58 + .../CLRInterface/RestartResultType.cs | 58 + .../CLRInterface/SimpleCommandHandler.cs | 125 + .../bindings/CLRInterface/StackStatistics.cs | 41 + .../dotnet/bindings/CLRInterface/TLSConfig.cs | 61 + .../CLRInterface/TaskCompletionProxy.cs | 57 + .../bindings/CLRInterface/TaskConfig.cs | 49 + .../dotnet/bindings/CLRInterface/TaskId.cs | 70 + .../dotnet/bindings/CLRInterface/TaskInfo.cs | 43 + .../dotnet/bindings/CLRInterface/X509Info.cs | 26 + .../CLRInterface/config/DatabaseTemplate.cs | 166 + .../CLRInterface/config/EventBufferConfig.cs | 80 + .../CLRInterface/config/LinkConfig.cs | 189 + .../CLRInterface/config/MasterConfig.cs | 124 + .../CLRInterface/config/MasterStackConfig.cs | 33 + .../CLRInterface/config/OutstationConfig.cs | 24 + .../CLRInterface/config/OutstationParams.cs | 63 + .../config/OutstationStackConfig.cs | 40 + .../CLRInterface/config/PointRecords.cs | 178 + .../CLRInterface/config/SerialSettings.cs | 80 + .../CLRInterface/config/StaticTypeBitfield.cs | 40 + .../gen/AnalogOutputStatusQuality.cs | 61 + .../CLRInterface/gen/AnalogQuality.cs | 61 + .../CLRInterface/gen/AssignClassType.cs | 36 + .../gen/BinaryOutputStatusQuality.cs | 61 + .../CLRInterface/gen/BinaryQuality.cs | 61 + .../bindings/CLRInterface/gen/ChannelState.cs | 45 + .../CLRInterface/gen/CommandPointState.cs | 53 + .../CLRInterface/gen/CommandStatus.cs | 114 + .../bindings/CLRInterface/gen/ControlCode.cs | 90 + .../CLRInterface/gen/CounterQuality.cs | 61 + .../bindings/CLRInterface/gen/DoubleBit.cs | 45 + .../gen/DoubleBitBinaryQuality.cs | 61 + .../gen/EventAnalogOutputStatusVariation.cs | 36 + .../CLRInterface/gen/EventAnalogVariation.cs | 36 + .../gen/EventBinaryOutputStatusVariation.cs | 30 + .../CLRInterface/gen/EventBinaryVariation.cs | 31 + .../CLRInterface/gen/EventCounterVariation.cs | 32 + .../gen/EventDoubleBinaryVariation.cs | 31 + .../gen/EventFrozenCounterVariation.cs | 32 + .../bindings/CLRInterface/gen/EventMode.cs | 41 + .../gen/EventSecurityStatVariation.cs | 30 + .../bindings/CLRInterface/gen/FlagsType.cs | 36 + .../bindings/CLRInterface/gen/FlowControl.cs | 32 + .../CLRInterface/gen/FrozenCounterQuality.cs | 61 + .../bindings/CLRInterface/gen/FunctionCode.cs | 165 + .../CLRInterface/gen/GroupVariation.cs | 162 + .../bindings/CLRInterface/gen/IINField.cs | 126 + .../CLRInterface/gen/ILinkStatusListener.cs | 29 + .../bindings/CLRInterface/gen/IndexMode.cs | 37 + .../CLRInterface/gen/IntervalUnits.cs | 77 + .../CLRInterface/gen/KeyChangeMethod.cs | 38 + .../CLRInterface/gen/KeyWrapAlgorithm.cs | 38 + .../bindings/CLRInterface/gen/LinkFunction.cs | 39 + .../bindings/CLRInterface/gen/LinkStatus.cs | 37 + .../CLRInterface/gen/MasterTaskType.cs | 38 + .../bindings/CLRInterface/gen/OperateType.cs | 41 + .../bindings/CLRInterface/gen/Parity.cs | 32 + .../bindings/CLRInterface/gen/PointClass.cs | 45 + .../CLRInterface/gen/QualifierCode.cs | 38 + .../bindings/CLRInterface/gen/RestartMode.cs | 41 + .../bindings/CLRInterface/gen/RestartType.cs | 37 + .../gen/StaticAnalogOutputStatusVariation.cs | 32 + .../CLRInterface/gen/StaticAnalogVariation.cs | 34 + .../gen/StaticBinaryOutputStatusVariation.cs | 29 + .../CLRInterface/gen/StaticBinaryVariation.cs | 30 + .../gen/StaticCounterVariation.cs | 32 + .../gen/StaticDoubleBinaryVariation.cs | 29 + .../gen/StaticFrozenCounterVariation.cs | 34 + .../gen/StaticSecurityStatVariation.cs | 29 + .../gen/StaticTimeAndIntervalVariation.cs | 29 + .../CLRInterface/gen/StaticTypeBitmask.cs | 37 + .../bindings/CLRInterface/gen/StopBits.cs | 33 + .../CLRInterface/gen/TaskCompletion.cs | 65 + .../bindings/CLRInterface/gen/TimeSyncMode.cs | 37 + .../CLRInterface/gen/TimestampMode.cs | 41 + .../CLRInterface/gen/UserOperation.cs | 33 + .../bindings/CLRInterface/gen/UserRole.cs | 38 + utils/dnp3_src/dotnet/config/opendnp3.props | 19 + .../dotnet/config/openssl_lib32_dir.props | 15 + .../dotnet/config/openssl_lib64_dir.props | 15 + .../dotnet/config/ossl_debug_lib.props | 12 + .../dotnet/config/ossl_release_lib.props | 12 + utils/dnp3_src/dotnet/config/output_dir.props | 11 + .../examples/master-gprs-tls/App.config | 6 + .../CLRMasterGPRSTLSDemo.csproj | 109 + .../CLRMasterGPRSTLSDemo.csproj.user | 7 + .../examples/master-gprs-tls/Program.cs | 53 + .../Properties/AssemblyInfo.cs | 36 + .../dotnet/examples/master-gprs/App.config | 6 + .../master-gprs/CLRMasterGPRSDemo.csproj | 109 + .../master-gprs/CLRMasterGPRSDemo.csproj.user | 6 + .../dotnet/examples/master-gprs/Program.cs | 33 + .../master-gprs/Properties/AssemblyInfo.cs | 36 + .../dotnet/examples/master/App.config | 6 + .../examples/master/CLRMasterDemo.csproj | 111 + .../examples/master/CLRMasterDemo.csproj.user | 9 + .../dotnet/examples/master/Program.cs | 119 + .../master/Properties/AssemblyInfo.cs | 36 + .../dotnet/examples/outstation/App.config | 6 + .../outstation/CLROutstationDemo.csproj | 114 + .../dotnet/examples/outstation/Program.cs | 81 + .../outstation/Properties/AssemblyInfo.cs | 36 + utils/dnp3_src/dotnet/nuget/opendnp3.nuspec | 29 + .../dnp3_src/generation/AUTOMATAK_FILE_HEADER | 16 + utils/dnp3_src/generation/dnp3/pom.xml | 22 + .../com/automatak/render/dnp3/Generate.scala | 36 + .../render/dnp3/enums/AssignClassType.scala | 27 + .../render/dnp3/enums/AuthErrorCode.scala | 32 + .../render/dnp3/enums/CertificateType.scala | 24 + .../render/dnp3/enums/ChallengeReason.scala | 23 + .../render/dnp3/enums/ChannelState.scala | 21 + .../render/dnp3/enums/CommandPointState.scala | 27 + .../render/dnp3/enums/CommandStatus.scala | 44 + .../render/dnp3/enums/ConfigAuthMode.scala | 22 + .../render/dnp3/enums/ControlCode.scala | 44 + .../render/dnp3/enums/DefaultVariations.scala | 33 + .../render/dnp3/enums/DoubleBit.scala | 22 + .../render/dnp3/enums/EventMode.scala | 23 + .../render/dnp3/enums/FlagsType.scala | 26 + .../render/dnp3/enums/FunctionCode.scala | 56 + .../dnp3/enums/GroupVariationEnum.scala | 24 + .../dnp3/enums/GroupVariationType.scala | 22 + .../render/dnp3/enums/HMACType.scala | 28 + .../render/dnp3/enums/IndexMode.scala | 22 + .../render/dnp3/enums/IntervalUnit.scala | 33 + .../render/dnp3/enums/KeyChangeMethod.scala | 27 + .../render/dnp3/enums/KeyStatus.scala | 24 + .../render/dnp3/enums/KeyWrapAlgorithm.scala | 21 + .../render/dnp3/enums/LinkFunction.scala | 29 + .../render/dnp3/enums/LinkStatus.scala | 19 + .../render/dnp3/enums/LogLevel.scala | 19 + .../render/dnp3/enums/MasterTaskType.scala | 29 + .../render/dnp3/enums/OperateType.scala | 25 + .../render/dnp3/enums/PointClass.scala | 24 + .../render/dnp3/enums/QualifierCode.scala | 24 + .../render/dnp3/enums/QualityMasks.scala | 140 + .../render/dnp3/enums/RestartMode.scala | 20 + .../render/dnp3/enums/RestartType.scala | 19 + .../render/dnp3/enums/SecurityStatIndex.scala | 33 + .../render/dnp3/enums/SerialEnums.scala | 51 + .../render/dnp3/enums/StaticTypeBitmask.scala | 28 + .../render/dnp3/enums/TaskCompletion.scala | 28 + .../render/dnp3/enums/TimeSyncMode.scala | 23 + .../render/dnp3/enums/TimestampMode.scala | 21 + .../render/dnp3/enums/UserOperation.scala | 22 + .../render/dnp3/enums/UserRole.scala | 22 + .../generators/CSharpEnumGenerator.scala | 30 + .../enums/generators/CppEnumGenerator.scala | 57 + .../enums/generators/JavaEnumGenerator.scala | 29 + .../dnp3/enums/groups/CSharpEnumGroup.scala | 44 + .../dnp3/enums/groups/DNPCppEnumGroup.scala | 57 + .../render/dnp3/objects/Fields.scala | 127 + .../render/dnp3/objects/GroupVariation.scala | 101 + .../render/dnp3/objects/ObjectGroup.scala | 52 + .../render/dnp3/objects/VariationNames.scala | 36 + .../generators/AttributeGenerator.scala | 99 + .../AuthVariableSizeGenerator.scala | 242 + .../dnp3/objects/generators/Conversions.scala | 178 + .../generators/FixedSizeGenerator.scala | 68 + .../objects/generators/FixedSizeHelpers.scala | 30 + .../GroupVariationFileGenerator.scala | 85 + .../generators/GroupVariationIncludes.scala | 25 + .../generators/GroupVariationLines.scala | 15 + .../generators/GroupVariationRenderer.scala | 18 + .../render/dnp3/objects/groups/Group1.scala | 19 + .../render/dnp3/objects/groups/Group10.scala | 21 + .../render/dnp3/objects/groups/Group11.scala | 18 + .../render/dnp3/objects/groups/Group110.scala | 12 + .../render/dnp3/objects/groups/Group111.scala | 12 + .../render/dnp3/objects/groups/Group112.scala | 12 + .../render/dnp3/objects/groups/Group113.scala | 12 + .../render/dnp3/objects/groups/Group12.scala | 24 + .../render/dnp3/objects/groups/Group120.scala | 104 + .../render/dnp3/objects/groups/Group121.scala | 17 + .../render/dnp3/objects/groups/Group122.scala | 17 + .../render/dnp3/objects/groups/Group13.scala | 18 + .../render/dnp3/objects/groups/Group2.scala | 19 + .../render/dnp3/objects/groups/Group20.scala | 22 + .../render/dnp3/objects/groups/Group21.scala | 34 + .../render/dnp3/objects/groups/Group22.scala | 21 + .../render/dnp3/objects/groups/Group23.scala | 20 + .../render/dnp3/objects/groups/Group3.scala | 18 + .../render/dnp3/objects/groups/Group30.scala | 22 + .../render/dnp3/objects/groups/Group32.scala | 25 + .../render/dnp3/objects/groups/Group4.scala | 19 + .../render/dnp3/objects/groups/Group40.scala | 21 + .../render/dnp3/objects/groups/Group41.scala | 21 + .../render/dnp3/objects/groups/Group42.scala | 25 + .../render/dnp3/objects/groups/Group43.scala | 24 + .../render/dnp3/objects/groups/Group50.scala | 23 + .../render/dnp3/objects/groups/Group51.scala | 16 + .../render/dnp3/objects/groups/Group52.scala | 15 + .../render/dnp3/objects/groups/Group60.scala | 15 + .../render/dnp3/objects/groups/Group70.scala | 32 + .../render/dnp3/objects/groups/Group80.scala | 14 + .../GroupVariationRenderingTestSuite.scala | 27 + .../render/dnp3/GroupVariationTestSuite.scala | 39 + utils/dnp3_src/generation/pom.xml | 171 + utils/dnp3_src/generation/render/pom.xml | 18 + .../com/automatak/render/EnumModel.scala | 79 + .../scala/com/automatak/render/Header.scala | 30 + .../com/automatak/render/Indentation.scala | 7 + .../com/automatak/render/ModelRenderer.scala | 29 + .../render/cc/EnumModelRenderer.scala | 49 + .../automatak/render/cpp/CppFunction.scala | 24 + .../automatak/render/cpp/CppIndentation.scala | 26 + .../com/automatak/render/cpp/EnumConfig.scala | 6 + .../automatak/render/cpp/EnumFromType.scala | 51 + .../render/cpp/EnumModelRenderer.scala | 46 + .../automatak/render/cpp/EnumToString.scala | 50 + .../com/automatak/render/cpp/EnumToType.scala | 44 + .../render/cpp/HeaderImplModelRender.scala | 8 + .../render/cpp/SwitchModelRenderer.scala | 37 + .../com/automatak/render/cpp/package.scala | 125 + .../render/csharp/EnumModelRenderer.scala | 52 + .../com/automatak/render/csharp/package.scala | 10 + .../render/java/EnumModelRenderer.scala | 82 + .../scala/com/automatak/render/pacakge.scala | 123 + utils/dnp3_src/java/AUTOMATAK_FILE_HEADER | 16 + utils/dnp3_src/java/README.md | 40 + utils/dnp3_src/java/bindings/pom.xml | 14 + .../automatak/dnp3/ActionCommandHeader.java | 59 + .../java/com/automatak/dnp3/AnalogConfig.java | 33 + .../java/com/automatak/dnp3/AnalogInput.java | 44 + .../automatak/dnp3/AnalogOutputDouble64.java | 38 + .../automatak/dnp3/AnalogOutputFloat32.java | 38 + .../com/automatak/dnp3/AnalogOutputInt16.java | 38 + .../com/automatak/dnp3/AnalogOutputInt32.java | 38 + .../automatak/dnp3/AnalogOutputStatus.java | 39 + .../dnp3/AnalogOutputStatusConfig.java | 33 + .../com/automatak/dnp3/ApplicationIIN.java | 46 + .../java/com/automatak/dnp3/BinaryConfig.java | 38 + .../java/com/automatak/dnp3/BinaryInput.java | 40 + .../automatak/dnp3/BinaryOutputStatus.java | 39 + .../dnp3/BinaryOutputStatusConfig.java | 33 + .../java/com/automatak/dnp3/ChangeSet.java | 31 + .../main/java/com/automatak/dnp3/Channel.java | 67 + .../com/automatak/dnp3/ChannelListener.java | 33 + .../java/com/automatak/dnp3/ChannelRetry.java | 50 + .../com/automatak/dnp3/ChannelStatistics.java | 39 + .../com/automatak/dnp3/ClassAssignment.java | 39 + .../java/com/automatak/dnp3/ClassField.java | 72 + .../com/automatak/dnp3/CommandBuilder.java | 31 + .../com/automatak/dnp3/CommandHandler.java | 124 + .../com/automatak/dnp3/CommandHeader.java | 98 + .../com/automatak/dnp3/CommandHeaders.java | 27 + .../automatak/dnp3/CommandPointResult.java | 49 + .../com/automatak/dnp3/CommandProcessor.java | 121 + .../java/com/automatak/dnp3/CommandSet.java | 48 + .../com/automatak/dnp3/CommandTaskResult.java | 53 + .../dnp3/ControlRelayOutputBlock.java | 52 + .../main/java/com/automatak/dnp3/Counter.java | 39 + .../com/automatak/dnp3/CounterConfig.java | 33 + .../com/automatak/dnp3/DNP3Exception.java | 26 + .../java/com/automatak/dnp3/DNP3Manager.java | 104 + .../main/java/com/automatak/dnp3/DNPTime.java | 20 + .../java/com/automatak/dnp3/Database.java | 133 + .../com/automatak/dnp3/DatabaseConfig.java | 58 + .../automatak/dnp3/DoubleBinaryConfig.java | 33 + .../automatak/dnp3/DoubleBitBinaryInput.java | 41 + .../com/automatak/dnp3/EventBufferConfig.java | 95 + .../java/com/automatak/dnp3/EventConfig.java | 32 + .../com/automatak/dnp3/ExceptionScan.java | 50 + .../com/automatak/dnp3/FrozenCounter.java | 39 + .../automatak/dnp3/FrozenCounterConfig.java | 33 + .../main/java/com/automatak/dnp3/Header.java | 139 + .../java/com/automatak/dnp3/HeaderInfo.java | 71 + .../java/com/automatak/dnp3/IINField.java | 91 + .../java/com/automatak/dnp3/IndexedValue.java | 40 + .../com/automatak/dnp3/LinkLayerConfig.java | 84 + .../automatak/dnp3/LinkLayerStatistics.java | 39 + .../com/automatak/dnp3/LinkStatistics.java | 17 + .../automatak/dnp3/LinkStatusListener.java | 48 + .../java/com/automatak/dnp3/LogEntry.java | 61 + .../java/com/automatak/dnp3/LogHandler.java | 32 + .../java/com/automatak/dnp3/LogLevels.java | 86 + .../java/com/automatak/dnp3/LogMasks.java | 27 + .../main/java/com/automatak/dnp3/Master.java | 56 + .../com/automatak/dnp3/MasterApplication.java | 76 + .../java/com/automatak/dnp3/MasterConfig.java | 99 + .../com/automatak/dnp3/MasterStackConfig.java | 45 + .../java/com/automatak/dnp3/Measurement.java | 34 + .../java/com/automatak/dnp3/OctetString.java | 33 + .../java/com/automatak/dnp3/Outstation.java | 32 + .../automatak/dnp3/OutstationApplication.java | 59 + .../automatak/dnp3/OutstationChangeSet.java | 113 + .../com/automatak/dnp3/OutstationConfig.java | 70 + .../automatak/dnp3/OutstationStackConfig.java | 52 + .../com/automatak/dnp3/ParserStatistics.java | 61 + .../com/automatak/dnp3/PointClassMasks.java | 28 + .../java/com/automatak/dnp3/QualityField.java | 31 + .../main/java/com/automatak/dnp3/Range.java | 50 + .../java/com/automatak/dnp3/SOEHandler.java | 94 + .../com/automatak/dnp3/SerialSettings.java | 67 + .../main/java/com/automatak/dnp3/Stack.java | 53 + .../com/automatak/dnp3/StackStatistics.java | 20 + .../java/com/automatak/dnp3/TLSConfig.java | 68 + .../main/java/com/automatak/dnp3/TaskId.java | 41 + .../java/com/automatak/dnp3/TaskInfo.java | 36 + .../automatak/dnp3/TransportStatistics.java | 51 + .../dnp3/enums/AnalogOutputStatusQuality.java | 96 + .../automatak/dnp3/enums/AnalogQuality.java | 96 + .../automatak/dnp3/enums/AssignClassType.java | 69 + .../dnp3/enums/BinaryOutputStatusQuality.java | 96 + .../automatak/dnp3/enums/BinaryQuality.java | 96 + .../automatak/dnp3/enums/ChannelState.java | 70 + .../dnp3/enums/CommandPointState.java | 84 + .../automatak/dnp3/enums/CommandStatus.java | 173 + .../com/automatak/dnp3/enums/ControlCode.java | 137 + .../automatak/dnp3/enums/CounterQuality.java | 96 + .../com/automatak/dnp3/enums/DoubleBit.java | 70 + .../dnp3/enums/DoubleBitBinaryQuality.java | 96 + .../EventAnalogOutputStatusVariation.java | 71 + .../dnp3/enums/EventAnalogVariation.java | 71 + .../EventBinaryOutputStatusVariation.java | 53 + .../dnp3/enums/EventBinaryVariation.java | 56 + .../dnp3/enums/EventCounterVariation.java | 59 + .../enums/EventDoubleBinaryVariation.java | 56 + .../enums/EventFrozenCounterVariation.java | 59 + .../com/automatak/dnp3/enums/EventMode.java | 66 + .../enums/EventSecurityStatVariation.java | 53 + .../com/automatak/dnp3/enums/FlagsType.java | 67 + .../com/automatak/dnp3/enums/FlowControl.java | 55 + .../dnp3/enums/FrozenCounterQuality.java | 96 + .../automatak/dnp3/enums/GroupVariation.java | 445 + .../com/automatak/dnp3/enums/IndexMode.java | 60 + .../automatak/dnp3/enums/IntervalUnits.java | 118 + .../automatak/dnp3/enums/KeyChangeMethod.java | 73 + .../dnp3/enums/KeyWrapAlgorithm.java | 61 + .../automatak/dnp3/enums/LinkFunction.java | 76 + .../com/automatak/dnp3/enums/LinkStatus.java | 60 + .../automatak/dnp3/enums/MasterTaskType.java | 75 + .../com/automatak/dnp3/enums/OperateType.java | 66 + .../java/com/automatak/dnp3/enums/Parity.java | 55 + .../com/automatak/dnp3/enums/PointClass.java | 72 + .../automatak/dnp3/enums/QualifierCode.java | 73 + .../com/automatak/dnp3/enums/RestartMode.java | 66 + .../com/automatak/dnp3/enums/RestartType.java | 60 + .../StaticAnalogOutputStatusVariation.java | 59 + .../dnp3/enums/StaticAnalogVariation.java | 65 + .../StaticBinaryOutputStatusVariation.java | 50 + .../dnp3/enums/StaticBinaryVariation.java | 53 + .../dnp3/enums/StaticCounterVariation.java | 59 + .../enums/StaticDoubleBinaryVariation.java | 50 + .../enums/StaticFrozenCounterVariation.java | 65 + .../enums/StaticSecurityStatVariation.java | 50 + .../enums/StaticTimeAndIntervalVariation.java | 50 + .../dnp3/enums/StaticTypeBitmask.java | 72 + .../com/automatak/dnp3/enums/StopBits.java | 58 + .../automatak/dnp3/enums/TaskCompletion.java | 100 + .../automatak/dnp3/enums/TimeSyncMode.java | 58 + .../automatak/dnp3/enums/TimestampMode.java | 64 + .../automatak/dnp3/enums/UserOperation.java | 58 + .../com/automatak/dnp3/enums/UserRole.java | 73 + .../automatak/dnp3/enums/package-info.java | 22 + .../automatak/dnp3/impl/ChangeSetImpl.java | 135 + .../com/automatak/dnp3/impl/ChannelImpl.java | 90 + .../dnp3/impl/CommandBuilderImpl.java | 76 + .../dnp3/impl/DNP3ManagerFactory.java | 77 + .../com/automatak/dnp3/impl/ManagerImpl.java | 156 + .../com/automatak/dnp3/impl/MasterImpl.java | 185 + .../automatak/dnp3/impl/OutstationImpl.java | 81 + .../com/automatak/dnp3/impl/package-info.java | 24 + .../dnp3/mock/ConstantCommandHandler.java | 83 + .../dnp3/mock/DefaultMasterApplication.java | 86 + .../mock/DefaultOutstationApplication.java | 67 + .../automatak/dnp3/mock/OutputHandler.java | 23 + .../dnp3/mock/PrintingChannelListener.java | 39 + .../dnp3/mock/PrintingLogHandler.java | 85 + .../dnp3/mock/PrintingSOEHandler.java | 100 + .../dnp3/mock/SuccessCommandHandler.java | 36 + .../com/automatak/dnp3/mock/package-info.java | 24 + .../java/com/automatak/dnp3/package-info.java | 35 + .../dnp3/impl/DNP3ManagerIntegrationTest.java | 96 + .../dnp3/impl/ExpectedValueTestSuite.java | 62 + .../impl/mocks/BlockingChannelListener.java | 52 + .../dnp3/impl/mocks/ExpectedValue.java | 96 + .../dnp3/impl/mocks/NullLogHandler.java | 29 + .../dnp3/impl/mocks/QueuedSOEHandler.java | 111 + .../automatak/dnp3/impl/mocks/StackPair.java | 237 + utils/dnp3_src/java/codegen/pom.xml | 29 + .../com/automatak/dnp3/codegen/Classes.scala | 128 + .../automatak/dnp3/codegen/ConfigTypes.scala | 71 + .../automatak/dnp3/codegen/Generator.scala | 30 + .../automatak/dnp3/codegen/Indentation.scala | 25 + .../dnp3/codegen/JCacheGenerator.scala | 67 + .../dnp3/codegen/JNIClassGenerator.scala | 157 + .../automatak/dnp3/codegen/JNIMethod.scala | 221 + .../com/automatak/dnp3/codegen/License.scala | 27 + .../com/automatak/dnp3/codegen/package.scala | 129 + utils/dnp3_src/java/cpp/adapters/CString.h | 59 + .../cpp/adapters/ChannelListenerAdapter.h | 47 + .../cpp/adapters/CommandHandlerAdapter.cpp | 156 + .../java/cpp/adapters/CommandHandlerAdapter.h | 69 + .../java/cpp/adapters/ConfigReader.cpp | 246 + .../dnp3_src/java/cpp/adapters/ConfigReader.h | 57 + .../java/cpp/adapters/Conversions.cpp | 45 + .../dnp3_src/java/cpp/adapters/Conversions.h | 37 + utils/dnp3_src/java/cpp/adapters/GlobalRef.h | 58 + utils/dnp3_src/java/cpp/adapters/JNI.cpp | 97 + utils/dnp3_src/java/cpp/adapters/JNI.h | 59 + utils/dnp3_src/java/cpp/adapters/LocalRef.h | 77 + .../java/cpp/adapters/LogHandlerAdapter.cpp | 42 + .../java/cpp/adapters/LogHandlerAdapter.h | 39 + .../cpp/adapters/MasterApplicationAdapter.cpp | 110 + .../cpp/adapters/MasterApplicationAdapter.h | 49 + .../adapters/OutstationApplicationAdapter.cpp | 65 + .../adapters/OutstationApplicationAdapter.h | 47 + .../java/cpp/adapters/SOEHandlerAdapter.cpp | 170 + .../java/cpp/adapters/SOEHandlerAdapter.h | 62 + .../com_automatak_dnp3_impl_ChangeSetImpl.cpp | 90 + .../com_automatak_dnp3_impl_ChangeSetImpl.h | 85 + .../com_automatak_dnp3_impl_ChannelImpl.cpp | 119 + .../cpp/com_automatak_dnp3_impl_ChannelImpl.h | 61 + ...automatak_dnp3_impl_CommandBuilderImpl.cpp | 125 + ...m_automatak_dnp3_impl_CommandBuilderImpl.h | 69 + ...m_automatak_dnp3_impl_DNP3ManagerFactory.h | 13 + .../com_automatak_dnp3_impl_ManagerImpl.cpp | 174 + .../cpp/com_automatak_dnp3_impl_ManagerImpl.h | 69 + .../com_automatak_dnp3_impl_MasterImpl.cpp | 201 + .../cpp/com_automatak_dnp3_impl_MasterImpl.h | 93 + ...com_automatak_dnp3_impl_OutstationImpl.cpp | 76 + .../com_automatak_dnp3_impl_OutstationImpl.h | 69 + utils/dnp3_src/java/cpp/jni/JCache.cpp | 307 + utils/dnp3_src/java/cpp/jni/JCache.h | 219 + .../dnp3_src/java/cpp/jni/JNIAnalogConfig.cpp | 71 + utils/dnp3_src/java/cpp/jni/JNIAnalogConfig.h | 62 + .../dnp3_src/java/cpp/jni/JNIAnalogInput.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIAnalogInput.h | 56 + .../java/cpp/jni/JNIAnalogOutputDouble64.cpp | 65 + .../java/cpp/jni/JNIAnalogOutputDouble64.h | 64 + .../java/cpp/jni/JNIAnalogOutputFloat32.cpp | 65 + .../java/cpp/jni/JNIAnalogOutputFloat32.h | 64 + .../java/cpp/jni/JNIAnalogOutputInt16.cpp | 65 + .../java/cpp/jni/JNIAnalogOutputInt16.h | 64 + .../java/cpp/jni/JNIAnalogOutputInt32.cpp | 65 + .../java/cpp/jni/JNIAnalogOutputInt32.h | 64 + .../java/cpp/jni/JNIAnalogOutputStatus.cpp | 49 + .../java/cpp/jni/JNIAnalogOutputStatus.h | 56 + .../cpp/jni/JNIAnalogOutputStatusConfig.cpp | 71 + .../cpp/jni/JNIAnalogOutputStatusConfig.h | 62 + .../java/cpp/jni/JNIApplicationIIN.cpp | 73 + .../dnp3_src/java/cpp/jni/JNIApplicationIIN.h | 62 + utils/dnp3_src/java/cpp/jni/JNIArrayList.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIArrayList.h | 62 + .../java/cpp/jni/JNIAssignClassType.cpp | 57 + .../java/cpp/jni/JNIAssignClassType.h | 58 + .../dnp3_src/java/cpp/jni/JNIBinaryConfig.cpp | 63 + utils/dnp3_src/java/cpp/jni/JNIBinaryConfig.h | 60 + .../dnp3_src/java/cpp/jni/JNIBinaryInput.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIBinaryInput.h | 56 + .../java/cpp/jni/JNIBinaryOutputStatus.cpp | 49 + .../java/cpp/jni/JNIBinaryOutputStatus.h | 56 + .../cpp/jni/JNIBinaryOutputStatusConfig.cpp | 63 + .../cpp/jni/JNIBinaryOutputStatusConfig.h | 60 + .../java/cpp/jni/JNIChannelListener.cpp | 49 + .../java/cpp/jni/JNIChannelListener.h | 56 + .../dnp3_src/java/cpp/jni/JNIChannelState.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIChannelState.h | 58 + .../java/cpp/jni/JNIChannelStatistics.cpp | 49 + .../java/cpp/jni/JNIChannelStatistics.h | 56 + .../java/cpp/jni/JNIClassAssignment.cpp | 73 + .../java/cpp/jni/JNIClassAssignment.h | 62 + utils/dnp3_src/java/cpp/jni/JNIClassField.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIClassField.h | 56 + .../java/cpp/jni/JNICommandHandler.cpp | 137 + .../dnp3_src/java/cpp/jni/JNICommandHandler.h | 78 + .../java/cpp/jni/JNICommandPointResult.cpp | 49 + .../java/cpp/jni/JNICommandPointResult.h | 56 + .../java/cpp/jni/JNICommandPointState.cpp | 57 + .../java/cpp/jni/JNICommandPointState.h | 58 + .../java/cpp/jni/JNICommandProcessor.cpp | 137 + .../java/cpp/jni/JNICommandProcessor.h | 78 + .../java/cpp/jni/JNICommandStatus.cpp | 57 + .../dnp3_src/java/cpp/jni/JNICommandStatus.h | 58 + .../java/cpp/jni/JNICommandTaskResult.cpp | 49 + .../java/cpp/jni/JNICommandTaskResult.h | 56 + .../java/cpp/jni/JNICompletableFuture.cpp | 49 + .../java/cpp/jni/JNICompletableFuture.h | 56 + .../dnp3_src/java/cpp/jni/JNIControlCode.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIControlCode.h | 58 + .../cpp/jni/JNIControlRelayOutputBlock.cpp | 89 + .../java/cpp/jni/JNIControlRelayOutputBlock.h | 70 + utils/dnp3_src/java/cpp/jni/JNICounter.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNICounter.h | 56 + .../java/cpp/jni/JNICounterConfig.cpp | 71 + .../dnp3_src/java/cpp/jni/JNICounterConfig.h | 62 + utils/dnp3_src/java/cpp/jni/JNIDNPTime.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIDNPTime.h | 56 + .../java/cpp/jni/JNIDatabaseConfig.cpp | 97 + .../dnp3_src/java/cpp/jni/JNIDatabaseConfig.h | 68 + .../java/cpp/jni/JNIDoubleBinaryConfig.cpp | 63 + .../java/cpp/jni/JNIDoubleBinaryConfig.h | 60 + utils/dnp3_src/java/cpp/jni/JNIDoubleBit.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIDoubleBit.h | 58 + .../java/cpp/jni/JNIDoubleBitBinaryInput.cpp | 49 + .../java/cpp/jni/JNIDoubleBitBinaryInput.h | 56 + utils/dnp3_src/java/cpp/jni/JNIDuration.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIDuration.h | 56 + .../JNIEventAnalogOutputStatusVariation.cpp | 57 + .../jni/JNIEventAnalogOutputStatusVariation.h | 58 + .../java/cpp/jni/JNIEventAnalogVariation.cpp | 57 + .../java/cpp/jni/JNIEventAnalogVariation.h | 58 + .../JNIEventBinaryOutputStatusVariation.cpp | 57 + .../jni/JNIEventBinaryOutputStatusVariation.h | 58 + .../java/cpp/jni/JNIEventBinaryVariation.cpp | 57 + .../java/cpp/jni/JNIEventBinaryVariation.h | 58 + .../java/cpp/jni/JNIEventBufferConfig.cpp | 97 + .../java/cpp/jni/JNIEventBufferConfig.h | 68 + .../dnp3_src/java/cpp/jni/JNIEventConfig.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIEventConfig.h | 58 + .../java/cpp/jni/JNIEventCounterVariation.cpp | 57 + .../java/cpp/jni/JNIEventCounterVariation.h | 58 + .../cpp/jni/JNIEventDoubleBinaryVariation.cpp | 57 + .../cpp/jni/JNIEventDoubleBinaryVariation.h | 58 + .../jni/JNIEventFrozenCounterVariation.cpp | 57 + .../cpp/jni/JNIEventFrozenCounterVariation.h | 58 + .../java/cpp/jni/JNIFrozenCounter.cpp | 49 + .../dnp3_src/java/cpp/jni/JNIFrozenCounter.h | 56 + .../java/cpp/jni/JNIFrozenCounterConfig.cpp | 71 + .../java/cpp/jni/JNIFrozenCounterConfig.h | 62 + .../java/cpp/jni/JNIGroupVariation.cpp | 57 + .../dnp3_src/java/cpp/jni/JNIGroupVariation.h | 58 + utils/dnp3_src/java/cpp/jni/JNIHeader.cpp | 89 + utils/dnp3_src/java/cpp/jni/JNIHeader.h | 66 + utils/dnp3_src/java/cpp/jni/JNIHeaderInfo.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIHeaderInfo.h | 56 + utils/dnp3_src/java/cpp/jni/JNIIINField.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIIINField.h | 56 + utils/dnp3_src/java/cpp/jni/JNIIndexMode.cpp | 73 + utils/dnp3_src/java/cpp/jni/JNIIndexMode.h | 62 + .../dnp3_src/java/cpp/jni/JNIIndexedValue.cpp | 65 + utils/dnp3_src/java/cpp/jni/JNIIndexedValue.h | 64 + utils/dnp3_src/java/cpp/jni/JNIIterable.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIIterable.h | 56 + utils/dnp3_src/java/cpp/jni/JNIIterator.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIIterator.h | 58 + .../java/cpp/jni/JNILinkLayerConfig.cpp | 97 + .../java/cpp/jni/JNILinkLayerConfig.h | 68 + .../java/cpp/jni/JNILinkLayerStatistics.cpp | 49 + .../java/cpp/jni/JNILinkLayerStatistics.h | 56 + .../java/cpp/jni/JNILinkStatistics.cpp | 49 + .../dnp3_src/java/cpp/jni/JNILinkStatistics.h | 56 + utils/dnp3_src/java/cpp/jni/JNIList.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNIList.h | 56 + utils/dnp3_src/java/cpp/jni/JNILogEntry.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNILogEntry.h | 56 + utils/dnp3_src/java/cpp/jni/JNILogHandler.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNILogHandler.h | 56 + .../java/cpp/jni/JNIMasterApplication.cpp | 105 + .../java/cpp/jni/JNIMasterApplication.h | 70 + .../dnp3_src/java/cpp/jni/JNIMasterConfig.cpp | 137 + utils/dnp3_src/java/cpp/jni/JNIMasterConfig.h | 78 + .../java/cpp/jni/JNIMasterStackConfig.cpp | 57 + .../java/cpp/jni/JNIMasterStackConfig.h | 58 + .../java/cpp/jni/JNIMasterTaskType.cpp | 57 + .../dnp3_src/java/cpp/jni/JNIMasterTaskType.h | 58 + .../dnp3_src/java/cpp/jni/JNIOperateType.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIOperateType.h | 58 + .../java/cpp/jni/JNIOutstationApplication.cpp | 81 + .../java/cpp/jni/JNIOutstationApplication.h | 64 + .../java/cpp/jni/JNIOutstationConfig.cpp | 105 + .../java/cpp/jni/JNIOutstationConfig.h | 70 + .../java/cpp/jni/JNIOutstationStackConfig.cpp | 73 + .../java/cpp/jni/JNIOutstationStackConfig.h | 62 + .../java/cpp/jni/JNIParserStatistics.cpp | 49 + .../java/cpp/jni/JNIParserStatistics.h | 56 + utils/dnp3_src/java/cpp/jni/JNIPointClass.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNIPointClass.h | 58 + .../java/cpp/jni/JNIQualifierCode.cpp | 57 + .../dnp3_src/java/cpp/jni/JNIQualifierCode.h | 58 + utils/dnp3_src/java/cpp/jni/JNIRange.cpp | 65 + utils/dnp3_src/java/cpp/jni/JNIRange.h | 64 + utils/dnp3_src/java/cpp/jni/JNISOEHandler.cpp | 121 + utils/dnp3_src/java/cpp/jni/JNISOEHandler.h | 74 + utils/dnp3_src/java/cpp/jni/JNIStack.cpp | 81 + utils/dnp3_src/java/cpp/jni/JNIStack.h | 64 + .../java/cpp/jni/JNIStackStatistics.cpp | 49 + .../java/cpp/jni/JNIStackStatistics.h | 56 + .../JNIStaticAnalogOutputStatusVariation.cpp | 57 + .../JNIStaticAnalogOutputStatusVariation.h | 58 + .../java/cpp/jni/JNIStaticAnalogVariation.cpp | 57 + .../java/cpp/jni/JNIStaticAnalogVariation.h | 58 + .../JNIStaticBinaryOutputStatusVariation.cpp | 57 + .../JNIStaticBinaryOutputStatusVariation.h | 58 + .../java/cpp/jni/JNIStaticBinaryVariation.cpp | 57 + .../java/cpp/jni/JNIStaticBinaryVariation.h | 58 + .../cpp/jni/JNIStaticCounterVariation.cpp | 57 + .../java/cpp/jni/JNIStaticCounterVariation.h | 58 + .../jni/JNIStaticDoubleBinaryVariation.cpp | 57 + .../cpp/jni/JNIStaticDoubleBinaryVariation.h | 58 + .../jni/JNIStaticFrozenCounterVariation.cpp | 57 + .../cpp/jni/JNIStaticFrozenCounterVariation.h | 58 + utils/dnp3_src/java/cpp/jni/JNITLSConfig.cpp | 105 + utils/dnp3_src/java/cpp/jni/JNITLSConfig.h | 70 + .../java/cpp/jni/JNITaskCompletion.cpp | 57 + .../dnp3_src/java/cpp/jni/JNITaskCompletion.h | 58 + utils/dnp3_src/java/cpp/jni/JNITaskConfig.cpp | 46 + utils/dnp3_src/java/cpp/jni/JNITaskConfig.h | 49 + utils/dnp3_src/java/cpp/jni/JNITaskId.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNITaskId.h | 56 + utils/dnp3_src/java/cpp/jni/JNITaskInfo.cpp | 49 + utils/dnp3_src/java/cpp/jni/JNITaskInfo.h | 56 + .../dnp3_src/java/cpp/jni/JNITimeSyncMode.cpp | 57 + utils/dnp3_src/java/cpp/jni/JNITimeSyncMode.h | 58 + .../java/cpp/jni/JNITimestampMode.cpp | 57 + .../dnp3_src/java/cpp/jni/JNITimestampMode.h | 58 + .../java/cpp/jni/JNITransportStatistics.cpp | 49 + .../java/cpp/jni/JNITransportStatistics.h | 56 + utils/dnp3_src/java/example/pom.xml | 23 + .../automatak/dnp3/example/MasterDemo.java | 112 + .../dnp3/example/OutstationDemo.java | 100 + utils/dnp3_src/java/pom.xml | 215 + utils/dnp3_src/java/run-javah.bat | 4 + utils/dnp3_src/profile/opendnp3_profile.xml | 4551 + utils/glue_generator_src/glue_generator.cpp | 257 + utils/libmodbus_src/AUTHORS | 8 + utils/libmodbus_src/CONTRIBUTING.md | 29 + utils/libmodbus_src/COPYING.LESSER | 502 + utils/libmodbus_src/ISSUE_TEMPLATE.md | 13 + utils/libmodbus_src/MIGRATION | 53 + utils/libmodbus_src/Makefile.am | 16 + utils/libmodbus_src/NEWS | 517 + utils/libmodbus_src/README.md | 90 + utils/libmodbus_src/acinclude.m4 | 29 + utils/libmodbus_src/autogen.sh | 14 + utils/libmodbus_src/configure.ac | 183 + utils/libmodbus_src/doc/Makefile.am | 85 + utils/libmodbus_src/doc/asciidoc.conf | 51 + utils/libmodbus_src/doc/libmodbus.txt | 280 + utils/libmodbus_src/doc/modbus_close.txt | 51 + utils/libmodbus_src/doc/modbus_connect.txt | 52 + utils/libmodbus_src/doc/modbus_flush.txt | 30 + utils/libmodbus_src/doc/modbus_free.txt | 33 + .../doc/modbus_get_byte_from_bits.txt | 35 + .../doc/modbus_get_byte_timeout.txt | 50 + utils/libmodbus_src/doc/modbus_get_float.txt | 39 + .../doc/modbus_get_float_abcd.txt | 39 + .../doc/modbus_get_float_badc.txt | 39 + .../doc/modbus_get_float_cdab.txt | 39 + .../doc/modbus_get_float_dcba.txt | 39 + .../doc/modbus_get_header_length.txt | 35 + .../doc/modbus_get_response_timeout.txt | 52 + utils/libmodbus_src/doc/modbus_get_socket.txt | 35 + .../libmodbus_src/doc/modbus_mapping_free.txt | 34 + .../libmodbus_src/doc/modbus_mapping_new.txt | 69 + .../doc/modbus_mapping_new_start_address.txt | 81 + .../doc/modbus_mask_write_register.txt | 41 + utils/libmodbus_src/doc/modbus_new_rtu.txt | 87 + utils/libmodbus_src/doc/modbus_new_tcp.txt | 71 + utils/libmodbus_src/doc/modbus_new_tcp_pi.txt | 73 + utils/libmodbus_src/doc/modbus_read_bits.txt | 48 + .../doc/modbus_read_input_bits.txt | 47 + .../doc/modbus_read_input_registers.txt | 51 + .../doc/modbus_read_registers.txt | 79 + utils/libmodbus_src/doc/modbus_receive.txt | 42 + .../doc/modbus_receive_confirmation.txt | 53 + utils/libmodbus_src/doc/modbus_reply.txt | 52 + .../doc/modbus_reply_exception.txt | 57 + .../doc/modbus_report_slave_id.txt | 61 + .../libmodbus_src/doc/modbus_rtu_get_rts.txt | 47 + .../doc/modbus_rtu_get_rts_delay.txt | 46 + .../doc/modbus_rtu_get_serial_mode.txt | 53 + .../doc/modbus_rtu_set_custom_rts.txt | 45 + .../libmodbus_src/doc/modbus_rtu_set_rts.txt | 81 + .../doc/modbus_rtu_set_rts_delay.txt | 46 + .../doc/modbus_rtu_set_serial_mode.txt | 56 + .../doc/modbus_send_raw_request.txt | 68 + .../doc/modbus_set_bits_from_byte.txt | 36 + .../doc/modbus_set_bits_from_bytes.txt | 36 + .../doc/modbus_set_byte_timeout.txt | 54 + utils/libmodbus_src/doc/modbus_set_debug.txt | 38 + .../doc/modbus_set_error_recovery.txt | 70 + utils/libmodbus_src/doc/modbus_set_float.txt | 36 + .../doc/modbus_set_float_abcd.txt | 38 + .../doc/modbus_set_float_badc.txt | 38 + .../doc/modbus_set_float_cdab.txt | 39 + .../doc/modbus_set_float_dcba.txt | 37 + .../doc/modbus_set_response_timeout.txt | 65 + utils/libmodbus_src/doc/modbus_set_slave.txt | 80 + utils/libmodbus_src/doc/modbus_set_socket.txt | 56 + utils/libmodbus_src/doc/modbus_strerror.txt | 54 + utils/libmodbus_src/doc/modbus_tcp_accept.txt | 56 + utils/libmodbus_src/doc/modbus_tcp_listen.txt | 72 + .../doc/modbus_tcp_pi_accept.txt | 56 + .../doc/modbus_tcp_pi_listen.txt | 67 + .../doc/modbus_write_and_read_registers.txt | 51 + utils/libmodbus_src/doc/modbus_write_bit.txt | 38 + utils/libmodbus_src/doc/modbus_write_bits.txt | 45 + .../doc/modbus_write_register.txt | 38 + .../doc/modbus_write_registers.txt | 38 + utils/libmodbus_src/libmodbus.pc.in | 10 + utils/libmodbus_src/m4/.gitignore | 5 + utils/libmodbus_src/src/Makefile.am | 42 + utils/libmodbus_src/src/modbus-data.c | 229 + utils/libmodbus_src/src/modbus-private.h | 115 + utils/libmodbus_src/src/modbus-rtu-private.h | 76 + utils/libmodbus_src/src/modbus-rtu.c | 1275 + utils/libmodbus_src/src/modbus-rtu.h | 42 + utils/libmodbus_src/src/modbus-tcp-private.h | 44 + utils/libmodbus_src/src/modbus-tcp.c | 901 + utils/libmodbus_src/src/modbus-tcp.h | 52 + utils/libmodbus_src/src/modbus-version.h.in | 53 + utils/libmodbus_src/src/modbus.c | 1861 + utils/libmodbus_src/src/modbus.h | 289 + utils/libmodbus_src/src/win32/Make-tests | 62 + utils/libmodbus_src/src/win32/README.win32 | 20 + utils/libmodbus_src/src/win32/config.h.win32 | 167 + utils/libmodbus_src/src/win32/configure.js | 163 + utils/libmodbus_src/src/win32/modbus-9.sln | 20 + .../src/win32/modbus.dll.manifest.in | 14 + utils/libmodbus_src/src/win32/modbus.rc | 55 + utils/libmodbus_src/src/win32/modbus.vcproj | 457 + utils/libmodbus_src/tests/LICENSE | 30 + utils/libmodbus_src/tests/Makefile.am | 52 + utils/libmodbus_src/tests/README.md | 27 + utils/libmodbus_src/tests/bandwidth-client.c | 214 + .../tests/bandwidth-server-many-up.c | 141 + .../tests/bandwidth-server-one.c | 92 + .../libmodbus_src/tests/random-test-client.c | 245 + .../libmodbus_src/tests/random-test-server.c | 60 + utils/libmodbus_src/tests/unit-test-client.c | 878 + utils/libmodbus_src/tests/unit-test-server.c | 203 + utils/libmodbus_src/tests/unit-test.h.in | 71 + utils/libmodbus_src/tests/unit-tests.sh | 19 + utils/libmodbus_src/tests/version.c | 25 + utils/matiec_src/AnnexF/average_st.txt | 18 + utils/matiec_src/AnnexF/cmd_monitor_il.txt | 37 + utils/matiec_src/AnnexF/cmd_monitor_st.txt | 25 + utils/matiec_src/AnnexF/delay_st.txt | 18 + utils/matiec_src/AnnexF/derivative_st.txt | 18 + utils/matiec_src/AnnexF/diffeq_st.txt | 30 + utils/matiec_src/AnnexF/fwd_rev_mon_il.txt | 77 + utils/matiec_src/AnnexF/fwd_rev_mon_st.txt | 53 + utils/matiec_src/AnnexF/gravel_st.txt | 129 + utils/matiec_src/AnnexF/hysteresis_st.txt | 10 + utils/matiec_src/AnnexF/integral_st.txt | 18 + utils/matiec_src/AnnexF/lag1_st.txt | 16 + utils/matiec_src/AnnexF/pid_st.txt | 25 + utils/matiec_src/AnnexF/ramp_st.txt | 25 + utils/matiec_src/AnnexF/readme | 6 + utils/matiec_src/AnnexF/stack_int_il.txt | 58 + utils/matiec_src/AnnexF/stack_int_st.txt | 31 + utils/matiec_src/AnnexF/transfer_st.txt | 25 + utils/matiec_src/AnnexF/weigh_il.txt | 18 + utils/matiec_src/AnnexF/weigh_st.txt | 12 + utils/matiec_src/COPYING | 674 + utils/matiec_src/Makefile.am | 27 + utils/matiec_src/README.build | 43 + utils/matiec_src/absyntax/Makefile.am | 8 + utils/matiec_src/absyntax/absyntax.cc | 341 + utils/matiec_src/absyntax/absyntax.def | 1290 + utils/matiec_src/absyntax/absyntax.hh | 473 + utils/matiec_src/absyntax/visitor.cc | 427 + utils/matiec_src/absyntax/visitor.hh | 208 + utils/matiec_src/absyntax_utils/Makefile.am | 29 + .../absyntax_utils/absyntax_utils.cc | 285 + .../absyntax_utils/absyntax_utils.hh | 117 + .../absyntax_utils/add_en_eno_param_decl.cc | 209 + .../absyntax_utils/add_en_eno_param_decl.hh | 109 + .../array_dimension_iterator.cc | 144 + .../array_dimension_iterator.hh | 102 + .../absyntax_utils/case_element_iterator.cc | 184 + .../absyntax_utils/case_element_iterator.hh | 125 + utils/matiec_src/absyntax_utils/debug_ast.cc | 255 + utils/matiec_src/absyntax_utils/debug_ast.hh | 73 + .../decompose_var_instance_name.cc | 183 + .../decompose_var_instance_name.hh | 140 + .../absyntax_utils/function_call_iterator.cc | 150 + .../absyntax_utils/function_call_iterator.hh | 106 + .../function_call_param_iterator.cc | 598 + .../function_call_param_iterator.hh | 363 + .../absyntax_utils/function_param_iterator.cc | 691 + .../absyntax_utils/function_param_iterator.hh | 362 + .../absyntax_utils/get_datatype_info.cc | 1456 + .../absyntax_utils/get_datatype_info.hh | 244 + .../absyntax_utils/get_sizeof_datatype.cc | 477 + .../absyntax_utils/get_sizeof_datatype.hh | 243 + .../matiec_src/absyntax_utils/get_var_name.cc | 142 + .../matiec_src/absyntax_utils/get_var_name.hh | 117 + .../absyntax_utils/search_base_type.cc | 433 + .../absyntax_utils/search_base_type.hh | 289 + .../absyntax_utils/search_fb_instance_decl.cc | 143 + .../absyntax_utils/search_fb_instance_decl.hh | 116 + .../absyntax_utils/search_fb_typedecl.cc | 69 + .../absyntax_utils/search_fb_typedecl.hh | 63 + .../absyntax_utils/search_il_label.cc | 97 + .../absyntax_utils/search_il_label.hh | 95 + .../search_var_instance_decl.cc | 643 + .../search_var_instance_decl.hh | 372 + .../search_varfb_instance_type.cc | 451 + .../search_varfb_instance_type.hh | 217 + .../absyntax_utils/spec_init_separator.cc | 269 + .../absyntax_utils/spec_init_separator.hh | 131 + .../absyntax_utils/type_initial_value.cc | 417 + .../absyntax_utils/type_initial_value.hh | 299 + .../matiec_src/bin_win32/crosscompile_w32.txt | 6 + utils/matiec_src/bin_win32/iec2c.exe | Bin 0 -> 10273422 bytes .../matiec_src/bin_win32/libgcc_s_sjlj-1.dll | Bin 0 -> 531266 bytes utils/matiec_src/bin_win32/libstdc++-6.dll | Bin 0 -> 11510933 bytes utils/matiec_src/common.mk | 3 + utils/matiec_src/config/INSTALL | 365 + utils/matiec_src/config/aclocal.m4 | 8917 ++ utils/matiec_src/config/depcomp | 584 + utils/matiec_src/config/install-sh | 507 + utils/matiec_src/config/libtool.m4 | 7377 + utils/matiec_src/config/ltmain.sh | 8413 ++ utils/matiec_src/config/ltoptions.m4 | 368 + utils/matiec_src/config/ltsugar.m4 | 123 + utils/matiec_src/config/ltversion.m4 | 23 + utils/matiec_src/config/lt~obsolete.m4 | 92 + utils/matiec_src/config/missing | 367 + utils/matiec_src/config/ylwrap | 223 + utils/matiec_src/configure.ac | 79 + utils/matiec_src/debian/README.Debian | 6 + utils/matiec_src/debian/changelog | 6 + utils/matiec_src/debian/compat | 1 + utils/matiec_src/debian/control | 12 + utils/matiec_src/debian/copyright | 35 + utils/matiec_src/debian/dirs | 1 + utils/matiec_src/debian/postinst | 43 + utils/matiec_src/debian/postrm | 31 + utils/matiec_src/debian/rules | 89 + utils/matiec_src/lib/C/accessor.h | 136 + utils/matiec_src/lib/C/iec_std_FB.h | 1905 + utils/matiec_src/lib/C/iec_std_FB_no_ENENO.h | 1548 + utils/matiec_src/lib/C/iec_std_functions.h | 1589 + utils/matiec_src/lib/C/iec_std_lib.h | 756 + utils/matiec_src/lib/C/iec_types.h | 83 + utils/matiec_src/lib/C/iec_types_all.h | 183 + utils/matiec_src/lib/COPYING.LESSER | 165 + utils/matiec_src/lib/bistable.txt | 84 + utils/matiec_src/lib/counter.txt | 460 + .../lib/create_standard_function_txt.sh | 916 + utils/matiec_src/lib/derivative_st.txt | 30 + utils/matiec_src/lib/edge_detection.txt | 35 + utils/matiec_src/lib/hysteresis_st.txt | 21 + utils/matiec_src/lib/ieclib.txt | 32 + utils/matiec_src/lib/integral_st.txt | 28 + utils/matiec_src/lib/pid_st.txt | 35 + utils/matiec_src/lib/ramp_st.txt | 35 + utils/matiec_src/lib/rtc.txt | 51 + utils/matiec_src/lib/sema.txt | 25 + utils/matiec_src/lib/standard_FB.txt | 48 + utils/matiec_src/lib/standard_functions.txt | 1853 + utils/matiec_src/lib/test_iec_std_lib.c | 33 + utils/matiec_src/lib/timer.txt | 290 + utils/matiec_src/main.cc | 264 + utils/matiec_src/main.hh | 163 + utils/matiec_src/readme | 533 + utils/matiec_src/stage1_2/.cvsignore | 5 + utils/matiec_src/stage1_2/Makefile.am | 26 + .../create_enumtype_conversion_functions.cc | 328 + .../create_enumtype_conversion_functions.hh | 82 + utils/matiec_src/stage1_2/iec_bison.yy | 8848 ++ utils/matiec_src/stage1_2/iec_flex.ll | 2132 + utils/matiec_src/stage1_2/stage1_2.cc | 251 + utils/matiec_src/stage1_2/stage1_2.hh | 54 + utils/matiec_src/stage1_2/stage1_2_priv.hh | 260 + .../stage1_2/standard_function_names.c | 464 + utils/matiec_src/stage3/Makefile.am | 20 + utils/matiec_src/stage3/TODO | 13 + utils/matiec_src/stage3/array_range_check.cc | 348 + utils/matiec_src/stage3/array_range_check.hh | 101 + .../matiec_src/stage3/case_elements_check.cc | 249 + .../matiec_src/stage3/case_elements_check.hh | 85 + utils/matiec_src/stage3/constant_folding.cc | 2114 + utils/matiec_src/stage3/constant_folding.hh | 337 + utils/matiec_src/stage3/datatype_functions.cc | 453 + utils/matiec_src/stage3/datatype_functions.hh | 101 + utils/matiec_src/stage3/declaration_check.cc | 320 + utils/matiec_src/stage3/declaration_check.hh | 65 + .../stage3/enum_declaration_check.cc | 254 + .../stage3/enum_declaration_check.hh | 81 + .../stage3/fill_candidate_datatypes.cc | 2325 + .../stage3/fill_candidate_datatypes.hh | 424 + .../stage3/flow_control_analysis.cc | 402 + .../stage3/flow_control_analysis.hh | 166 + .../forced_narrow_candidate_datatypes.cc | 259 + .../forced_narrow_candidate_datatypes.hh | 91 + utils/matiec_src/stage3/lvalue_check.cc | 588 + utils/matiec_src/stage3/lvalue_check.hh | 142 + .../stage3/narrow_candidate_datatypes.cc | 1815 + .../stage3/narrow_candidate_datatypes.hh | 392 + .../stage3/print_datatypes_error.cc | 1292 + .../stage3/print_datatypes_error.hh | 348 + .../stage3/remove_forward_dependencies.cc | 303 + .../stage3/remove_forward_dependencies.hh | 114 + utils/matiec_src/stage3/stage3.cc | 175 + utils/matiec_src/stage3/stage3.hh | 41 + utils/matiec_src/stage4/Makefile.am | 6 + utils/matiec_src/stage4/generate_c/.cvsignore | 2 + .../matiec_src/stage4/generate_c/Makefile.am | 10 + .../stage4/generate_c/generate_c.cc | 2352 + .../stage4/generate_c/generate_c.hh | 64 + .../stage4/generate_c/generate_c_base.cc | 1040 + .../generate_c/generate_c_configbody.cc | 182 + .../stage4/generate_c/generate_c_il.cc | 1843 + .../generate_c/generate_c_inlinefcall.cc | 927 + .../stage4/generate_c/generate_c_sfc.cc | 1014 + .../stage4/generate_c/generate_c_sfcdecl.cc | 410 + .../stage4/generate_c/generate_c_st.cc | 1322 + .../stage4/generate_c/generate_c_typedecl.cc | 1171 + .../stage4/generate_c/generate_c_vardecl.cc | 2772 + .../generate_c/generate_location_list.cc | 154 + .../stage4/generate_c/generate_var_list.cc | 1084 + utils/matiec_src/stage4/generate_c/plc.h | 85 + utils/matiec_src/stage4/generate_c/types.h | 73 + .../matiec_src/stage4/generate_cc/.cvsignore | 1 + .../matiec_src/stage4/generate_iec/.cvsignore | 1 + .../stage4/generate_iec/Makefile.am | 10 + .../stage4/generate_iec/generate_iec.cc | 2180 + .../stage4/generate_iec/generate_iec.hh | 63 + utils/matiec_src/stage4/stage4.cc | 255 + utils/matiec_src/stage4/stage4.hh | 111 + utils/matiec_src/tests/.cvsignore | 11 + utils/matiec_src/tests/LD_TEST.xml | 81 + utils/matiec_src/tests/SFC_TEST.xml | 791 + utils/matiec_src/tests/STD_TEST.xml | 4802 + utils/matiec_src/tests/build.sh | 41 + utils/matiec_src/tests/build_win32.sh | 41 + utils/matiec_src/tests/main.c | 151 + utils/matiec_src/tests/plc.c | 82 + .../syntax/configuration/configuration.txt | 67 + .../syntax/enumeration/enumerationvalue.txt | 41 + .../tests/syntax/identifier/Makefile | 32 + .../tests/syntax/identifier/basic_code.test | 685 + .../tests/syntax/identifier/identifier.txt | 57 + .../identifier_as_configuration.test | 48 + .../identifier/identifier_as_datatype.test | 46 + .../identifier_as_enumerationvalue.test | 60 + .../identifier/identifier_as_function1.test | 164 + .../identifier/identifier_as_function2.test | 149 + .../identifier_as_functionblock.test | 103 + .../identifier/identifier_as_label.test | 65 + .../identifier/identifier_as_program.test | 66 + .../identifier/identifier_as_variable1.test | 398 + .../identifier/identifier_as_variable2.test | 303 + .../syntax/identifier/identifier_in_sfc.test | 611 + .../tests/syntax/identifier/runtests | 30 + utils/matiec_src/tests/syntax/sfc/sfc.txt | 164 + utils/matiec_src/util/dsymtable.cc | 115 + utils/matiec_src/util/dsymtable.hh | 129 + utils/matiec_src/util/strdup.hh | 58 + utils/matiec_src/util/symtable.cc | 214 + utils/matiec_src/util/symtable.hh | 137 + utils/st_optimizer_src/st_optimizer.cpp | 214 + webserver/active_program | 1 + webserver/core/custom_layer.cpp | 66 + webserver/core/custom_layer.original | 66 + webserver/core/dnp3.cpp | 435 + webserver/core/dnp3_dummy.disabled | 6 + webserver/core/glueVars.cpp | 72 + webserver/core/hardware_layer.cpp | 86 + webserver/core/hardware_layers/blank.cpp | 86 + .../core/hardware_layers/fischertechnik.cpp | 232 + webserver/core/hardware_layers/pixtend.cpp | 900 + webserver/core/hardware_layers/pixtend2s.cpp | 719 + .../core/hardware_layers/raspberrypi.cpp | 140 + .../core/hardware_layers/raspberrypi_old.cpp | 140 + webserver/core/hardware_layers/simulink.cpp | 188 + webserver/core/hardware_layers/unipi.cpp | 236 + webserver/core/interactive_server.cpp | 413 + webserver/core/ladder.h | 135 + webserver/core/lib/accessor.h | 136 + webserver/core/lib/iec_std_FB.h | 1894 + webserver/core/lib/iec_std_functions.h | 1577 + webserver/core/lib/iec_std_lib.h | 742 + webserver/core/lib/iec_types.h | 83 + webserver/core/lib/iec_types_all.h | 183 + webserver/core/main.cpp | 238 + webserver/core/modbus.cpp | 889 + webserver/core/server.cpp | 264 + webserver/dnp3.cfg | 61 + webserver/lib/COPYING.LESSER | 165 + webserver/lib/bistable.txt | 84 + webserver/lib/counter.txt | 460 + webserver/lib/create_standard_function_txt.sh | 916 + webserver/lib/derivative_st.txt | 30 + webserver/lib/edge_detection.txt | 35 + webserver/lib/hysteresis_st.txt | 21 + webserver/lib/ieclib.txt | 32 + webserver/lib/integral_st.txt | 28 + webserver/lib/pid_st.txt | 35 + webserver/lib/ramp_st.txt | 35 + webserver/lib/rtc.txt | 51 + webserver/lib/sema.txt | 25 + webserver/lib/standard_FB.txt | 48 + webserver/lib/standard_functions.txt | 1853 + webserver/lib/test_iec_std_lib.c | 33 + webserver/lib/timer.txt | 290 + webserver/openplc.db | Bin 0 -> 28672 bytes webserver/openplc.py | 206 + webserver/pages.py | 1112 + webserver/scripts/change_hardware_layer.sh | 85 + webserver/scripts/compile_program.sh | 120 + webserver/scripts/openplc_driver | 1 + webserver/scripts/openplc_platform | 1 + webserver/scripts/start_openplc.sh | 3 + webserver/st_files/blank_program.st | 17 + webserver/static/arrow.png | Bin 0 -> 348 bytes webserver/static/bool_false.png | Bin 0 -> 2357 bytes webserver/static/bool_true.png | Bin 0 -> 2350 bytes webserver/static/codemirror/active-line.js | 72 + webserver/static/codemirror/codemirror.css | 346 + webserver/static/codemirror/codemirror.js | 9685 ++ webserver/static/codemirror/javascript.js | 896 + webserver/static/codemirror/liquibyte.css | 95 + webserver/static/codemirror/matchbrackets.js | 145 + webserver/static/communication-icon-64x64.png | Bin 0 -> 1473 bytes webserver/static/default-user.png | Bin 0 -> 45226 bytes webserver/static/hardware-icon-980x974.png | Bin 0 -> 5030 bytes webserver/static/home-icon-64x64.png | Bin 0 -> 524 bytes webserver/static/logout-icon-64x64.png | Bin 0 -> 1230 bytes webserver/static/modbus-icon-512x512.png | Bin 0 -> 26793 bytes webserver/static/monitoring-icon-64x64.png | Bin 0 -> 738 bytes webserver/static/openplc_logo.gif | Bin 0 -> 22697 bytes webserver/static/programs-icon-64x64.png | Bin 0 -> 978 bytes webserver/static/settings-icon-64x64.png | Bin 0 -> 783 bytes webserver/static/users-icon-64x64.png | Bin 0 -> 1128 bytes webserver/webserver.py | 1300 + 2742 files changed, 568737 insertions(+), 2 deletions(-) create mode 100755 install.sh create mode 100644 utils/apt-cyg/apt-cyg create mode 100755 utils/apt-cyg/wget.exe create mode 100644 utils/dnp3_src/CHANGELOG.markdown create mode 100644 utils/dnp3_src/CMakeLists.txt create mode 100644 utils/dnp3_src/NOTICE create mode 100755 utils/dnp3_src/README.md create mode 100644 utils/dnp3_src/appveyor.yml create mode 100644 utils/dnp3_src/build-dotnet.bat create mode 100644 utils/dnp3_src/cmake/inc/msvc.cmake create mode 100644 utils/dnp3_src/cmake/inc/posix.cmake create mode 100644 utils/dnp3_src/cmake/settings.cmake create mode 100644 utils/dnp3_src/config/APACHE_LICENSE_HEADER create mode 100755 utils/dnp3_src/config/astyle.cfg create mode 100644 utils/dnp3_src/config/doxygen.config create mode 100644 utils/dnp3_src/config/doxygen_files/img/opendnp3.png create mode 100644 utils/dnp3_src/config/doxygen_files/mainpage.dox create mode 100644 utils/dnp3_src/config/formatHeaders.xml create mode 100644 utils/dnp3_src/config/gecapache.licenseheader create mode 100644 utils/dnp3_src/config/src-footer.inc create mode 100644 utils/dnp3_src/config/src-header.inc create mode 100644 utils/dnp3_src/cpp/examples/decoder/main.cpp create mode 100644 utils/dnp3_src/cpp/examples/master-gprs/main.cpp create mode 100644 utils/dnp3_src/cpp/examples/master/main.cpp create mode 100644 utils/dnp3_src/cpp/examples/outstation/main.cpp create mode 100644 utils/dnp3_src/cpp/examples/tls/master-gprs/main.cpp create mode 100644 utils/dnp3_src/cpp/examples/tls/master/main.cpp create mode 100644 utils/dnp3_src/cpp/examples/tls/outstation/main.cpp create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/ConsoleLogger.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/DNP3Manager.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/DatabaseConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultListenCallbacks.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultMasterApplication.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/ErrorCodes.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IChannel.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IChannelListener.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IListenCallbacks.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IMaster.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterOperations.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterScan.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterSession.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IOutstation.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/ISessionAcceptor.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/IStack.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/MasterStackConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/MasterTCPServer.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/OutstationStackConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingChannelListener.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingCommandCallback.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingSOEHandler.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/UpdateBuilder.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/Updates.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiodnp3/X509Info.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/ASIOSerialHelpers.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/ChannelRetry.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/Executor.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IAsyncChannel.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IChannelCallbacks.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IListener.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IO.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IOpenDelayStrategy.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IPEndpoint.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/IResourceManager.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/LoggingConnectionCondition.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/ResourceManager.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/SerialChannel.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/SerialTypes.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/SocketChannel.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/SocketHelpers.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/SteadyClock.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/Synchronized.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/TCPClient.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/TCPServer.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/TLSConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/ThreadPool.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/TimeConversions.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/Timer.h create mode 100644 utils/dnp3_src/cpp/libs/include/asiopal/UTCTimeSource.h create mode 100644 utils/dnp3_src/cpp/libs/include/dnp3decode/Decoder.h create mode 100644 utils/dnp3_src/cpp/libs/include/dnp3decode/IDecoderCallbacks.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/LogLevels.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/StackStatistics.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogCommandEvent.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogOutput.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/AppConstants.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/BaseMeasurementTypes.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/BinaryCommandEvent.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/ClassField.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/ControlRelayOutputBlock.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/DNPTime.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/EventCells.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/EventTriggers.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/EventType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/Flags.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/GroupVariationID.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/IINField.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/ITransactable.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/Indexed.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementInfo.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypeSpecs.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypes.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetData.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetString.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/QualityMasks.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/SecurityStat.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/app/parsing/ICollection.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogOutputStatusQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/AssignClassType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/Attributes.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/AuthErrorCode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryOutputStatusQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/CertificateType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChallengeReason.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChannelState.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandPointState.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandStatus.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/ConfigAuthMode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/ControlCode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/CounterQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBit.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBitBinaryQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogOutputStatusVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryOutputStatusVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventCounterVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventDoubleBinaryVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventFrozenCounterVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventMode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventSecurityStatVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlagsType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlowControl.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/FrozenCounterQuality.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/FunctionCode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/GroupVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/HMACType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/IndexMode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/IntervalUnits.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyChangeMethod.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyStatus.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyWrapAlgorithm.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkFunction.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkStatus.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/MasterTaskType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/OperateType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/Parity.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/PointClass.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/QualifierCode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartMode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartType.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/SecurityStatIndex.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogOutputStatusVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryOutputStatusVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticCounterVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticDoubleBinaryVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticFrozenCounterVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticSecurityStatVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTimeAndIntervalVariation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTypeBitmask.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/StopBits.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/TaskCompletion.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimeSyncMode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimestampMode.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserOperation.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserRole.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/link/ILinkListener.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkHeaderFields.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkStatistics.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandCallbackT.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandPointResult.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandSet.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderInfo.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderTypes.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandCollection.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandProcessor.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandTaskResult.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/IMasterApplication.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/ISOEHandler.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/ITaskCallback.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/MasterParams.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/RestartOperationResult.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskId.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskInfo.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ApplicationIIN.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/Cell.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/DatabaseSizes.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/EventBufferConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ICommandHandler.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IOutstationApplication.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IUpdateHandler.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/MeasurementConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationConfig.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationParams.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/SimpleCommandHandler.h create mode 100644 utils/dnp3_src/cpp/libs/include/opendnp3/outstation/StaticTypeBitfield.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/Configure.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayerCallbacks.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/Array.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/ArrayView.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/Buffer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/HasSize.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/LinkedList.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/Pair.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/Queue.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/RSlice.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/RingBuffer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/SecureBuffer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/Settable.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/StaticBuffer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/container/WSlice.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/IExecutor.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/IMonotonicTimeSource.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/ITimer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/IUTCTimeSource.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/MonotonicTimestamp.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/TimeDuration.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/TimerRef.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/executor/UTCTimestamp.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/ILogHandler.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/Location.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/LogEntry.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/LogFilters.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/LogLevels.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/LogMacros.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/Logger.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/logging/StringFormatting.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/ByteSerialization.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/DoubleFloat.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/FloatByteOrder.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/Format.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/Parse.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/Serialization.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/SerializationTemplatesLE.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/Serializer.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/SingleFloat.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48LE.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48Type.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/util/Comparisons.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/util/Finally.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/util/Limits.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/util/SequenceNum.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/util/ToHex.h create mode 100644 utils/dnp3_src/cpp/libs/include/openpal/util/Uncopyable.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/ConsoleLogger.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Manager.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultListenCallbacks.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultMasterApplication.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/ErrorCodes.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/MasterTCPServer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingCommandCallback.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingSOEHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/StackBase.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/UpdateBuilder.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/ASIOSerialHelpers.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/ChannelRetry.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/Executor.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/IOpenDelayStrategy.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/ResourceManager.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/SerialChannel.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/SocketChannel.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/TCPClient.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/TCPServer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/ThreadPool.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/TimeConversions.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/Timer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/UTCTimeSource.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSContext.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.h create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.h create mode 100644 utils/dnp3_src/cpp/libs/src/dnp3decode/Decoder.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.h create mode 100644 utils/dnp3_src/cpp/libs/src/dnp3decode/Indent.h create mode 100644 utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/LayerInterfaces.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/LogLevels.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/Route.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogCommandEvent.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogOutput.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/AppSeqNum.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/BinaryCommandEvent.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/BitfieldRangeWriteIterator.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/ClassField.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/ControlRelayOutputBlock.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/CountWriteIterator.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/DNP3Serializer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/DownSampling.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/EventTriggers.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/IINField.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/IINValue.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/IVariableLength.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementFactory.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementTypes.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/OctetData.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/PrefixedWriteIterator.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/Range.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/RangeWriteIterator.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/SecurityStat.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/SequenceInfo.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/TxBuffer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversionTemplates.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversions.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BufferedCollection.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Collections.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Functions.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IWhiteList.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParseResult.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParserSettings.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/PrefixFields.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/Attributes.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/AuthErrorCode.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/CertificateType.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChallengeReason.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChannelState.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandPointState.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandStatus.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/ControlCode.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/DoubleBit.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlagsType.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlowControl.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/FunctionCode.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/GroupVariation.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/HMACType.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/IntervalUnits.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyChangeMethod.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyStatus.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyWrapAlgorithm.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkFunction.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkStatus.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/MasterTaskType.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/Parity.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/QualifierCode.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/StopBits.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/TaskCompletion.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserOperation.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserRole.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/IFrameSink.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkLayer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkSession.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkTx.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/ITransportSegment.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeaderFields.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerConstants.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/link/Singleton.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSet.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderBuilder.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderTypes.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ICommandHeader.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/IScheduleCallback.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskFilter.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/ScanResult.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskPriority.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/TimeSyncHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/TypedCommandHeader.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group110.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group111.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group112.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group113.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group60.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group70.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group80.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ApplicationIIN.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ConstantCommandAction.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ControlState.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Event.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBufferConfig.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IClassAssigner.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ICommandAction.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IDatabase.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventReceiver.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventRecorder.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventSelector.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IOutstationApplication.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IResponseLoader.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IStaticSelector.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IndexSearch.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationChannelStates.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationSeqNum.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SimpleCommandHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportConstants.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportSeqNum.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.h create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.h create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/container/Buffer.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/container/RSlice.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/container/WSlice.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/executor/MonotonicTimestamp.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/executor/TimeDuration.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/executor/TimerRef.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/logging/Logger.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/logging/StringFormatting.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/ByteSerialization.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/DoubleFloat.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/FloatByteOrder.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/Format.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/Parse.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/SingleFloat.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/serialization/UInt48LE.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/util/Limits.cpp create mode 100644 utils/dnp3_src/cpp/libs/src/openpal/util/ToHex.cpp create mode 100644 utils/dnp3_src/cpp/tests/afl-fuzzer/main.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/CatchTestStart.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/TestDNP3Manager.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/TestEventIntegration.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/TestMasterServerSmoke.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/TestPerfomance.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/CountingSOEHandler.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/ExpectedValue.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuedChannelListener.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuingSOEHandler.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/SynchronizedQueue.h create mode 100644 utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/TestTypedefs.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/CatchTestStart.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/TestASIO.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/TestStrandExecutor.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/TestTCPClientServer.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPServer.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/tls/TestTLSClientServer.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSClientHandler.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.cpp create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSServer.h create mode 100644 utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_cert.pem create mode 100644 utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_key.pem create mode 100644 utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_cert.pem create mode 100644 utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_key.pem create mode 100644 utils/dnp3_src/cpp/tests/libs/src/catch.hpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CallbackQueue.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CommandCallbackQueue.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockCommandHandler.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLinkListener.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockMasterApplication.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockOutstationApplication.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockSOEHandler.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockTaskCallback.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/MockUTCTimeSource.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/Random.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/RandomDouble.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.h create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.cpp create mode 100644 utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/CatchTestStart.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUParsing.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUWriting.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestAuthRequestParser.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestCRC.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestCastLongLongDouble.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestCollectionTransform.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestDatabase.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var1.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var2.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var5.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestIndexSearch.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkFrame.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayer.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayerKeepAlive.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkReceiver.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkRoute.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestLog.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMaster.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterAssignClass.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterCommandRequests.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultiCommandRequests.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultidrop.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterUnsolBehaviors.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestMeasurementHandler.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstation.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationAssignClass.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationCommandResponses.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationEventResponses.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationStateMachine.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationUnsolicitedResponses.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestShiftableBuffer.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestTransportLayer.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestTypedCommandHeader.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestTypes.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestUtil.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/TestWriteConversions.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DatabaseTestObject.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/FanoutDataObserver.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkReceiverTest.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MeasurementComparisons.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockAPDUHeaderHandler.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockLinkLayer.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TestHelpers.h create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.cpp create mode 100644 utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.h create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/CatchTestStart.cpp create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/LinkedListTestSuite.cpp create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/QueueTestSuite.cpp create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/TestFloatSerialization.cpp create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/TestIntegerSerialization.cpp create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/TestStaticBuffer.cpp create mode 100644 utils/dnp3_src/cpp/tests/openpal/src/TestTime.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/COPYING create mode 100644 utils/dnp3_src/deps/asio/asio/INSTALL create mode 100644 utils/dnp3_src/deps/asio/asio/LICENSE_1_0.txt create mode 100644 utils/dnp3_src/deps/asio/asio/Makefile.am create mode 100644 utils/dnp3_src/deps/asio/asio/README create mode 100644 utils/dnp3_src/deps/asio/asio/asio.manifest create mode 100755 utils/dnp3_src/deps/asio/asio/autogen.sh create mode 100644 utils/dnp3_src/deps/asio/asio/boost_asio.manifest create mode 100755 utils/dnp3_src/deps/asio/asio/boostify.pl create mode 100644 utils/dnp3_src/deps/asio/asio/configure.ac create mode 100644 utils/dnp3_src/deps/asio/asio/include/Makefile.am create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/async_result.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_datagram_socket.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_deadline_timer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_io_object.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_raw_socket.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_seq_packet_socket.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_serial_port.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_signal_set.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_socket.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_acceptor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_iostream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_streambuf.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_stream_socket.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_streambuf.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_streambuf_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/basic_waitable_timer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffered_read_stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffered_read_stream_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffered_stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffered_stream_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffered_write_stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffered_write_stream_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/buffers_iterator.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/completion_condition.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/connect.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/coroutine.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/datagram_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/deadline_timer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/deadline_timer_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/addressof.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/array.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/array_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/assert.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/atomic_count.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/base_from_completion_cond.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/bind_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/buffer_resize_guard.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/buffer_sequence_adapter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/buffered_stream_storage.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/call_stack.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/chrono_time_traits.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/completion_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/config.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/consuming_buffers.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/cstdint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/date_time_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/deadline_timer_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/dependent_type.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/descriptor_ops.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/descriptor_read_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/descriptor_write_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/dev_poll_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/epoll_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/event.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/eventfd_select_interrupter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/fd_set_adapter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/function.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/gcc_arm_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/gcc_hppa_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/gcc_sync_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/gcc_x86_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/handler_alloc_helpers.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/handler_cont_helpers.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/handler_invoke_helpers.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/handler_tracking.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/handler_type_requirements.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/hash_map.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/descriptor_ops.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/dev_poll_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/dev_poll_reactor.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/epoll_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/epoll_reactor.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/handler_tracking.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/kqueue_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/kqueue_reactor.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/pipe_select_interrupter.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/posix_event.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/posix_mutex.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/posix_thread.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/posix_tss_ptr.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/reactive_descriptor_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/reactive_serial_port_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/reactive_socket_service_base.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/resolver_service_base.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/select_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/select_reactor.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/service_registry.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/service_registry.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/signal_set_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/socket_ops.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/socket_select_interrupter.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/strand_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/strand_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/task_io_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/task_io_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/throw_error.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/timer_queue_ptime.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/timer_queue_set.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_event.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_iocp_handle_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_iocp_io_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_iocp_io_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_mutex.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_object_handle_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_static_mutex.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_thread.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/win_tss_ptr.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/impl/winsock_init.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/io_control.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/keyword_tss_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/kqueue_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/limits.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/local_free_on_block_exit.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/macos_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/noncopyable.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_event.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_signal_blocker.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_static_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/null_tss_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/object_pool.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/old_win_sdk_compat.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/op_queue.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/operation.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/pipe_select_interrupter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/pop_options.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_event.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_fd_set_adapter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_signal_blocker.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_static_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/posix_tss_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/push_options.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_descriptor_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_null_buffers_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_serial_port_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_accept_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_connect_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_recv_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_send_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_sendto_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactive_socket_service_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactor_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactor_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/reactor_op_queue.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/regex_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/resolve_endpoint_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/resolve_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/resolver_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/resolver_service_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/scoped_lock.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/scoped_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/select_interrupter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/select_reactor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/service_registry.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/shared_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/signal_blocker.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/signal_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/signal_init.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/signal_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/signal_set_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/socket_holder.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/socket_ops.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/socket_option.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/socket_select_interrupter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/socket_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/solaris_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/static_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/std_event.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/std_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/std_static_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/std_thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/strand_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/task_io_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/task_io_service_operation.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/task_io_service_thread_info.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/thread_info_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/throw_error.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/throw_exception.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/timer_queue.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/timer_queue_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/timer_queue_ptime.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/timer_queue_set.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/timer_scheduler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/timer_scheduler_fwd.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/tss_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/type_traits.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/variadic_templates.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/wait_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/wait_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/weak_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_event.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_fd_set_adapter.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_fenced_block.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_handle_read_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_handle_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_handle_write_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_io_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_null_buffers_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_operation.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_overlapped_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_serial_port_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_accept_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_connect_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_recv_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_send_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_socket_service_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_iocp_thread_info.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_object_handle_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_static_mutex.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/win_tss_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winapi_thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_async_manager.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_async_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_resolve_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_resolver_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_socket_connect_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_socket_recv_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_socket_send_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_ssocket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_ssocket_service_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_timer_scheduler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winrt_utils.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/winsock_init.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/detail/wrapped_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/error.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/error_code.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/basic_endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/datagram_protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/detail/endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/detail/impl/endpoint.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/raw_protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/seq_packet_protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/generic/stream_protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/handler_alloc_hook.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/handler_continuation_hook.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/handler_invoke_hook.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/handler_type.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/high_resolution_timer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/buffered_read_stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/buffered_write_stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/connect.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/error.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/error_code.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/handler_alloc_hook.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/io_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/io_service.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/read.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/read_at.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/read_until.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/serial_port_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/serial_port_base.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/spawn.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/src.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/src.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/use_future.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/write.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/impl/write_at.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/io_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/address.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/address_v4.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/address_v6.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/basic_endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/basic_resolver.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/basic_resolver_entry.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/basic_resolver_iterator.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/basic_resolver_query.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/detail/endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/detail/impl/endpoint.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/detail/socket_option.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/host_name.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/icmp.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/address.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/address.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/address_v4.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/address_v4.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/address_v6.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/address_v6.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/basic_endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/impl/host_name.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/multicast.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/resolver_query_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/resolver_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/tcp.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/udp.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/unicast.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ip/v6_only.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/is_read_buffered.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/is_write_buffered.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/local/basic_endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/local/connect_pair.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/local/datagram_protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/local/detail/endpoint.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/local/detail/impl/endpoint.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/local/stream_protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/placeholders.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/posix/basic_descriptor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/posix/basic_stream_descriptor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/posix/descriptor_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/posix/stream_descriptor.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/posix/stream_descriptor_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/raw_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/read.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/read_at.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/read_until.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/seq_packet_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/serial_port.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/serial_port_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/serial_port_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/signal_set.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/signal_set_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/socket_acceptor_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/socket_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/spawn.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/basic_context.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/context.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/context_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/context_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/buffered_handshake_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/engine.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/handshake_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/impl/engine.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/impl/openssl_init.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/io.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/openssl_init.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/openssl_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/password_callback.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/read_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/shutdown_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/stream_core.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/verify_callback.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/detail/write_op.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/error.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/impl/context.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/impl/context.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/impl/error.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/impl/rfc2818_verification.ipp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/impl/src.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/basic_context.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/context_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/detail/openssl_context_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/detail/openssl_operation.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/detail/openssl_stream_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/old/stream_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/rfc2818_verification.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/stream.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/stream_base.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/stream_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/verify_context.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/ssl/verify_mode.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/steady_timer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/strand.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/stream_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/streambuf.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/system_error.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/system_timer.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/thread.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/time_traits.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/unyield.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/use_future.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/version.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/wait_traits.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/waitable_timer_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/basic_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/basic_object_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/basic_random_access_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/basic_stream_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/object_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/object_handle_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/overlapped_ptr.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/random_access_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/random_access_handle_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/stream_handle.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/windows/stream_handle_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/write.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/write_at.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/include/asio/yield.hpp create mode 100755 utils/dnp3_src/deps/asio/asio/release.pl create mode 100644 utils/dnp3_src/deps/asio/asio/src/Makefile.am create mode 100644 utils/dnp3_src/deps/asio/asio/src/Makefile.mgw create mode 100644 utils/dnp3_src/deps/asio/asio/src/Makefile.msc create mode 100644 utils/dnp3_src/deps/asio/asio/src/asio.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/asio_ssl.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/Jamfile.v2 create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/asio.png create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/asio.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/asioref.sty create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/asioref.xsl create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/boost_bind_dox.txt create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/doxy2qbk.pl create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/examples.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/history.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/index.xml create mode 100755 utils/dnp3_src/deps/asio/asio/src/doc/makepdf.pl create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/noncopyable_dox.txt create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/allocation.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/async.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/async_op1.dot create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/async_op1.png create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/async_op2.dot create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/async_op2.png create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/basics.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/bsd_sockets.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/buffers.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/coroutine.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/cpp2011.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/handler_tracking.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/implementation.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/iostreams.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/line_based.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/other_protocols.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/posix.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/proactor.dot create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/proactor.png create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/protocols.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/rationale.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/reactor.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/serial_ports.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/signals.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/spawn.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/ssl.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/strands.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/streams.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/sync_op.dot create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/sync_op.png create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/threads.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/timers.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/overview/windows.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/project-root.jam create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/quickref.xml create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/reference.dox create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/reference.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/reference.xsl create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/release_checklist.htm create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/AcceptHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/AsyncRandomAccessReadDevice.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/AsyncRandomAccessWriteDevice.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/AsyncReadStream.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/AsyncWriteStream.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/BufferedHandshakeHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/CompletionHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ComposedConnectHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ConnectHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ConstBufferSequence.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ConvertibleToConstBuffer.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ConvertibleToMutableBuffer.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/DatagramSocketService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/DescriptorService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/Endpoint.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/GettableSerialPortOption.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/GettableSocketOption.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/HandleService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/Handler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/HandshakeHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/InternetProtocol.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/IoControlCommand.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/IoObjectService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/MutableBufferSequence.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ObjectHandleService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/Protocol.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/RandomAccessHandleService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/RawSocketService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ReadHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ResolveHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ResolverService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SeqPacketSocketService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SerialPortService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/Service.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SettableSerialPortOption.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SettableSocketOption.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/ShutdownHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SignalHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SignalSetService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SocketAcceptorService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SocketService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/StreamDescriptorService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/StreamHandleService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/StreamSocketService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SyncRandomAccessReadDevice.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SyncRandomAccessWriteDevice.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SyncReadStream.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/SyncWriteStream.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/TimeTraits.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/TimerService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/WaitHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/WaitTraits.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/WaitableTimerService.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/WriteHandler.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/requirements/asynchronous_operations.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/std_exception_dox.txt create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/tutorial.dox create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/tutorial.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/tutorial.xsl create mode 100644 utils/dnp3_src/deps/asio/asio/src/doc/using.qbk create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/Makefile.am create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/allocation/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/buffers/reference_counted.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/chat/chat_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/chat/chat_message.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/chat/chat_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/chat/posix_chat_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/echo/async_tcp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/echo/async_udp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/echo/blocking_tcp_echo_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/echo/blocking_tcp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/echo/blocking_udp_echo_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/echo/blocking_udp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/fork/daemon.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/fork/process_per_connection.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/client/async_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/client/sync_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/doc_root/data_1K.html create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/doc_root/data_2K.html create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/doc_root/data_4K.html create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/doc_root/data_8K.html create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/connection.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/connection.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/connection_manager.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/connection_manager.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/main.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/mime_types.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/mime_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/reply.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/reply.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/request.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/request_handler.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/request_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/request_parser.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/request_parser.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server/server.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/connection.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/connection.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/io_service_pool.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/io_service_pool.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/main.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/mime_types.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/mime_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/reply.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/reply.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/request.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/request_handler.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/request_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/request_parser.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/request_parser.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server2/server.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/connection.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/connection.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/main.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/mime_types.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/mime_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/reply.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/reply.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/request.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/request_handler.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/request_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/request_parser.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/request_parser.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server3/server.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/file_handler.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/file_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/main.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/mime_types.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/mime_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/reply.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/reply.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/request.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/request_parser.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/request_parser.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/http/server4/server.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/icmp/icmp_header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/icmp/ipv4_header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/icmp/ping.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/invocation/prioritised_handlers.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/iostreams/daytime_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/iostreams/daytime_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/iostreams/http_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/local/connect_pair.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/local/iostream_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/local/stream_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/local/stream_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/multicast/receiver.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/multicast/sender.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/nonblocking/third_party_lib.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/porthopper/client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/porthopper/protocol.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/porthopper/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/serialization/client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/serialization/connection.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/serialization/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/serialization/stock.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/services/basic_logger.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/services/daytime_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/services/logger.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/services/logger_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/services/logger_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/services/stream_socket_service.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/socks4/socks4.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/socks4/sync_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/spawn/echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/ssl/README create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/ssl/ca.pem create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/ssl/client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/ssl/dh2048.pem create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/ssl/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/ssl/server.pem create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/timeouts/async_tcp_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/timeouts/blocking_tcp_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/timeouts/blocking_udp_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/timeouts/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/timers/tick_count_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/timers/time_t_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime1/client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime2/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime3/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime4/client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime5/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime6/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime7/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/daytime_dox.txt create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/index_dox.txt create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/timer1/timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/timer2/timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/timer3/timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/timer4/timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/timer5/timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/tutorial/timer_dox.txt create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp03/windows/transmit_file.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/Makefile.am create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/allocation/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/buffers/reference_counted.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/chat/chat_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/chat/chat_message.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/chat/chat_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/echo/async_udp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/echo/blocking_tcp_echo_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/echo/blocking_udp_echo_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/echo/blocking_udp_echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/futures/daytime_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/connection.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/connection.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/connection_manager.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/connection_manager.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/header.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/main.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/mime_types.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/mime_types.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/reply.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/reply.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/request.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/request_handler.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/request_handler.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/request_parser.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/request_parser.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/http/server/server.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/examples/cpp11/spawn/echo_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/Makefile.am create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/allocator.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/coroutine.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/high_res_clock.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/tcp_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/tcp_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/udp_client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/udp_server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/unyield.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/latency/yield.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/performance/client.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/performance/handler_allocator.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/performance/server.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/archetypes/async_result.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/archetypes/gettable_socket_option.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/archetypes/io_control_command.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/archetypes/settable_socket_option.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_datagram_socket.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_deadline_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_raw_socket.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_seq_packet_socket.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_serial_port.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_signal_set.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_socket_acceptor.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_stream_socket.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_streambuf.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/basic_waitable_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/buffer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/buffered_read_stream.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/buffered_stream.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/buffered_write_stream.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/buffers_iterator.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/completion_condition.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/connect.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/coroutine.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/datagram_socket_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/deadline_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/deadline_timer_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/error.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/generic/basic_endpoint.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/generic/datagram_protocol.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/generic/raw_protocol.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/generic/seq_packet_protocol.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/generic/stream_protocol.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/high_resolution_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/io_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/address.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/address_v4.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/address_v6.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/basic_endpoint.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/basic_resolver.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/basic_resolver_entry.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/basic_resolver_iterator.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/basic_resolver_query.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/host_name.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/icmp.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/multicast.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/resolver_query_base.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/resolver_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/tcp.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/udp.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/unicast.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ip/v6_only.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/is_read_buffered.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/is_write_buffered.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/local/basic_endpoint.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/local/connect_pair.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/local/datagram_protocol.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/local/stream_protocol.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/placeholders.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/posix/basic_descriptor.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/posix/basic_stream_descriptor.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/posix/descriptor_base.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/posix/stream_descriptor.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/posix/stream_descriptor_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/raw_socket_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/read.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/read_at.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/read_until.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/seq_packet_socket_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/serial_port.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/serial_port_base.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/serial_port_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/signal_set.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/signal_set_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/socket_acceptor_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/socket_base.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/basic_context.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/context.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/context_base.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/context_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/rfc2818_verification.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/stream.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/stream_base.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/ssl/stream_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/steady_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/strand.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/stream_socket_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/streambuf.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/system_timer.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/thread.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/time_traits.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/unit_test.hpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/wait_traits.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/waitable_timer_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/basic_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/basic_object_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/basic_random_access_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/basic_stream_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/object_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/object_handle_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/overlapped_ptr.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/random_access_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/random_access_handle_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/stream_handle.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/windows/stream_handle_service.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/write.cpp create mode 100644 utils/dnp3_src/deps/asio/asio/src/tests/unit/write_at.cpp create mode 100755 utils/dnp3_src/deps/asio/asio/src/tools/handlerviz.pl create mode 100644 utils/dnp3_src/dotnet/bindings.sln create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/AssemblyInfo.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/CLRAdapter.vcxproj create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/CLRAdapter.vcxproj.filters create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/ReadMe.txt create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/app.ico create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/app.rc create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/resource.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/CallbackAdapters.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/CallbackAdapters.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ChangeSetAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ChangeSetAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ChannelAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ChannelAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ChannelListenerAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/CollectionAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/CommandSetBuilder.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/CommandSetBuilder.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/Conversions.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/Conversions.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/DNP3ManagerAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/DNP3ManagerAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/EventConverter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ICommandHeaderWorkAround.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ListenCallbacksAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ListenCallbacksAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/ListenerAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/Lock.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/LogAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/LogAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterApplicationAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterConversions.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterConversions.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterOperationsAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterOperationsAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterScanAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterSessionAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/MasterSessionAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/OutstationAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/OutstationAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/OutstationApplicationAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/OutstationApplicationAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/OutstationCommandHandlerAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/OutstationCommandHandlerAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/SOEHandlerAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/SOEHandlerAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/SessionAcceptorAdapter.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/SessionAcceptorAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/StdIOWorkaround.cpp create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/StdIOWorkaround.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRAdapter/src/TaskCallbackAdapter.h create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ApplicationIIN.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/BaseMeasurementTypes.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ChangeSet.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ChannelRetry.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ChannelStatistics.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ClassAssignment.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ClassField.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/CommandResultTypes.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/CommandSet.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/CommandTypes.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/Conversions.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/DNP3CLRInterface.csproj create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/DefaultListenCallbacks.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/Extensions.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/Header.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IChannel.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IChannelListener.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IChannelStatistics.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ICommandHandler.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ICommandProcessor.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IDNP3Manager.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IDatabase.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ILinkListener.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IListenCallbacks.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IListener.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ILogHandler.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IMaster.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IMasterApplication.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IMasterOperations.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IMasterScan.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IMasterSession.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IOutstation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IOutstationApplication.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IPEndpoint.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IQualityBitInfo.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ISOEHandler.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ISessionAcceptor.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IStack.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/IStackStatistics.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/ITaskCallback.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/LinkHeader.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/LogLevels.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/MeasurementTypes.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/NamespaceDoc.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/PrintingSOEHandler.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/Properties/AssemblyInfo.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/RestartResultType.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/SimpleCommandHandler.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/StackStatistics.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/TLSConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/TaskCompletionProxy.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/TaskConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/TaskId.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/TaskInfo.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/X509Info.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/DatabaseTemplate.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/EventBufferConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/LinkConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/MasterConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/MasterStackConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/OutstationConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/OutstationParams.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/OutstationStackConfig.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/PointRecords.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/SerialSettings.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/config/StaticTypeBitfield.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/AnalogOutputStatusQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/AnalogQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/AssignClassType.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/BinaryOutputStatusQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/BinaryQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/ChannelState.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/CommandPointState.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/CommandStatus.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/ControlCode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/CounterQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/DoubleBit.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/DoubleBitBinaryQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventAnalogOutputStatusVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventAnalogVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventBinaryOutputStatusVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventBinaryVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventCounterVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventDoubleBinaryVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventFrozenCounterVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventMode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/EventSecurityStatVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/FlagsType.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/FlowControl.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/FrozenCounterQuality.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/FunctionCode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/GroupVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/IINField.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/ILinkStatusListener.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/IndexMode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/IntervalUnits.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/KeyChangeMethod.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/KeyWrapAlgorithm.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/LinkFunction.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/LinkStatus.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/MasterTaskType.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/OperateType.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/Parity.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/PointClass.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/QualifierCode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/RestartMode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/RestartType.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticAnalogOutputStatusVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticAnalogVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticBinaryOutputStatusVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticBinaryVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticCounterVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticDoubleBinaryVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticFrozenCounterVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticSecurityStatVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticTimeAndIntervalVariation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StaticTypeBitmask.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/StopBits.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/TaskCompletion.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/TimeSyncMode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/TimestampMode.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/UserOperation.cs create mode 100644 utils/dnp3_src/dotnet/bindings/CLRInterface/gen/UserRole.cs create mode 100644 utils/dnp3_src/dotnet/config/opendnp3.props create mode 100644 utils/dnp3_src/dotnet/config/openssl_lib32_dir.props create mode 100644 utils/dnp3_src/dotnet/config/openssl_lib64_dir.props create mode 100644 utils/dnp3_src/dotnet/config/ossl_debug_lib.props create mode 100644 utils/dnp3_src/dotnet/config/ossl_release_lib.props create mode 100644 utils/dnp3_src/dotnet/config/output_dir.props create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs-tls/App.config create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs-tls/CLRMasterGPRSTLSDemo.csproj create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs-tls/CLRMasterGPRSTLSDemo.csproj.user create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs-tls/Program.cs create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs-tls/Properties/AssemblyInfo.cs create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs/App.config create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs/CLRMasterGPRSDemo.csproj create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs/CLRMasterGPRSDemo.csproj.user create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs/Program.cs create mode 100644 utils/dnp3_src/dotnet/examples/master-gprs/Properties/AssemblyInfo.cs create mode 100644 utils/dnp3_src/dotnet/examples/master/App.config create mode 100644 utils/dnp3_src/dotnet/examples/master/CLRMasterDemo.csproj create mode 100644 utils/dnp3_src/dotnet/examples/master/CLRMasterDemo.csproj.user create mode 100644 utils/dnp3_src/dotnet/examples/master/Program.cs create mode 100644 utils/dnp3_src/dotnet/examples/master/Properties/AssemblyInfo.cs create mode 100644 utils/dnp3_src/dotnet/examples/outstation/App.config create mode 100644 utils/dnp3_src/dotnet/examples/outstation/CLROutstationDemo.csproj create mode 100644 utils/dnp3_src/dotnet/examples/outstation/Program.cs create mode 100644 utils/dnp3_src/dotnet/examples/outstation/Properties/AssemblyInfo.cs create mode 100644 utils/dnp3_src/dotnet/nuget/opendnp3.nuspec create mode 100755 utils/dnp3_src/generation/AUTOMATAK_FILE_HEADER create mode 100755 utils/dnp3_src/generation/dnp3/pom.xml create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/Generate.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/AssignClassType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/AuthErrorCode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/CertificateType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/ChallengeReason.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/ChannelState.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/CommandPointState.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/CommandStatus.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/ConfigAuthMode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/ControlCode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/DefaultVariations.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/DoubleBit.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/EventMode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/FlagsType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/FunctionCode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/GroupVariationEnum.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/GroupVariationType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/HMACType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/IndexMode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/IntervalUnit.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/KeyChangeMethod.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/KeyStatus.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/KeyWrapAlgorithm.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/LinkFunction.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/LinkStatus.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/LogLevel.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/MasterTaskType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/OperateType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/PointClass.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/QualifierCode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/QualityMasks.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/RestartMode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/RestartType.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/SecurityStatIndex.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/SerialEnums.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/StaticTypeBitmask.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/TaskCompletion.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/TimeSyncMode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/TimestampMode.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/UserOperation.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/UserRole.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/generators/CSharpEnumGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/generators/CppEnumGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/generators/JavaEnumGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/groups/CSharpEnumGroup.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/enums/groups/DNPCppEnumGroup.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/Fields.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/GroupVariation.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/ObjectGroup.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/VariationNames.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/AttributeGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/AuthVariableSizeGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/Conversions.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/FixedSizeGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/FixedSizeHelpers.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/GroupVariationFileGenerator.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/GroupVariationIncludes.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/GroupVariationLines.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/generators/GroupVariationRenderer.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group1.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group10.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group11.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group110.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group111.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group112.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group113.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group12.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group120.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group121.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group122.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group13.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group2.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group20.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group21.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group22.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group23.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group3.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group30.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group32.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group4.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group40.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group41.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group42.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group43.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group50.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group51.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group52.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group60.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group70.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/main/scala/com/automatak/render/dnp3/objects/groups/Group80.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/test/scala/com/automatak/render/dnp3/GroupVariationRenderingTestSuite.scala create mode 100644 utils/dnp3_src/generation/dnp3/src/test/scala/com/automatak/render/dnp3/GroupVariationTestSuite.scala create mode 100755 utils/dnp3_src/generation/pom.xml create mode 100755 utils/dnp3_src/generation/render/pom.xml create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/EnumModel.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/Header.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/Indentation.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/ModelRenderer.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cc/EnumModelRenderer.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/CppFunction.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/CppIndentation.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/EnumConfig.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/EnumFromType.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/EnumModelRenderer.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/EnumToString.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/EnumToType.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/HeaderImplModelRender.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/SwitchModelRenderer.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/cpp/package.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/csharp/EnumModelRenderer.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/csharp/package.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/java/EnumModelRenderer.scala create mode 100644 utils/dnp3_src/generation/render/src/main/scala/com/automatak/render/pacakge.scala create mode 100644 utils/dnp3_src/java/AUTOMATAK_FILE_HEADER create mode 100644 utils/dnp3_src/java/README.md create mode 100644 utils/dnp3_src/java/bindings/pom.xml create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ActionCommandHeader.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogInput.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogOutputDouble64.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogOutputFloat32.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogOutputInt16.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogOutputInt32.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogOutputStatus.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/AnalogOutputStatusConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ApplicationIIN.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/BinaryConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/BinaryInput.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/BinaryOutputStatus.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/BinaryOutputStatusConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ChangeSet.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Channel.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ChannelListener.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ChannelRetry.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ChannelStatistics.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ClassAssignment.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ClassField.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandBuilder.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandHeader.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandHeaders.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandPointResult.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandProcessor.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandSet.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CommandTaskResult.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ControlRelayOutputBlock.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Counter.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/CounterConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/DNP3Exception.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/DNP3Manager.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/DNPTime.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Database.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/DatabaseConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/DoubleBinaryConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/DoubleBitBinaryInput.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/EventBufferConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/EventConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ExceptionScan.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/FrozenCounter.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/FrozenCounterConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Header.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/HeaderInfo.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/IINField.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/IndexedValue.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LinkLayerConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LinkLayerStatistics.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LinkStatistics.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LinkStatusListener.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LogEntry.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LogHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LogLevels.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/LogMasks.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Master.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/MasterApplication.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/MasterConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/MasterStackConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Measurement.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/OctetString.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Outstation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/OutstationApplication.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/OutstationChangeSet.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/OutstationConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/OutstationStackConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/ParserStatistics.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/PointClassMasks.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/QualityField.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Range.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/SOEHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/SerialSettings.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/Stack.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/StackStatistics.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/TLSConfig.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/TaskId.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/TaskInfo.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/TransportStatistics.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/AnalogOutputStatusQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/AnalogQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/AssignClassType.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/BinaryOutputStatusQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/BinaryQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/ChannelState.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/CommandPointState.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/CommandStatus.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/ControlCode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/CounterQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/DoubleBit.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/DoubleBitBinaryQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventAnalogOutputStatusVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventAnalogVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventBinaryOutputStatusVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventBinaryVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventCounterVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventDoubleBinaryVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventFrozenCounterVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventMode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/EventSecurityStatVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/FlagsType.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/FlowControl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/FrozenCounterQuality.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/GroupVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/IndexMode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/IntervalUnits.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/KeyChangeMethod.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/KeyWrapAlgorithm.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/LinkFunction.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/LinkStatus.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/MasterTaskType.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/OperateType.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/Parity.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/PointClass.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/QualifierCode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/RestartMode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/RestartType.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticAnalogOutputStatusVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticAnalogVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticBinaryOutputStatusVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticBinaryVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticCounterVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticDoubleBinaryVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticFrozenCounterVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticSecurityStatVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticTimeAndIntervalVariation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StaticTypeBitmask.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/StopBits.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/TaskCompletion.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/TimeSyncMode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/TimestampMode.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/UserOperation.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/UserRole.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/enums/package-info.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/ChangeSetImpl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/ChannelImpl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/CommandBuilderImpl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/DNP3ManagerFactory.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/ManagerImpl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/MasterImpl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/OutstationImpl.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/impl/package-info.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/ConstantCommandHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/DefaultMasterApplication.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/DefaultOutstationApplication.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/OutputHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/PrintingChannelListener.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/PrintingLogHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/PrintingSOEHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/SuccessCommandHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/mock/package-info.java create mode 100644 utils/dnp3_src/java/bindings/src/main/java/com/automatak/dnp3/package-info.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/DNP3ManagerIntegrationTest.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/ExpectedValueTestSuite.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/mocks/BlockingChannelListener.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/mocks/ExpectedValue.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/mocks/NullLogHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/mocks/QueuedSOEHandler.java create mode 100644 utils/dnp3_src/java/bindings/src/test/java/com/automatak/dnp3/impl/mocks/StackPair.java create mode 100644 utils/dnp3_src/java/codegen/pom.xml create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/Classes.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/ConfigTypes.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/Generator.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/Indentation.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/JCacheGenerator.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/JNIClassGenerator.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/JNIMethod.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/License.scala create mode 100644 utils/dnp3_src/java/codegen/src/main/scala/com/automatak/dnp3/codegen/package.scala create mode 100644 utils/dnp3_src/java/cpp/adapters/CString.h create mode 100644 utils/dnp3_src/java/cpp/adapters/ChannelListenerAdapter.h create mode 100644 utils/dnp3_src/java/cpp/adapters/CommandHandlerAdapter.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/CommandHandlerAdapter.h create mode 100644 utils/dnp3_src/java/cpp/adapters/ConfigReader.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/ConfigReader.h create mode 100644 utils/dnp3_src/java/cpp/adapters/Conversions.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/Conversions.h create mode 100644 utils/dnp3_src/java/cpp/adapters/GlobalRef.h create mode 100644 utils/dnp3_src/java/cpp/adapters/JNI.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/JNI.h create mode 100644 utils/dnp3_src/java/cpp/adapters/LocalRef.h create mode 100644 utils/dnp3_src/java/cpp/adapters/LogHandlerAdapter.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/LogHandlerAdapter.h create mode 100644 utils/dnp3_src/java/cpp/adapters/MasterApplicationAdapter.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/MasterApplicationAdapter.h create mode 100644 utils/dnp3_src/java/cpp/adapters/OutstationApplicationAdapter.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/OutstationApplicationAdapter.h create mode 100644 utils/dnp3_src/java/cpp/adapters/SOEHandlerAdapter.cpp create mode 100644 utils/dnp3_src/java/cpp/adapters/SOEHandlerAdapter.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_ChangeSetImpl.cpp create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_ChangeSetImpl.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_ChannelImpl.cpp create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_ChannelImpl.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_CommandBuilderImpl.cpp create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_CommandBuilderImpl.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_DNP3ManagerFactory.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_ManagerImpl.cpp create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_ManagerImpl.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_MasterImpl.cpp create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_MasterImpl.h create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_OutstationImpl.cpp create mode 100644 utils/dnp3_src/java/cpp/com_automatak_dnp3_impl_OutstationImpl.h create mode 100644 utils/dnp3_src/java/cpp/jni/JCache.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JCache.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogInput.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogInput.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputDouble64.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputDouble64.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputFloat32.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputFloat32.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputInt16.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputInt16.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputInt32.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputInt32.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputStatus.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputStatus.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputStatusConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAnalogOutputStatusConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIApplicationIIN.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIApplicationIIN.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIArrayList.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIArrayList.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAssignClassType.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIAssignClassType.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryInput.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryInput.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryOutputStatus.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryOutputStatus.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryOutputStatusConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIBinaryOutputStatusConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIChannelListener.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIChannelListener.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIChannelState.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIChannelState.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIChannelStatistics.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIChannelStatistics.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIClassAssignment.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIClassAssignment.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIClassField.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIClassField.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandHandler.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandHandler.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandPointResult.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandPointResult.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandPointState.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandPointState.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandProcessor.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandProcessor.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandStatus.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandStatus.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandTaskResult.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICommandTaskResult.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICompletableFuture.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICompletableFuture.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIControlCode.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIControlCode.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIControlRelayOutputBlock.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIControlRelayOutputBlock.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICounter.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICounter.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNICounterConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNICounterConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDNPTime.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDNPTime.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDatabaseConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDatabaseConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDoubleBinaryConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDoubleBinaryConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDoubleBit.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDoubleBit.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDoubleBitBinaryInput.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDoubleBitBinaryInput.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDuration.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIDuration.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventAnalogOutputStatusVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventAnalogOutputStatusVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventAnalogVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventAnalogVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventBinaryOutputStatusVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventBinaryOutputStatusVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventBinaryVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventBinaryVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventBufferConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventBufferConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventCounterVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventCounterVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventDoubleBinaryVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventDoubleBinaryVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventFrozenCounterVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIEventFrozenCounterVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIFrozenCounter.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIFrozenCounter.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIFrozenCounterConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIFrozenCounterConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIGroupVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIGroupVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIHeader.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIHeader.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIHeaderInfo.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIHeaderInfo.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIINField.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIINField.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIndexMode.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIndexMode.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIndexedValue.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIndexedValue.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIterable.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIterable.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIterator.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIIterator.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNILinkLayerConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNILinkLayerConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNILinkLayerStatistics.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNILinkLayerStatistics.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNILinkStatistics.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNILinkStatistics.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIList.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIList.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNILogEntry.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNILogEntry.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNILogHandler.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNILogHandler.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterApplication.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterApplication.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterStackConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterStackConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterTaskType.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIMasterTaskType.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOperateType.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOperateType.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOutstationApplication.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOutstationApplication.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOutstationConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOutstationConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOutstationStackConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIOutstationStackConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIParserStatistics.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIParserStatistics.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIPointClass.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIPointClass.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIQualifierCode.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIQualifierCode.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIRange.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIRange.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNISOEHandler.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNISOEHandler.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStack.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStack.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStackStatistics.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStackStatistics.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticAnalogOutputStatusVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticAnalogOutputStatusVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticAnalogVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticAnalogVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticBinaryOutputStatusVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticBinaryOutputStatusVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticBinaryVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticBinaryVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticCounterVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticCounterVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticDoubleBinaryVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticDoubleBinaryVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticFrozenCounterVariation.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNIStaticFrozenCounterVariation.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITLSConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITLSConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskCompletion.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskCompletion.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskConfig.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskConfig.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskId.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskId.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskInfo.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITaskInfo.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITimeSyncMode.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITimeSyncMode.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITimestampMode.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITimestampMode.h create mode 100644 utils/dnp3_src/java/cpp/jni/JNITransportStatistics.cpp create mode 100644 utils/dnp3_src/java/cpp/jni/JNITransportStatistics.h create mode 100644 utils/dnp3_src/java/example/pom.xml create mode 100644 utils/dnp3_src/java/example/src/main/java/com/automatak/dnp3/example/MasterDemo.java create mode 100644 utils/dnp3_src/java/example/src/main/java/com/automatak/dnp3/example/OutstationDemo.java create mode 100644 utils/dnp3_src/java/pom.xml create mode 100644 utils/dnp3_src/java/run-javah.bat create mode 100644 utils/dnp3_src/profile/opendnp3_profile.xml create mode 100755 utils/glue_generator_src/glue_generator.cpp create mode 100755 utils/libmodbus_src/AUTHORS create mode 100755 utils/libmodbus_src/CONTRIBUTING.md create mode 100755 utils/libmodbus_src/COPYING.LESSER create mode 100755 utils/libmodbus_src/ISSUE_TEMPLATE.md create mode 100755 utils/libmodbus_src/MIGRATION create mode 100755 utils/libmodbus_src/Makefile.am create mode 100755 utils/libmodbus_src/NEWS create mode 100755 utils/libmodbus_src/README.md create mode 100755 utils/libmodbus_src/acinclude.m4 create mode 100755 utils/libmodbus_src/autogen.sh create mode 100755 utils/libmodbus_src/configure.ac create mode 100755 utils/libmodbus_src/doc/Makefile.am create mode 100755 utils/libmodbus_src/doc/asciidoc.conf create mode 100755 utils/libmodbus_src/doc/libmodbus.txt create mode 100755 utils/libmodbus_src/doc/modbus_close.txt create mode 100755 utils/libmodbus_src/doc/modbus_connect.txt create mode 100755 utils/libmodbus_src/doc/modbus_flush.txt create mode 100755 utils/libmodbus_src/doc/modbus_free.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_byte_from_bits.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_byte_timeout.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_float.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_float_abcd.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_float_badc.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_float_cdab.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_float_dcba.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_header_length.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_response_timeout.txt create mode 100755 utils/libmodbus_src/doc/modbus_get_socket.txt create mode 100755 utils/libmodbus_src/doc/modbus_mapping_free.txt create mode 100755 utils/libmodbus_src/doc/modbus_mapping_new.txt create mode 100755 utils/libmodbus_src/doc/modbus_mapping_new_start_address.txt create mode 100755 utils/libmodbus_src/doc/modbus_mask_write_register.txt create mode 100755 utils/libmodbus_src/doc/modbus_new_rtu.txt create mode 100755 utils/libmodbus_src/doc/modbus_new_tcp.txt create mode 100755 utils/libmodbus_src/doc/modbus_new_tcp_pi.txt create mode 100755 utils/libmodbus_src/doc/modbus_read_bits.txt create mode 100755 utils/libmodbus_src/doc/modbus_read_input_bits.txt create mode 100755 utils/libmodbus_src/doc/modbus_read_input_registers.txt create mode 100755 utils/libmodbus_src/doc/modbus_read_registers.txt create mode 100755 utils/libmodbus_src/doc/modbus_receive.txt create mode 100755 utils/libmodbus_src/doc/modbus_receive_confirmation.txt create mode 100755 utils/libmodbus_src/doc/modbus_reply.txt create mode 100755 utils/libmodbus_src/doc/modbus_reply_exception.txt create mode 100755 utils/libmodbus_src/doc/modbus_report_slave_id.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_get_rts.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_get_rts_delay.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_get_serial_mode.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_set_custom_rts.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_set_rts.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_set_rts_delay.txt create mode 100755 utils/libmodbus_src/doc/modbus_rtu_set_serial_mode.txt create mode 100755 utils/libmodbus_src/doc/modbus_send_raw_request.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_bits_from_byte.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_bits_from_bytes.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_byte_timeout.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_debug.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_error_recovery.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_float.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_float_abcd.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_float_badc.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_float_cdab.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_float_dcba.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_response_timeout.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_slave.txt create mode 100755 utils/libmodbus_src/doc/modbus_set_socket.txt create mode 100755 utils/libmodbus_src/doc/modbus_strerror.txt create mode 100755 utils/libmodbus_src/doc/modbus_tcp_accept.txt create mode 100755 utils/libmodbus_src/doc/modbus_tcp_listen.txt create mode 100755 utils/libmodbus_src/doc/modbus_tcp_pi_accept.txt create mode 100755 utils/libmodbus_src/doc/modbus_tcp_pi_listen.txt create mode 100755 utils/libmodbus_src/doc/modbus_write_and_read_registers.txt create mode 100755 utils/libmodbus_src/doc/modbus_write_bit.txt create mode 100755 utils/libmodbus_src/doc/modbus_write_bits.txt create mode 100755 utils/libmodbus_src/doc/modbus_write_register.txt create mode 100755 utils/libmodbus_src/doc/modbus_write_registers.txt create mode 100755 utils/libmodbus_src/libmodbus.pc.in create mode 100755 utils/libmodbus_src/m4/.gitignore create mode 100755 utils/libmodbus_src/src/Makefile.am create mode 100755 utils/libmodbus_src/src/modbus-data.c create mode 100755 utils/libmodbus_src/src/modbus-private.h create mode 100755 utils/libmodbus_src/src/modbus-rtu-private.h create mode 100755 utils/libmodbus_src/src/modbus-rtu.c create mode 100755 utils/libmodbus_src/src/modbus-rtu.h create mode 100755 utils/libmodbus_src/src/modbus-tcp-private.h create mode 100755 utils/libmodbus_src/src/modbus-tcp.c create mode 100755 utils/libmodbus_src/src/modbus-tcp.h create mode 100755 utils/libmodbus_src/src/modbus-version.h.in create mode 100755 utils/libmodbus_src/src/modbus.c create mode 100755 utils/libmodbus_src/src/modbus.h create mode 100755 utils/libmodbus_src/src/win32/Make-tests create mode 100755 utils/libmodbus_src/src/win32/README.win32 create mode 100755 utils/libmodbus_src/src/win32/config.h.win32 create mode 100755 utils/libmodbus_src/src/win32/configure.js create mode 100755 utils/libmodbus_src/src/win32/modbus-9.sln create mode 100755 utils/libmodbus_src/src/win32/modbus.dll.manifest.in create mode 100755 utils/libmodbus_src/src/win32/modbus.rc create mode 100755 utils/libmodbus_src/src/win32/modbus.vcproj create mode 100755 utils/libmodbus_src/tests/LICENSE create mode 100755 utils/libmodbus_src/tests/Makefile.am create mode 100755 utils/libmodbus_src/tests/README.md create mode 100755 utils/libmodbus_src/tests/bandwidth-client.c create mode 100755 utils/libmodbus_src/tests/bandwidth-server-many-up.c create mode 100755 utils/libmodbus_src/tests/bandwidth-server-one.c create mode 100755 utils/libmodbus_src/tests/random-test-client.c create mode 100755 utils/libmodbus_src/tests/random-test-server.c create mode 100755 utils/libmodbus_src/tests/unit-test-client.c create mode 100755 utils/libmodbus_src/tests/unit-test-server.c create mode 100755 utils/libmodbus_src/tests/unit-test.h.in create mode 100755 utils/libmodbus_src/tests/unit-tests.sh create mode 100755 utils/libmodbus_src/tests/version.c create mode 100755 utils/matiec_src/AnnexF/average_st.txt create mode 100755 utils/matiec_src/AnnexF/cmd_monitor_il.txt create mode 100755 utils/matiec_src/AnnexF/cmd_monitor_st.txt create mode 100755 utils/matiec_src/AnnexF/delay_st.txt create mode 100755 utils/matiec_src/AnnexF/derivative_st.txt create mode 100755 utils/matiec_src/AnnexF/diffeq_st.txt create mode 100755 utils/matiec_src/AnnexF/fwd_rev_mon_il.txt create mode 100755 utils/matiec_src/AnnexF/fwd_rev_mon_st.txt create mode 100755 utils/matiec_src/AnnexF/gravel_st.txt create mode 100755 utils/matiec_src/AnnexF/hysteresis_st.txt create mode 100755 utils/matiec_src/AnnexF/integral_st.txt create mode 100755 utils/matiec_src/AnnexF/lag1_st.txt create mode 100755 utils/matiec_src/AnnexF/pid_st.txt create mode 100755 utils/matiec_src/AnnexF/ramp_st.txt create mode 100755 utils/matiec_src/AnnexF/readme create mode 100755 utils/matiec_src/AnnexF/stack_int_il.txt create mode 100755 utils/matiec_src/AnnexF/stack_int_st.txt create mode 100755 utils/matiec_src/AnnexF/transfer_st.txt create mode 100755 utils/matiec_src/AnnexF/weigh_il.txt create mode 100755 utils/matiec_src/AnnexF/weigh_st.txt create mode 100644 utils/matiec_src/COPYING create mode 100644 utils/matiec_src/Makefile.am create mode 100644 utils/matiec_src/README.build create mode 100644 utils/matiec_src/absyntax/Makefile.am create mode 100755 utils/matiec_src/absyntax/absyntax.cc create mode 100644 utils/matiec_src/absyntax/absyntax.def create mode 100755 utils/matiec_src/absyntax/absyntax.hh create mode 100755 utils/matiec_src/absyntax/visitor.cc create mode 100755 utils/matiec_src/absyntax/visitor.hh create mode 100644 utils/matiec_src/absyntax_utils/Makefile.am create mode 100644 utils/matiec_src/absyntax_utils/absyntax_utils.cc create mode 100644 utils/matiec_src/absyntax_utils/absyntax_utils.hh create mode 100755 utils/matiec_src/absyntax_utils/add_en_eno_param_decl.cc create mode 100755 utils/matiec_src/absyntax_utils/add_en_eno_param_decl.hh create mode 100755 utils/matiec_src/absyntax_utils/array_dimension_iterator.cc create mode 100755 utils/matiec_src/absyntax_utils/array_dimension_iterator.hh create mode 100755 utils/matiec_src/absyntax_utils/case_element_iterator.cc create mode 100755 utils/matiec_src/absyntax_utils/case_element_iterator.hh create mode 100644 utils/matiec_src/absyntax_utils/debug_ast.cc create mode 100644 utils/matiec_src/absyntax_utils/debug_ast.hh create mode 100755 utils/matiec_src/absyntax_utils/decompose_var_instance_name.cc create mode 100755 utils/matiec_src/absyntax_utils/decompose_var_instance_name.hh create mode 100755 utils/matiec_src/absyntax_utils/function_call_iterator.cc create mode 100755 utils/matiec_src/absyntax_utils/function_call_iterator.hh create mode 100755 utils/matiec_src/absyntax_utils/function_call_param_iterator.cc create mode 100755 utils/matiec_src/absyntax_utils/function_call_param_iterator.hh create mode 100644 utils/matiec_src/absyntax_utils/function_param_iterator.cc create mode 100755 utils/matiec_src/absyntax_utils/function_param_iterator.hh create mode 100644 utils/matiec_src/absyntax_utils/get_datatype_info.cc create mode 100644 utils/matiec_src/absyntax_utils/get_datatype_info.hh create mode 100755 utils/matiec_src/absyntax_utils/get_sizeof_datatype.cc create mode 100755 utils/matiec_src/absyntax_utils/get_sizeof_datatype.hh create mode 100644 utils/matiec_src/absyntax_utils/get_var_name.cc create mode 100644 utils/matiec_src/absyntax_utils/get_var_name.hh create mode 100755 utils/matiec_src/absyntax_utils/search_base_type.cc create mode 100755 utils/matiec_src/absyntax_utils/search_base_type.hh create mode 100755 utils/matiec_src/absyntax_utils/search_fb_instance_decl.cc create mode 100755 utils/matiec_src/absyntax_utils/search_fb_instance_decl.hh create mode 100755 utils/matiec_src/absyntax_utils/search_fb_typedecl.cc create mode 100755 utils/matiec_src/absyntax_utils/search_fb_typedecl.hh create mode 100644 utils/matiec_src/absyntax_utils/search_il_label.cc create mode 100644 utils/matiec_src/absyntax_utils/search_il_label.hh create mode 100644 utils/matiec_src/absyntax_utils/search_var_instance_decl.cc create mode 100644 utils/matiec_src/absyntax_utils/search_var_instance_decl.hh create mode 100755 utils/matiec_src/absyntax_utils/search_varfb_instance_type.cc create mode 100755 utils/matiec_src/absyntax_utils/search_varfb_instance_type.hh create mode 100755 utils/matiec_src/absyntax_utils/spec_init_separator.cc create mode 100755 utils/matiec_src/absyntax_utils/spec_init_separator.hh create mode 100644 utils/matiec_src/absyntax_utils/type_initial_value.cc create mode 100755 utils/matiec_src/absyntax_utils/type_initial_value.hh create mode 100644 utils/matiec_src/bin_win32/crosscompile_w32.txt create mode 100755 utils/matiec_src/bin_win32/iec2c.exe create mode 100755 utils/matiec_src/bin_win32/libgcc_s_sjlj-1.dll create mode 100755 utils/matiec_src/bin_win32/libstdc++-6.dll create mode 100644 utils/matiec_src/common.mk create mode 100644 utils/matiec_src/config/INSTALL create mode 100644 utils/matiec_src/config/aclocal.m4 create mode 100755 utils/matiec_src/config/depcomp create mode 100755 utils/matiec_src/config/install-sh create mode 100644 utils/matiec_src/config/libtool.m4 create mode 100755 utils/matiec_src/config/ltmain.sh create mode 100644 utils/matiec_src/config/ltoptions.m4 create mode 100644 utils/matiec_src/config/ltsugar.m4 create mode 100644 utils/matiec_src/config/ltversion.m4 create mode 100644 utils/matiec_src/config/lt~obsolete.m4 create mode 100755 utils/matiec_src/config/missing create mode 100755 utils/matiec_src/config/ylwrap create mode 100644 utils/matiec_src/configure.ac create mode 100755 utils/matiec_src/debian/README.Debian create mode 100755 utils/matiec_src/debian/changelog create mode 100755 utils/matiec_src/debian/compat create mode 100755 utils/matiec_src/debian/control create mode 100755 utils/matiec_src/debian/copyright create mode 100755 utils/matiec_src/debian/dirs create mode 100755 utils/matiec_src/debian/postinst create mode 100755 utils/matiec_src/debian/postrm create mode 100755 utils/matiec_src/debian/rules create mode 100755 utils/matiec_src/lib/C/accessor.h create mode 100644 utils/matiec_src/lib/C/iec_std_FB.h create mode 100644 utils/matiec_src/lib/C/iec_std_FB_no_ENENO.h create mode 100755 utils/matiec_src/lib/C/iec_std_functions.h create mode 100755 utils/matiec_src/lib/C/iec_std_lib.h create mode 100755 utils/matiec_src/lib/C/iec_types.h create mode 100755 utils/matiec_src/lib/C/iec_types_all.h create mode 100644 utils/matiec_src/lib/COPYING.LESSER create mode 100755 utils/matiec_src/lib/bistable.txt create mode 100755 utils/matiec_src/lib/counter.txt create mode 100755 utils/matiec_src/lib/create_standard_function_txt.sh create mode 100755 utils/matiec_src/lib/derivative_st.txt create mode 100755 utils/matiec_src/lib/edge_detection.txt create mode 100755 utils/matiec_src/lib/hysteresis_st.txt create mode 100755 utils/matiec_src/lib/ieclib.txt create mode 100755 utils/matiec_src/lib/integral_st.txt create mode 100755 utils/matiec_src/lib/pid_st.txt create mode 100755 utils/matiec_src/lib/ramp_st.txt create mode 100644 utils/matiec_src/lib/rtc.txt create mode 100644 utils/matiec_src/lib/sema.txt create mode 100755 utils/matiec_src/lib/standard_FB.txt create mode 100755 utils/matiec_src/lib/standard_functions.txt create mode 100755 utils/matiec_src/lib/test_iec_std_lib.c create mode 100755 utils/matiec_src/lib/timer.txt create mode 100755 utils/matiec_src/main.cc create mode 100644 utils/matiec_src/main.hh create mode 100755 utils/matiec_src/readme create mode 100755 utils/matiec_src/stage1_2/.cvsignore create mode 100644 utils/matiec_src/stage1_2/Makefile.am create mode 100644 utils/matiec_src/stage1_2/create_enumtype_conversion_functions.cc create mode 100644 utils/matiec_src/stage1_2/create_enumtype_conversion_functions.hh create mode 100644 utils/matiec_src/stage1_2/iec_bison.yy create mode 100644 utils/matiec_src/stage1_2/iec_flex.ll create mode 100755 utils/matiec_src/stage1_2/stage1_2.cc create mode 100755 utils/matiec_src/stage1_2/stage1_2.hh create mode 100755 utils/matiec_src/stage1_2/stage1_2_priv.hh create mode 100755 utils/matiec_src/stage1_2/standard_function_names.c create mode 100644 utils/matiec_src/stage3/Makefile.am create mode 100644 utils/matiec_src/stage3/TODO create mode 100644 utils/matiec_src/stage3/array_range_check.cc create mode 100644 utils/matiec_src/stage3/array_range_check.hh create mode 100644 utils/matiec_src/stage3/case_elements_check.cc create mode 100644 utils/matiec_src/stage3/case_elements_check.hh create mode 100644 utils/matiec_src/stage3/constant_folding.cc create mode 100644 utils/matiec_src/stage3/constant_folding.hh create mode 100644 utils/matiec_src/stage3/datatype_functions.cc create mode 100644 utils/matiec_src/stage3/datatype_functions.hh create mode 100644 utils/matiec_src/stage3/declaration_check.cc create mode 100644 utils/matiec_src/stage3/declaration_check.hh create mode 100644 utils/matiec_src/stage3/enum_declaration_check.cc create mode 100644 utils/matiec_src/stage3/enum_declaration_check.hh create mode 100755 utils/matiec_src/stage3/fill_candidate_datatypes.cc create mode 100755 utils/matiec_src/stage3/fill_candidate_datatypes.hh create mode 100644 utils/matiec_src/stage3/flow_control_analysis.cc create mode 100644 utils/matiec_src/stage3/flow_control_analysis.hh create mode 100644 utils/matiec_src/stage3/forced_narrow_candidate_datatypes.cc create mode 100644 utils/matiec_src/stage3/forced_narrow_candidate_datatypes.hh create mode 100644 utils/matiec_src/stage3/lvalue_check.cc create mode 100644 utils/matiec_src/stage3/lvalue_check.hh create mode 100755 utils/matiec_src/stage3/narrow_candidate_datatypes.cc create mode 100755 utils/matiec_src/stage3/narrow_candidate_datatypes.hh create mode 100755 utils/matiec_src/stage3/print_datatypes_error.cc create mode 100755 utils/matiec_src/stage3/print_datatypes_error.hh create mode 100644 utils/matiec_src/stage3/remove_forward_dependencies.cc create mode 100644 utils/matiec_src/stage3/remove_forward_dependencies.hh create mode 100755 utils/matiec_src/stage3/stage3.cc create mode 100755 utils/matiec_src/stage3/stage3.hh create mode 100644 utils/matiec_src/stage4/Makefile.am create mode 100755 utils/matiec_src/stage4/generate_c/.cvsignore create mode 100644 utils/matiec_src/stage4/generate_c/Makefile.am create mode 100644 utils/matiec_src/stage4/generate_c/generate_c.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c.hh create mode 100644 utils/matiec_src/stage4/generate_c/generate_c_base.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c_configbody.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c_il.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c_inlinefcall.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c_sfc.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c_sfcdecl.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_c_st.cc create mode 100644 utils/matiec_src/stage4/generate_c/generate_c_typedecl.cc create mode 100644 utils/matiec_src/stage4/generate_c/generate_c_vardecl.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_location_list.cc create mode 100755 utils/matiec_src/stage4/generate_c/generate_var_list.cc create mode 100755 utils/matiec_src/stage4/generate_c/plc.h create mode 100755 utils/matiec_src/stage4/generate_c/types.h create mode 100755 utils/matiec_src/stage4/generate_cc/.cvsignore create mode 100755 utils/matiec_src/stage4/generate_iec/.cvsignore create mode 100644 utils/matiec_src/stage4/generate_iec/Makefile.am create mode 100644 utils/matiec_src/stage4/generate_iec/generate_iec.cc create mode 100755 utils/matiec_src/stage4/generate_iec/generate_iec.hh create mode 100644 utils/matiec_src/stage4/stage4.cc create mode 100755 utils/matiec_src/stage4/stage4.hh create mode 100755 utils/matiec_src/tests/.cvsignore create mode 100755 utils/matiec_src/tests/LD_TEST.xml create mode 100755 utils/matiec_src/tests/SFC_TEST.xml create mode 100755 utils/matiec_src/tests/STD_TEST.xml create mode 100755 utils/matiec_src/tests/build.sh create mode 100755 utils/matiec_src/tests/build_win32.sh create mode 100755 utils/matiec_src/tests/main.c create mode 100755 utils/matiec_src/tests/plc.c create mode 100755 utils/matiec_src/tests/syntax/configuration/configuration.txt create mode 100755 utils/matiec_src/tests/syntax/enumeration/enumerationvalue.txt create mode 100755 utils/matiec_src/tests/syntax/identifier/Makefile create mode 100755 utils/matiec_src/tests/syntax/identifier/basic_code.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier.txt create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_configuration.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_datatype.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_enumerationvalue.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_function1.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_function2.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_functionblock.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_label.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_program.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_variable1.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_as_variable2.test create mode 100755 utils/matiec_src/tests/syntax/identifier/identifier_in_sfc.test create mode 100755 utils/matiec_src/tests/syntax/identifier/runtests create mode 100755 utils/matiec_src/tests/syntax/sfc/sfc.txt create mode 100755 utils/matiec_src/util/dsymtable.cc create mode 100755 utils/matiec_src/util/dsymtable.hh create mode 100755 utils/matiec_src/util/strdup.hh create mode 100755 utils/matiec_src/util/symtable.cc create mode 100755 utils/matiec_src/util/symtable.hh create mode 100755 utils/st_optimizer_src/st_optimizer.cpp create mode 100755 webserver/active_program create mode 100755 webserver/core/custom_layer.cpp create mode 100755 webserver/core/custom_layer.original create mode 100755 webserver/core/dnp3.cpp create mode 100755 webserver/core/dnp3_dummy.disabled create mode 100755 webserver/core/glueVars.cpp create mode 100755 webserver/core/hardware_layer.cpp create mode 100755 webserver/core/hardware_layers/blank.cpp create mode 100755 webserver/core/hardware_layers/fischertechnik.cpp create mode 100755 webserver/core/hardware_layers/pixtend.cpp create mode 100755 webserver/core/hardware_layers/pixtend2s.cpp create mode 100755 webserver/core/hardware_layers/raspberrypi.cpp create mode 100755 webserver/core/hardware_layers/raspberrypi_old.cpp create mode 100755 webserver/core/hardware_layers/simulink.cpp create mode 100755 webserver/core/hardware_layers/unipi.cpp create mode 100755 webserver/core/interactive_server.cpp create mode 100755 webserver/core/ladder.h create mode 100755 webserver/core/lib/accessor.h create mode 100755 webserver/core/lib/iec_std_FB.h create mode 100755 webserver/core/lib/iec_std_functions.h create mode 100755 webserver/core/lib/iec_std_lib.h create mode 100755 webserver/core/lib/iec_types.h create mode 100755 webserver/core/lib/iec_types_all.h create mode 100755 webserver/core/main.cpp create mode 100755 webserver/core/modbus.cpp create mode 100755 webserver/core/server.cpp create mode 100644 webserver/dnp3.cfg create mode 100755 webserver/lib/COPYING.LESSER create mode 100755 webserver/lib/bistable.txt create mode 100755 webserver/lib/counter.txt create mode 100755 webserver/lib/create_standard_function_txt.sh create mode 100755 webserver/lib/derivative_st.txt create mode 100755 webserver/lib/edge_detection.txt create mode 100755 webserver/lib/hysteresis_st.txt create mode 100755 webserver/lib/ieclib.txt create mode 100755 webserver/lib/integral_st.txt create mode 100755 webserver/lib/pid_st.txt create mode 100755 webserver/lib/ramp_st.txt create mode 100755 webserver/lib/rtc.txt create mode 100755 webserver/lib/sema.txt create mode 100755 webserver/lib/standard_FB.txt create mode 100755 webserver/lib/standard_functions.txt create mode 100755 webserver/lib/test_iec_std_lib.c create mode 100755 webserver/lib/timer.txt create mode 100755 webserver/openplc.db create mode 100755 webserver/openplc.py create mode 100755 webserver/pages.py create mode 100755 webserver/scripts/change_hardware_layer.sh create mode 100755 webserver/scripts/compile_program.sh create mode 100755 webserver/scripts/openplc_driver create mode 100755 webserver/scripts/openplc_platform create mode 100755 webserver/scripts/start_openplc.sh create mode 100644 webserver/st_files/blank_program.st create mode 100755 webserver/static/arrow.png create mode 100755 webserver/static/bool_false.png create mode 100755 webserver/static/bool_true.png create mode 100644 webserver/static/codemirror/active-line.js create mode 100644 webserver/static/codemirror/codemirror.css create mode 100644 webserver/static/codemirror/codemirror.js create mode 100644 webserver/static/codemirror/javascript.js create mode 100644 webserver/static/codemirror/liquibyte.css create mode 100644 webserver/static/codemirror/matchbrackets.js create mode 100755 webserver/static/communication-icon-64x64.png create mode 100755 webserver/static/default-user.png create mode 100755 webserver/static/hardware-icon-980x974.png create mode 100755 webserver/static/home-icon-64x64.png create mode 100755 webserver/static/logout-icon-64x64.png create mode 100755 webserver/static/modbus-icon-512x512.png create mode 100755 webserver/static/monitoring-icon-64x64.png create mode 100755 webserver/static/openplc_logo.gif create mode 100755 webserver/static/programs-icon-64x64.png create mode 100755 webserver/static/settings-icon-64x64.png create mode 100755 webserver/static/users-icon-64x64.png create mode 100755 webserver/webserver.py diff --git a/README.md b/README.md index a8cd56f..35c155e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,24 @@ -# OpenPLC_v3 -OpenPLC Runtime version 3 +# OpenPLC Runtime version 3 +OpenPLC is an open-source [Programmable Logic Controller](https://en.wikipedia.org/wiki/Programmable_logic_controller) that is based on easy to use software. Our focus is to provide a low cost industrial solution for automation and research. OpenPLC has been used in [many research papers](https://scholar.google.com/scholar?as_ylo=2014&q=openplc&hl=en&as_sdt=0,1) as a framework for industrial cyber security research, given that it is the only controller to provide the entire source code. +The OpenPLC Project consists of three sub-projects: +1. [Runtime](https://github.com/thiagoralves/OpenPLC_v3) +2. [Programming editor](http://www.openplcproject.com/downloads) +3. [HMI builder](http://www.openplcproject.com/reference-installing-scadabr) +
+To install: +
+git clone https://github.com/thiagoralves/OpenPLC_v3.git +
+cd OpenPLC_v3 +
+./install.sh [platform] +
+where [platform] can be +
+**win** - Install OpenPLC on Windows over Cygwin +
+**linux** - Install OpenPLC on a Debian-based Linux distribution +
+**rpi** - Install OpenPLC on a Raspberry Pi +
+**custom** - Skip all specific package installation and tries to install OpenPLC assuming your system already has all dependencies met. This option can be useful if you're trying to install OpenPLC on an unsuported Linux platform or had manually installed all the dependency packages before. diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..ed4c88b --- /dev/null +++ b/install.sh @@ -0,0 +1,253 @@ +#!/bin/bash +if [ $# -eq 0 ]; then + echo "" + echo "Error: You must provide a platform name as argument" + echo "" + echo "Usage: ./install.sh [platform] where [platform] can be" + echo " win Install OpenPLC on Windows over Cygwin" + echo " linux Install OpenPLC on a Debian-based Linux distribution" + echo " rpi Install OpenPLC on a Raspberry Pi" + echo " custom Skip all specific package installation and tries to install" + echo " OpenPLC assuming your system already has all dependencies met." + echo " This option can be useful if you're trying to install OpenPLC" + echo " on an unsuported Linux platform or had manually installed" + echo " all the dependency packages before." + echo "" + exit 1 +fi + +if [ "$1" == "win" ]; then + echo "Installing OpenPLC on Windows" + cp ./utils/apt-cyg/apt-cyg ./ + cp ./utils/apt-cyg/wget.exe /bin + install apt-cyg /bin + apt-cyg install lynx + rm -f /bin/wget.exe + apt-cyg install wget gcc-core gcc-g++ git pkg-config automake autoconf libtool make python2 python2-pip sqlite3 + lynx -source https://bootstrap.pypa.io/get-pip.py > get-pip.py + python get-pip.py + pip install flask + pip install flask-login + + echo "" + echo "[MATIEC COMPILER]" + cp ./utils/matiec_src/bin_win32/*.* ./webserver/ + if [ $? -ne 0 ]; then + echo "Error compiling MatIEC" + echo "OpenPLC was NOT installed!" + exit 1 + fi + + echo "" + echo "[ST OPTIMIZER]" + cd utils/st_optimizer_src + g++ st_optimizer.cpp -o st_optimizer + cp ./st_optimizer.exe ../../webserver/ + if [ $? -ne 0 ]; then + echo "Error compiling ST Optimizer" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[GLUE GENERATOR]" + cd utils/glue_generator_src + g++ glue_generator.cpp -o glue_generator + cp ./glue_generator.exe ../../webserver/core + if [ $? -ne 0 ]; then + echo "Error compiling Glue Generator" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[OPEN DNP3]" + cd webserver/core + mv dnp3.cpp dnp3.disabled + if [ $? -ne 0 ]; then + echo "Error disabling OpenDNP3" + echo "OpenPLC was NOT installed!" + exit 1 + fi + mv dnp3_dummy.disabled dnp3_dummy.cpp + if [ $? -ne 0 ]; then + echo "Error disabling OpenDNP3" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[FINALIZING]" + cd webserver/scripts + ./change_hardware_layer.sh blank + ./compile_program.sh blank_program.st + cp ./start_openplc.sh ../../ + + + +elif [ "$1" == "linux" ]; then + echo "Installing OpenPLC on Linux" + sudo apt-get update + sudo apt-get install build-essential pkg-config bison flex autoconf automake libtool make git python2.7 python-pip sqlite3 cmake + + echo "" + echo "[MATIEC COMPILER]" + cd utils/matiec_src + autoreconf -i + ./configure + make + cp ./iec2c ../../webserver/ + if [ $? -ne 0 ]; then + echo "Error compiling MatIEC" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[ST OPTIMIZER]" + cd utils/st_optimizer_src + g++ st_optimizer.cpp -o st_optimizer + cp ./st_optimizer ../../webserver/ + if [ $? -ne 0 ]; then + echo "Error compiling ST Optimizer" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[GLUE GENERATOR]" + cd utils/glue_generator_src + g++ glue_generator.cpp -o glue_generator + cp ./glue_generator ../../webserver/core + if [ $? -ne 0 ]; then + echo "Error compiling Glue Generator" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[OPEN DNP3]" + cd utils/dnp3_src + echo "creating swapfile..." + sudo dd if=/dev/zero of=swapfile bs=1M count=1000 + sudo mkswap swapfile + sudo swapon swapfile + cmake ../dnp3_src + make + sudo make install + if [ $? -ne 0 ]; then + echo "Error installing OpenDNP3" + echo "OpenPLC was NOT installed!" + exit 1 + fi + sudo ldconfig + echo "removing swapfile..." + sudo swapoff swapfile + sudo rm -f ./swapfile + cd ../.. + + echo "" + echo "[FINALIZING]" + cd webserver/scripts + ./change_hardware_layer.sh blank_linux + ./compile_program.sh blank_program.st + cp ./start_openplc.sh ../../ + + + +elif [ "$1" == "rpi" ]; then + echo "Installing OpenPLC on Raspberry Pi" + sudo apt-get update + sudo apt-get install build-essential pkg-config bison flex autoconf automake libtool make git python2.7 python-pip sqlite3 cmake wiringpi + + echo "" + echo "[MATIEC COMPILER]" + cd utils/matiec_src + autoreconf -i + ./configure + make + cp ./iec2c ../../webserver/ + if [ $? -ne 0 ]; then + echo "Error compiling MatIEC" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[ST OPTIMIZER]" + cd utils/st_optimizer_src + g++ st_optimizer.cpp -o st_optimizer + cp ./st_optimizer ../../webserver/ + if [ $? -ne 0 ]; then + echo "Error compiling ST Optimizer" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[GLUE GENERATOR]" + cd utils/glue_generator_src + g++ glue_generator.cpp -o glue_generator + cp ./glue_generator ../../webserver/core + if [ $? -ne 0 ]; then + echo "Error compiling Glue Generator" + echo "OpenPLC was NOT installed!" + exit 1 + fi + cd ../.. + + echo "" + echo "[OPEN DNP3]" + cd utils/dnp3_src + echo "creating swapfile..." + sudo dd if=/dev/zero of=swapfile bs=1M count=1000 + sudo mkswap swapfile + sudo swapon swapfile + cmake ../dnp3_src + make + sudo make install + if [ $? -ne 0 ]; then + echo "Error installing OpenDNP3" + echo "OpenPLC was NOT installed!" + exit 1 + fi + sudo ldconfig + echo "removing swapfile..." + sudo swapoff swapfile + sudo rm -f ./swapfile + cd ../.. + + echo "" + echo "[FINALIZING]" + cd webserver/scripts + ./change_hardware_layer.sh blank_linux + ./compile_program.sh blank_program.st + cp ./start_openplc.sh ../../ + + +else + echo "" + echo "Error: unrecognized platform" + echo "" + echo "Usage: ./install.sh [platform] where [platform] can be" + echo " win Install OpenPLC on Windows over Cygwin" + echo " linux Install OpenPLC on a Debian-based Linux distribution" + echo " rpi Install OpenPLC on a Raspberry Pi" + echo " custom Skip all specific package installation and tries to install" + echo " OpenPLC assuming your system already has all dependencies met." + echo " This option can be useful if you're trying to install OpenPLC" + echo " on an unsuported Linux platform or had manually installed" + echo " all the dependency packages before." + echo "" + exit 1 +fi + + diff --git a/utils/apt-cyg/apt-cyg b/utils/apt-cyg/apt-cyg new file mode 100644 index 0000000..84a2d5f --- /dev/null +++ b/utils/apt-cyg/apt-cyg @@ -0,0 +1,673 @@ +#!/bin/bash +# apt-cyg: install tool for Cygwin similar to debian apt-get +# +# The MIT License (MIT) +# +# Copyright (c) 2013 Trans-code Design +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +if [ ${BASH_VERSINFO}${BASH_VERSINFO[1]} -lt 42 ] +then + echo 'Bash version 4.2+ required' + exit +fi + +usage="\ +NAME + apt-cyg - package manager utility + +SYNOPSIS + apt-cyg [operation] [options] [targets] + +DESCRIPTION + apt-cyg is a package management utility that tracks installed packages on a + Cygwin system. Invoking apt-cyg involves specifying an operation with any + potential options and targets to operate on. A target is usually a package + name, file name, URL, or a search string. Targets can be provided as command + line arguments. + +OPERATIONS + install + Install package(s). + + remove + Remove package(s) from the system. + + update + Download a fresh copy of the master package list (setup.ini) from the + server defined in setup.rc. + + download + Retrieve package(s) from the server, but do not install/upgrade anything. + + show + Display information on given package(s). + + depends + Produce a dependency tree for a package. + + rdepends + Produce a tree of packages that depend on the named package. + + list + Search each locally-installed package for names that match regexp. If no + package names are provided in the command line, all installed packages will + be queried. + + listall + This will search each package in the master package list (setup.ini) for + names that match regexp. + + category + Display all packages that are members of a named category. + + listfiles + List all files owned by a given package. Multiple packages can be specified + on the command line. + + search + Search for downloaded packages that own the specified file(s). The path can + be relative or absolute, and one or more files can be specified. + + searchall + Search cygwin.com to retrieve file information about packages. The provided + target is considered to be a filename and searchall will return the + package(s) which contain this file. + + mirror + Set the mirror; a full URL to a location where the database, packages, and + signatures for this repository can be found. If no URL is provided, display + current mirror. + + cache + Set the package cache directory. If a file is not found in cache directory, + it will be downloaded. Unix and Windows forms are accepted, as well as + absolute or regular paths. If no directory is provided, display current + cache. + +OPTIONS + --nodeps + Specify this option to skip all dependency checks. + + --version + Display version and exit. +" + +version="\ +apt-cyg version 1 + +The MIT License (MIT) + +Copyright (c) 2005-9 Stephen Jungels +" + +function wget { + if command wget -h &>/dev/null + then + command wget "$@" + else + warn wget is not installed, using lynx as fallback + set "${*: -1}" + lynx -source "$1" > "${1##*/}" + fi +} + +function find-workspace { + # default working directory and mirror + + # work wherever setup worked last, if possible + cache=$(awk ' + BEGIN { + RS = "\n\\<" + FS = "\n\t" + } + $1 == "last-cache" { + print $2 + } + ' /etc/setup/setup.rc) + + mirror=$(awk ' + /last-mirror/ { + getline + print $1 + } + ' /etc/setup/setup.rc) + mirrordir=$(sed ' + s / %2f g + s : %3a g + ' <<< "$mirror") + + mkdir -p "$cache/$mirrordir/$arch" + cd "$cache/$mirrordir/$arch" + if [ -e setup.ini ] + then + return 0 + else + get-setup + return 1 + fi +} + +function get-setup { + touch setup.ini + mv setup.ini setup.ini-save + wget -N $mirror/$arch/setup.bz2 + if [ -e setup.bz2 ] + then + bunzip2 setup.bz2 + mv setup setup.ini + echo Updated setup.ini + else + echo Error updating setup.ini, reverting + mv setup.ini-save setup.ini + fi +} + +function check-packages { + if [[ $pks ]] + then + return 0 + else + echo No packages found. + return 1 + fi +} + +function warn { + printf '\e[1;31m%s\e[m\n' "$*" >&2 +} + +function apt-update { + if find-workspace + then + get-setup + fi +} + +function apt-category { + check-packages + find-workspace + for pkg in "${pks[@]}" + do + awk ' + $1 == "@" { + pck = $2 + } + $1 == "category:" && $0 ~ query { + print pck + } + ' query="$pks" setup.ini + done +} + +function apt-list { + local sbq + for pkg in "${pks[@]}" + do + let sbq++ && echo + awk 'NR>1 && $1~pkg && $0=$1' pkg="$pkg" /etc/setup/installed.db + done + let sbq && return + awk 'NR>1 && $0=$1' /etc/setup/installed.db +} + +function apt-listall { + check-packages + find-workspace + local sbq + for pkg in "${pks[@]}" + do + let sbq++ && echo + awk '$1~pkg && $0=$1' RS='\n\n@ ' FS='\n' pkg="$pkg" setup.ini + done +} + +function apt-listfiles { + check-packages + find-workspace + local pkg sbq + for pkg in "${pks[@]}" + do + (( sbq++ )) && echo + if [ ! -e /etc/setup/"$pkg".lst.gz ] + then + download "$pkg" + fi + gzip -cd /etc/setup/"$pkg".lst.gz + done +} + +function apt-show { + find-workspace + check-packages + for pkg in "${pks[@]}" + do + (( notfirst++ )) && echo + awk ' + $1 == query { + print + fd++ + } + END { + if (! fd) + print "Unable to locate package " query + } + ' RS='\n\n@ ' FS='\n' query="$pkg" setup.ini + done +} + +function apt-depends { + find-workspace + check-packages + for pkg in "${pks[@]}" + do + awk ' + @include "join" + $1 == "@" { + apg = $2 + } + $1 == "requires:" { + for (z=2; z<=NF; z++) + reqs[apg][z-1] = $z + } + END { + prpg(ENVIRON["pkg"]) + } + function smartmatch(small, large, values) { + for (each in large) + values[large[each]] + return small in values + } + function prpg(fpg) { + if (smartmatch(fpg, spath)) return + spath[length(spath)+1] = fpg + print join(spath, 1, length(spath), " > ") + if (isarray(reqs[fpg])) + for (each in reqs[fpg]) + prpg(reqs[fpg][each]) + delete spath[length(spath)] + } + ' setup.ini + done +} + +function apt-rdepends { + find-workspace + for pkg in "${pks[@]}" + do + awk ' + @include "join" + $1 == "@" { + apg = $2 + } + $1 == "requires:" { + for (z=2; z<=NF; z++) + reqs[$z][length(reqs[$z])+1] = apg + } + END { + prpg(ENVIRON["pkg"]) + } + function smartmatch(small, large, values) { + for (each in large) + values[large[each]] + return small in values + } + function prpg(fpg) { + if (smartmatch(fpg, spath)) return + spath[length(spath)+1] = fpg + print join(spath, 1, length(spath), " < ") + if (isarray(reqs[fpg])) + for (each in reqs[fpg]) + prpg(reqs[fpg][each]) + delete spath[length(spath)] + } + ' setup.ini + done +} + +function apt-download { + check-packages + find-workspace + local pkg sbq + for pkg in "${pks[@]}" + do + (( sbq++ )) && echo + download "$pkg" + done +} + +function download { + local pkg digest digactual + pkg=$1 + # look for package and save desc file + + awk '$1 == pc' RS='\n\n@ ' FS='\n' pc=$pkg setup.ini > desc + if [ ! -s desc ] + then + echo Unable to locate package $pkg + exit 1 + fi + + # download and unpack the bz2 or xz file + + # pick the latest version, which comes first + set -- $(awk '$1 == "install:"' desc) + if (( ! $# )) + then + echo 'Could not find "install" in package description: obsolete package?' + exit 1 + fi + + dn=$(dirname $2) + bn=$(basename $2) + + # check the md5 + digest=$4 + case ${#digest} in + 32) hash=md5sum ;; + 128) hash=sha512sum ;; + esac + mkdir -p "$cache/$mirrordir/$dn" + cd "$cache/$mirrordir/$dn" + if ! test -e $bn || ! $hash -c <<< "$digest $bn" + then + wget -O $bn $mirror/$dn/$bn + $hash -c <<< "$digest $bn" || exit + fi + + tar tf $bn | gzip > /etc/setup/"$pkg".lst.gz + cd ~- + mv desc "$cache/$mirrordir/$dn" + echo $dn $bn > /tmp/dwn +} + +function apt-search { + check-packages + echo Searching downloaded packages... + for pkg in "${pks[@]}" + do + key=$(type -P "$pkg" | sed s./..) + [[ $key ]] || key=$pkg + for manifest in /etc/setup/*.lst.gz + do + if gzip -cd $manifest | grep -q "$key" + then + package=$(sed ' + s,/etc/setup/,, + s,.lst.gz,, + ' <<< $manifest) + echo $package + fi + done + done +} + +function apt-searchall { + cd /tmp + for pkg in "${pks[@]}" + do + printf -v qs 'text=1&arch=%s&grep=%s' $arch "$pkg" + wget -O matches cygwin.com/cgi-bin2/package-grep.cgi?"$qs" + awk ' + NR == 1 {next} + mc[$1]++ {next} + /-debuginfo-/ {next} + /^cygwin32-/ {next} + {print $1} + ' FS=-[[:digit:]] matches + done +} + +function apt-install { + check-packages + find-workspace + local pkg dn bn requires wr package sbq script + for pkg in "${pks[@]}" + do + + if grep -q "^$pkg " /etc/setup/installed.db + then + echo Package $pkg is already installed, skipping + continue + fi + (( sbq++ )) && echo + echo Installing $pkg + + download $pkg + read dn bn /tmp/awk.$$ + mv /etc/setup/installed.db /etc/setup/installed.db-save + mv /tmp/awk.$$ /etc/setup/installed.db + + [ -v nodeps ] && continue + # recursively install required packages + + requires=$(awk '$1=="requires", $0=$2' FS=': ' desc) + cd ~- + wr=0 + if [[ $requires ]] + then + echo Package $pkg requires the following packages, installing: + echo $requires + for package in $requires + do + if grep -q "^$package " /etc/setup/installed.db + then + echo Package $package is already installed, skipping + continue + fi + apt-cyg install --noscripts $package || (( wr++ )) + done + fi + if (( wr )) + then + echo some required packages did not install, continuing + fi + + # run all postinstall scripts + + [ -v noscripts ] && continue + find /etc/postinstall -name '*.sh' | while read script + do + echo Running $script + $script + mv $script $script.done + done + echo Package $pkg installed + + done +} + +function apt-remove { + check-packages + cd /etc + cygcheck awk bash bunzip2 grep gzip mv sed tar xz > setup/essential.lst + for pkg in "${pks[@]}" + do + + if ! grep -q "^$pkg " setup/installed.db + then + echo Package $pkg is not installed, skipping + continue + fi + + if [ ! -e setup/"$pkg".lst.gz ] + then + warn Package manifest missing, cannot remove $pkg. Exiting + exit 1 + fi + gzip -dk setup/"$pkg".lst.gz + awk ' + NR == FNR { + if ($NF) ess[$NF] + next + } + $NF in ess { + exit 1 + } + ' FS='[/\\\\]' setup/{essential,$pkg}.lst + esn=$? + if [ $esn = 0 ] + then + echo Removing $pkg + if [ -e preremove/"$pkg".sh ] + then + preremove/"$pkg".sh + rm preremove/"$pkg".sh + fi + mapfile dt < setup/"$pkg".lst + for each in ${dt[*]} + do + [ -f /$each ] && rm /$each + done + for each in ${dt[*]} + do + [ -d /$each ] && rmdir --i /$each + done + rm -f setup/"$pkg".lst.gz postinstall/"$pkg".sh.done + awk -i inplace '$1 != ENVIRON["pkg"]' setup/installed.db + echo Package $pkg removed + fi + rm setup/"$pkg".lst + if [ $esn = 1 ] + then + warn apt-cyg cannot remove package $pkg, exiting + exit 1 + fi + + done +} + +function apt-mirror { + if [ "$pks" ] + then + awk -i inplace ' + 1 + /last-mirror/ { + getline + print "\t" pks + } + ' pks="$pks" /etc/setup/setup.rc + echo Mirror set to "$pks". + else + awk ' + /last-mirror/ { + getline + print $1 + } + ' /etc/setup/setup.rc + fi +} + +function apt-cache { + if [ "$pks" ] + then + vas=$(cygpath -aw "$pks") + awk -i inplace ' + 1 + /last-cache/ { + getline + print "\t" vas + } + ' vas="${vas//\\/\\\\}" /etc/setup/setup.rc + echo Cache set to "$vas". + else + awk ' + /last-cache/ { + getline + print $1 + } + ' /etc/setup/setup.rc + fi +} + +if [ -p /dev/stdin ] +then + mapfile -t pks +fi + +# process options +until [ $# = 0 ] +do + case "$1" in + + --nodeps) + nodeps=1 + shift + ;; + + --noscripts) + noscripts=1 + shift + ;; + + --version) + printf "$version" + exit + ;; + + update) + command=$1 + shift + ;; + + list | cache | remove | depends | listall | download | listfiles |\ + show | mirror | search | install | category | rdepends | searchall ) + if [[ $command ]] + then + pks+=("$1") + else + command=$1 + fi + shift + ;; + + *) + pks+=("$1") + shift + ;; + + esac +done + +set -a + +if type -t apt-$command | grep -q function +then + readonly arch=${HOSTTYPE/i6/x} + apt-$command +else + printf "$usage" +fi diff --git a/utils/apt-cyg/wget.exe b/utils/apt-cyg/wget.exe new file mode 100755 index 0000000000000000000000000000000000000000..c7e47a733b05059a53fb701c8782ee8f98addd18 GIT binary patch literal 252416 zcmeFYXH*m2_dlAR03itwAV7f7L3)$kyMUxXf=U&X2o}^tKxzyv3_(QfC?Ke)s8|pb z6hcQ)K~Pads)`04q9UM_{CU3L-*4Uf>b|_|zPM+t*`KrbK6B>m&&*n9&dff6+lxU^ z5C{a@IK*NQsBr`TEw2BO|IcE0!;MjYi~&86c%jh<4tSvv%-nOBlz8Ys+@a`wq?qXa z`wy^4J9m)|vG?e5!(MbCa#O^YYmX_51pROfs?4NC=2cP@j!+J~TIkye{#g^^o z0yj{@FXEine~^4GU;`D|KL63T(nHRTZRo!2h;yop;B(YHG0cDa_}>wey+EJ zD|Gr_+c*ddmI5O{pz)1}aU0fFI4JS51PIg*2Z8D~@ZYHawL|{P$42cxy!?xx)(!u^ zzK!xPU;k15qi=}+vHuVJ$NO)8vEct!|KF4$lC{CWMmzKW zX#aBYZ~Q|W`0qpTe=Dy4ZD;Wx)4##}%h3impyB^A@E`kzaNS_%f9wB0{(pu6a}x_Q z(8hh%Kuf@pFZ;va?_6)lQ_hnB?RmX%|6C*8vy}< z$$$)+(r|5UiAtW4P&DFp;Mu#i|eACN0c&$9J+deEl=go+o|n^&M<$NsUhGB0rB$!UL^ zlC*ZzVaZ#1yV7 zvlOvdyyO_e8g%qvy>d)pJ$Ky3>UKa#~6`M z;&w{9a@%2?wM)zEsR=iDq;wnMWiviHi|-itRwy-^GkOiA?s)2N)q1vb*~QEEy7izx zE-WKEkD~^gQ4u^J!eJ}9W<&`G5^ZgOF*+0#>T`ZunoY6)eoNt0Ok+R4HsVFIk*0Dh2#s$Znb`X!idUXYTLr|(pQcz+c}zH3-4Mu+F_4h$9SZR z#lTdnH$MQ^&&TryCb@rOk|ejJ!5aFU*F7?(xqo8d#{%k85Bpm7kP>=iQobl2QU_y? zdGgf}kH&X9@Pg2Owz`N%#s0Qv*i$JxS4G99QG~kN^<-2iE)tXVr_9JUp`^`9X6GYB z?}zuV?t5mTlh8qFaPN%!Sh`4Kd3Q0nIWI5fQETF_hv>^oKOTa443z3(Y4dn2A}9>O z`MW=&fsaOOO;}Jlf2`266)6H;zXQZdxe{$IP~bps3x`eL`B<_9a@UVHfK>C{boS?a?M`3}^nPYEn=NUbwpL5oo292EHmQmCmF@+5F0tk=+I z(5eFnrLzI4rG*9FVDDm%YKrcm3{l`dlg+NIT~L4PUTdXeQrnzOz4R)=WpO4C(m-$!S4Muf+w(SR96O1+gdaSEfO4+%7`W7m#DkJB$-FFD7yXrORSR zLH1qoIbD|TBGK-i`4$LM#T8vw;*xxtJ5ORC(19e?lA9?Ob8PWPUK|AZ_qfM>xv zcM!FvonVq}&)yR^tH4q!({JQorGXFQ2*dka{S+Tu39XYZ*03S7{8y%rl=$3rTY=G2 zRQ5t3L^<%b*%eX{rU&)`^coa3e?v0;W)?P+DNl?&UjhPu*tK~5O40#gq()q3%;>`z zN@-q_YlhG`CV41(x3&3v5(c`C6kpA<1F^h8A(0W`maRLE2d*5OXa^QAqA>*6TJr9B zt`ADF%h{p$H|`ZeX5{qqFUZzHS-jkU?sWylLyz{pFh7c5<3B4p$v5A!eo;N$?|fF* zPWixr2UqLgK0_qvzK_`S5b^QWp7U=>5!>;Ypxr);nVp+Ks$eh#3WKX6kSGQ5@cg`l zs-%PzS{ehE#^PLLWMx(5AnB{(=c;&l1yw~=f|7!=stSzA_j^aUwdeF)LkU7tDW(do z_W4!Pa023kg0dJa0ftCGr5#AmC14V8xD4VzPvJEkqy%cL5Jncu|M02l$j5DkrGwk) zfM`l2ebbroNCX0we_eURh!F+5Rf6md)KEE#@1@c@SsI|t@nmMjduA5uNK@+ci9$5b zdh3A-`FN^ZO&4@JiaYz1vD~t?6TiFGfH5NhKEA%2)CTW9C5zSuP)8B-T@E*Ldf7)} z@kYQ5dPOXjie~u(zk!|trGi0wH8wH(H49&`4NMr5Kqg0k*_biNm>zrlT8kJYCxol? za^H)2EM?BuHTMx>Gw4;w!R2_+cwSOncZLC8sA$RjXpWOxA5Rp;gX1A4%Qo|A36=Uq z7TXv>dHfsS zM&RyuuJsa-DInRt>PE3V@~MJ@DBT_i($VhC zY(je;!HTY(R6c)q5BG|`K2Rt|_ovP;1AHic>4VDaR)W@Bo-r{Xoj8XrrY`kgA_%nF z+`65<5Pm$5XrFA~kAkUFDjWCS2l>1UWhtkj`*6hlnImq|{m4cL{w1w2XFoEST4}<$ z-OgXT$b+N@dCB%)P%X~GNO(3%I~9Wo>rmNJ?z)(zN(U}!n3rMboNE!>M56n>W05gWH4rKPOVAnmg2*P`8 zv}!jfEBv+~Ku@di?2dNyI&ueBOt)NQcfXMd?bLbi#Wm2hvhlEWlu&PxQaB6Sb}sr2v{)w*7;G2VtvNJLmK8Y z>T4>sTEDJFvf!iKVXXSt#qIj#;)LE}jXq6W^S&Fz!jfH@dt4V5ti7qE)au!1KB#gK9$i(w*7lyu zb2=;9^ZOm0)owBj_v~&#T|GPX;=ZdUZ4Q@0yEn^uzS ze^@h&ZlG1&G>9|qI$BtTB`?u&=4y1LD^KFi`K8P4N4xNU*jTR_8a?`m+y(TvfJwIY z1G%T~9F>XQPZbMAwAmwt0vz0--5bLk=l+AqKpotQrUVdqVmLrt!p$y}Hnrp+M`q%2 zO;MBpG_d@`!8UZ(0n`l``^vS#y!}itnEBuE%#_PN6tO+}ntWLOcAgEn+edoV-2cEi zo}k3I#dcsy4_(kz1qT=~*L=E23`jV1@dA#mrp*K0a+y=>#{?>hqIg(0;*f)5U5=8W zV2`3Q;<9BbvglZnFW>Q2aoN?#lKn{@cwSgMUfbgS8T)Mr}K8VYcM zpTRE;0A_w#&+(uZCMyW&2i9K^l8ffWvMXH0i!&)bz^3WP7fMboQy3JllZ zS2~&*vQ+F;tuC|W$mmSR#us*byWu1?zzdv?ipQlS7j6o|Ql@Iei9f$(9Dbn7y$rB% z4!z4vtdiF%pS@ZcM&z+;g>0AhR521z;Dz9XP;*=_{<2IB z;5_BiidE#L*Gvb~kWL%U{E)18>IZDxV^@4=UK&;FQtbu*+E zfb?eTcF)bUtN`Hzih%?76@=&ThpNAA^OK#%%WdK~ed^P+qlz@QgbF{Z$RfCob^OGlMTy z2s}Jtw-ReNkJ27kmwd3N^M^w zie^hM8?xhEv-IMa-V6K@5Taoz_DZOxUt+PhLZvd&iB1FodVdDc|$3G$S z@-txj*b?t3taiD2n_&83RttB6tEX5;r8~%9d#D4l4L$c%bkGS@a^O*ijlF5AUVdg( z^}4wJ$jOWOnn6Tm_-v-6N#ponsTTr=62eTD#;wt6O+?kxR2h`T-q6VxS+`DW7CI+U z&L@%PaFPb7L84=Bpx%qX;(*?fl|=i|M^7oUT(rS&y>T%Q!uJ+)m+i253d;q>%jTl} z(KnBr8b*Ka?Qqnh1~*FtP?E;SyT>qp)#CFAix9}?Way_R&$&Yj%X%s@Dy7DGkM-LC ztsHI^NEvJ&k$dyi@(;he4hRkVFb?D-_XV@=IAw*0DpJd&9xY#LTd`x$r0v$oR{eY| zaJp9Vz$b?u`6LRnPbVkg1Q)-L2Fowh6z$sF=G?A(DRsH{SouNAEV$u zqB=8C@1k6DB2jI74xqS}^?OhjshS-w5mK1b?ysLX7~q_q=5hE(mwcb-f*tSgW9%c3 zU-D71emY>u-}Uu%63%p)AhjJ@v-h7sLMn#2h6trE`G#$ncWFaQWF3{`W(5N1y#SX% z^6ojdt+Hvl5qWxNNuZ>sPGvTkfp+UYO1VNhBmcTD6&XOuBWE6E;gydy?{GLmRXw4! zV_JKL?U=p@^DyRltNBsa4-NbD&T8umU6OFrvMm~t5Bh;tZD-j4c?qMtXDiNSWrErr zhOvD6Uq9NQ0%gS)FkzIp)?mN;t^!@@wNVsx#T@fLWL|lO0Z>E@`zFzpFvnhjfVxG)g(DJx| zf_jYNTtX(^ZU3<3RYvuj)f%%oT6bhf#ImO>;(~ilEVW)v^2a%4x6vqinfmZCiLWlz zT34R!|69D|;q;MA_TgdE!^Z752b5A5K_n$L%$se8%ZezwG;5Cw*{?qt&+E;Dtp!5r zZ1$aYQYfx)l{N+G@%V`_{TyorSihJL`{~WI4!lBQp{N6!32EU%M8$_W34=$b@?W)pq}Oz_nsIcUt<(ZPfMHYefhcA{`M6H1ilY~BEewfUF>}%45q0Af+N6g z{WrRr;xM2{YzTNN@+Trr2l*2nri3RrreHpH2PR7637|GLbJ@)D##(3jDZ*i7fFbQv z%y90?1NIT7u597Q(sTJ3k$4w(#+GI0%QEm~Z$}!Y=v+Ihg2EIzHrmVh&Q~8{b(u*I zoTUrn5*UkdM#=+;hxai(GapYzox+2FbhH$Vtqz2lU>AIh>vC)+nH{=b|u3M_p4@0G~Dt19(u~Z zK^w&jT(G?4@SJw#cDV#AO<~iT(9&d~V(&IutRp=&AscGF5(2OB)=LMqN%iffbUr!g z0%fGSoq54(}!N#DmFc z4=+4xJ#Q1zTG|0YRS-u1mXghU5)D4a6fF@WnlIvyRt2FhR)jxFht^#zJH5BeSF-P& zGJl!mJU_PML%Jz2WMTM+7xK{oSaGIJEdhV|JwnstY2_^hi@N*N@I2|Q_J<71YQ!Ib z@QeRUmaC<=-uKrBXhu1Wchr5He{|B$H2TcCG`1@(C{}c{QI%Q2s`r;h!dF`zUa=+K zXR8sqdFjh6U%iuit^Tq+?b2s-K6gYdPUX$I)OLjk4YwoFha~H8*n~#vIQ`HJy6zfj z$*r004NhNdu_1ck%j+E8u`Da=TANssi{lgjym=t|?YDc-79-t(C}xAgM_Fd}VBPV& z?fd4(52LS9ate)Bn~$P<$c}P`bagoGTW-C&`YM%~mCe{516px;%^rTR^hsrL=`H6= ztSeMBYI>Jl&C=S{kkX2sP-3(eaU#kz#$XY`=W9A?S19qUn6Yk~Xx*w2u(p0euC1 zrrgi>1gl`_S3J@;10Uxfg{}#f+3*$+xQxemB>$>7ohU>}zcjBa^m_iwXug9DRq9yo z>w6$7Tyh*564xAnG#~mI(H2;p(|i3nImrvd zh|bQF8sPJTuc<%T3WfS8wzEHS_wedJO|D5zkG+F6JrKMYARh~9o^2KW4L%mmafgw7 zk>j6Q)=oi|`n3eSoX}h!e#k2Dil1}Ik3HnE=1{%#{@291l1N_k3413jXY~k#E#)05 zI`tKsQ|vC3P*<}X(n&!8)1knhWQ>R8=+Tmc;|c{dr$8x)9HmwP%qL6zc=J5h5i;og z4wKlkB@|duh0o0x`gXyfk{+t#7|JfkY%_YJZxOCmJ$zUmKs1Ecb0N)8J}=$8rc7g&MY)s zdpu~i*paX(ozrXcJAG(52|mP4pBA$XD;M5})QLwlJNRDHWF|@A3Sy>F6YGjq9qXFO z%D2Grvy?p_P9;8`mG>v_C3~4(f@b@F^}sEt&-z}9tEnoE+Ch1tv9W-_hmfiBpu;4K zvOg?e%q45owJb|Ff6vB?vD3(z8R|8&`ADI@|EI0EMKF%#Lp`POibHU`l1Pd#o6BJ7 z0y*}3v#(X$j_zAtrE*F06W=#s|Lm^@NA9vd$7jyw;F~E-*DdF9EEU({vl8>=uGC}P z`GknWhljnTYt>2uYx#Ad5$@*&Fh7lo*uzTKnaUNQfMtDE9~GGQlhtp1hlWR{w+i9R zKJ<@#Z^`&9})E^n-L2F{+&-$Nw{-oqV`VwUHw-ieMN6*pMt1O2r@PC_eoAw)#o z4fwh(t1PRKQH%tyv*5aGMQ4p2-(PWz9%{S2o3nnx$Z|mycK+jd_6YPot;b7tGG+Gd zxdj}iu0!HbDFdb(tNDwePiW;`yD#nFG`u5N-QNjj1nks(ZQcY~ZkxG8OggCxnG%Tt zXX1C%HcCgYUU*mapSDaM={;VMeWW;?7j%q`pY9QNzo=BclPt0vQPw)# z2p;iBuJ=#p1nN? zFY%nHULf-ke9pSjW)_&pnF@@Z20w>eXCv`)Id2!_QJBR5_S|+>ieUoN> z*tBPBnjA9m!3@@DXS&oyTuRD?q~8!8G7)EJ%#y{L1dd#rlk~R{qUDqkZ~p-YN_xy> z;*<6$kKb%kiI+%yNM6E&q0Zp-ZLhQ{S}RG5Ckk;p3tZ+GAz;NU52JV!kB*6(@@>Hs zQ>Ss6{dU>+%$D`Eo&_^SN>=>>RWF)iTle8fS>W&QAAIj7Y6DyH+8=+T*I-{jdjHH3 z)G7dhcJWX*7YMs~WTc_v6A+GzBB_78b0-Sf0)h1-EX5Ap)&bDQThYYp_@bL2Wb3E% zS6&{+-zD@DKNg;qwt2v~-@aoqgO`ftK`)<>c;;k-O3brJo!0=JvMX6$u>S7-=DVHK zW=q2~ZJ#$*<_31D+N{$8B83le(zo4y=(AoQ+E8p(0@Zgx2_+m3=K}3{sDTdXy)4=N z$z_*OM5LMAMFL3u(xVa&*pW!rVn%!R^>Y^iy{>%FDJ{^-#HKb|y#~v&@V#Vn^^n#* zW%>@Er-_6gbB1rJ)=VS49HH9#Uj&~tv9=xoeYzRAor&s{-G>`SFi!2p4hF%+v>^`8 zvX>V)3xH}$LLCxC&}%g?9{Hhl?2b*R;nfa5KJ2PMe=OUthtLD6eK4E)^d+Ral3ioB zVi;&t$ET8OP-8N;wfu>^f@GAKQi83G3DI%Ks}(|SHvH2_d@L+4F!V>UP3)vSCE2?4 z6LV%M@a9y7X&K;+B#+#usn%HE^`=qz1)dzTOvh&Rq$W}A9?YNR|1fQy^dOP{p#VK@ zD@*VBrzA6Lnl7vKQV(kNP^dI`aQre$ySvVNC+%7xnwKX;Tl}BayE1@vDzRjByE+hH+i_>SMT-H@$LZ zq0ZKb(6b25F&YZ$c;fvU{J5^qQu@YP`FRgX27F;TNx2!$?Scc#_hG<~pf2GI@G_g2 zPGqT#oQqT`Eb-&$uS7erC$pSQ@?L0qURvwu>I8*^05hD=CwhT(;bxO<`_O8> z#h+e1tn+Xv)(LkcojPXu&)tl5R>qUGl+#X~>pfEZz}Nyh7D0Bznzybm5V=ym@Dv67u*| zq)Ax<>dfru#JCDVo$F}Nj;3R=U!<fI!D3rhURm-}II9gDme{ zm$U<;ZhX%cV1P5(G~`H}4*6rObJe@8%n^xZ2bMY~b4=IY-bWTJi8xm2n=+O0SG#l<~kTf?Z z1Nbac)AAQ1T5x4nzG@h?rW3=Zt?h?U-QZC7TKfkvm9EX*a1r*Wg`~NnBTJ4vx+58^ zd?~t8z3Z8V*G1|8sC!%vTU z#yD3NIrM0Bn4k@Iqv{2CtoJ`h7<8!7T>HcL&Sg1_II^CywMrIsZ1$v#ePL=KAg}E} z?~Do!Dwor=_$WQ74SH7?G?`G(oz>PfBb{Ex@bz7vX6bEb63ukx9~25~vlT@HCO;qV z7u&z}fN|D~y$^ked>Y}0cf^OZ^Sh`s2$P@b&e~&@Z7RElL{|UAMOE%)lYHoYJc)=$ zGGB<5Oy`kJfgh+ugYH7HnVVny4r(J^alNK?Q?ZZZAC4&Rm2q{P~ zi>P5(`4Ao&Qo+V%_<~0@LY&fIZ0MDCM%IfCgv)d~irz|58NkkF{#a>LZ={ES`7Ftx zt&pW}!1A3eahqU99ooC&XcmjjD6XcUy;x4aSal%0|~l&Q^wgMztzY9uK>GV~1v&#v_N zX$B3Lncv|*9-BRlzuXD2|4>R%7M;AeSLzMv@~$xVF#J=*fKw#UiH_7sTT>?J-{v@V zA*#%7uzwv%tnx(J79bcka$;f5eV%6{bmIl4rT=M@MMOLj+iB)q%gfmhvvKuOeED1b zYd6Y+Bc4eRLT(i<=dP?k*?wm#(2hxa@9cerMrX;g7^L$RjZ z2_u1x^CL7ihlZ?7)^*xbyWPk-n;w^PO!|RJuZC%g-kkQN0yJWilv0Y`L^#C|gy-xz zIsW@nK~jLQbqe-rfvy?mg{G&Y(k^;a_4m>vamKzR2KP)HO&-1JuUVAdFg-8?=kw}P ztNAy6$ooQm;6uCYnx&23k&@XL z&1_)LZ88IED0#k5RAk~tMAT7{wbHvgyzWiAdPFSG3R^Rjo6t4|()5kqUKysk@o55$ ze~|qB8|dUe`U(l+YkE$O(vA1;wrZ+XZ+fsqcC9_At-@pDJYJbN`_Djsmf&>dptpw) zw!Wk!#_#~-lqZ^fd_}OeoJ0G{Y@AF^N)$l6PLhbc$EHztAkr$p~3V@V6y1 z%epHE#-9guKF=N1ux!yjN?D3pV!jLhOQf{aTn{=wo~T=`{ouNCejE~LyT!kfobvFl zn}<*}+C3{|rinXB#?;E{6gSW-@dF%B`jg>8zb(+;*=!_Z@-Zj-gnXpQ@Qu610)Ne) zVK(m1IX++?7WBbpm*-YQ0LmXaTLWikHQGFlRE7fGI}AIwxrTd7xyAJdy1=fq;Fi0^ z{R)Qt+({AV@9lJyU`Fh;GWd048pAU3!A=GJZdsGqiLqVctiO_nQQUE?9mdwpJBa-x zlB9~e6s@LR$rAl&lN~vJ`N9odZ|KY5Uq?hPQ{ntbQ8#?NNU*3Fd>;Nw;U?n%R&)cY zB(=&Ume84avMK_$f0M>1oIh+!mFC73k%RrQ-oiWW4LBQW?Ec72^t;@Dn$ z(3!sqGsqkH8aaTfH-Jn8VO6e5(XS8AM?|HyX1-_7P@aJXAN}acOL|(|c%L%Q~zR#S)ot4+mgM;!Xdmc{$% zlip%_ugF523CJS_Izg~)nJC594{tx{IP&bRLFBsvNUD=eaWWh3b;0GE_a-rE+K6Gv zEbp2aVGey-A|Oa^v!{mL4{K zeQ~(*+(6^VuJMoUjN0Zlu5DF8pKhj9k*IEt`-B^UCKY^JTqG-fEJYW7 z$@a@Hti8Zq#MM(7*6eRw8z@`CHvB#e@?}(oZVEC!Np|>Up`v%lO~b{U|KQg{{9Z>b zf2A}T!9e>n@SmryA)t{kPamUuTQ`$|wPLB!Zf~a`3CmtT1Ibs>9YV#10`wwRJxv)I zJ^{YNl6MSqC_Zw(J|uOtJ=wrw^Y`#0ELgsTmowj8KOO#535Lzn6l>>@BT$MyOgqIq z#&7OP>e`nraD#()Z;%U1tilTzUv~c3d9Hv$MFQHlu24$IZ`IMZ zk~XBAd#nC)TC|WWXhsrBTSKNU#ltI{(bqGl>yX8D2(OS&l^g>pUc%eRK>mf5rwLeP=>ey>B}uXJGrA?p|4!{~>U zZ_KY##b;Yh;2~iDXo&*(lYrJdlz5#bAPyE zD7J8azA^+`7xOM#C?2yvkVDZP{smDVx{%=CnUxGBZ4SylB3Y?4q;QGp2v)c4P>L$@ zn;H*(%0Au&A5$H~-rce#@4h(s=xOBwv^N?|+nxUN*wWTjEK9+@=v~fXn9yiOO}Dm%*|Fk%ekk+_h5;D!mda8 zA@HsHGT*xHic0e0tdDO$^t$f#o7RBQIfUtox+WjrO80ro`G-O~ z=+^+U(AvWN9?4RpGi^=4*>@WhqZ_R@3GXq9cJGY$@($Z+;jSqsoHTJLN6|q4eDk}u z>eMaqQ)lySJxq3jtp(A9AZXdo^aInb;gBdV&KDG!nB4s6g>}K+L!Y>g@4?EI@C8<7N7*aiSyIG_Ezknp1wYHE za*ouTX$~NWJCeDu!qO=)yf3+UN?>H>ov-M&E{-_P9=lO##D;nc;ao91O~q%&pyav~ zBJCcnn{ANg5dhUKrxYk}Wg72IWhUOpuYM!C(b0v}cw$$4bwagSjw%O#9j(=aEq(L4 z6VxqJO9_IT5aqUyqp`&!!}6cy`KnlvLEq~!8Z%kou1m1NyLn^0Eo7Xm-#*tsfRgj#;y<>d7fhi1Icbm@?!yT2gkS5E58) z+F(3%BX28o5XNW?-?p3>e;=wgfC)fi#+pd$oN zW%bK&O6Iy&Z-0$K|2{^z@J9^rj-A;&&o0E<65BPD?Vo=gq5 z*DPcKO3l=Q?xT=lh5hAko`pvdZb6Gf3{Wpx<2XGg8WQEL$^v=m2a>Dn$07={Vihdg z>-?PfiJFd?$_3(u?q#hLfC6w^UrBp~JGov#AFAJ{pgLhtnW+s7GjXO4^u4sHoiXhm zSFCZ|ke#}BW_!<%B(_x3&+(p?)kZkx%nr`x)vjpr+SyLIB#iT!Hl?q5#BOb& z;)gx~%-<_)r;EqO>&l89lXML|9}`DgoYFTTPQKsdzWoJkkZ zj^NI^!b2IGt*3hiFyOz)t4HX)?ThBGYf3FK6P4fI2h?eV< zffs8K%aI>OnKz_be899t6%^a{G2;ms4Z+?EZg+K+!6#Z2v6*l=m@6M$vDcw)4b_h( zJ^r42veICtf(;9n{+e~na2chKewz(}nRpG_vsu3RyECkJq2x=iI-G{HHEcHvLR`#q z9pxAdrK~yl@6en%jSy6In2^4wMiL(u9lSS+R-b!ihUXr$%+LC3wt5>tu;X|LzRv|G zpY{8jv3Zt|@k4#+Ml4{w3XZ+!Mj{uEri*?^BMWG$rQh?kEo2Akq8Epmfza}c| zE2ni8uk|X7oBty3F|?IC7)yaskL)$|rkR_pCFpB+wI%bRjz^tJH+kFdC#zL{?CF1M zBXF(42@hWm8#o(2>KdbYrpU!D16H2ZMPiZ5rI|*ix4&P%+C*a#uh3MG1TcJ9ohcJ# z;Rb;?GYqc133aChovm;g5Ggn`bXYvaMY(J7_-OP zSE6}mY{|n`ySM=K;FWxoZiiegxHceq!#JdS=(5t zJ$41%^Ps2!o1^=>bDKeInJjMC>#Nqk6W9w4jq%OAeEF@1Rpe7%pE*A~atHjW+2p#b z8Qp>kM80{A9TS71|2(pPEXbdqefv3_)wy|mBO1BEp>7Migw4EeSObCMS1{!xPS zEf>HuN!AJc54#Fq`MsoDhc;3%>SsrOpj7o!Uy{ZR76Ki`6XVUFfT@mOO{b_RS5gxmljL$;%ysyC!Ecx3iQPYjs!u z!ht=rI|qVIiIct0^7-NZ3-j`Z6+_#Ki8EN1sRXi4Xd_ua17RU9sQdSLhU@<_=BDq2 z5;?Pm&&4BOB$UvcE^Rt(c?bIByrbpMZ`{8M;45U+6Z99T9N>E`7J=PmoO_9hvI>f9 z4PqvibM3p0W_2&^*sfwd9KT~}ULuZpWBqI>I6j=Fb8|~FsyX!A<gjaJ2`aPMMyPNw?1E-{p(#vmeDkNb*xSFmo`56a zzIdy!)q>$Iq^>2C7`c_f`ee(&AEI3M1BSnzpu)&n-)){t)62?0$N4@#HvXy9S=kqt zl>uz$4_R({UPZJWJNAq_>rVKgqWLNsceHdW;vKzoC7x{>{NYSYr!4hT!T(^L3ill z-k7fM$35O|Vk43d?{WnzlakMy>NE4xWvkpop{JR9x$Jyrqj?yu zFAiqF59yiiJP0ceu8)HND7&9l01-&RU7li2o1YI_Z#Gl(Jtfn(GF;NWNJMc}boXV|2Eg1zMVfRdhZtL%f4()Gub#?eS?3 zH9!41#cDIH8Mbb{@f3z(!OayslQWwA)#a^PVIEr4udG-#dWq&6oha^>Z%T>rRR4R% z4{`%&{t*YSnuRsc%Wdzw4tUrGF8@Rk6P+9`Yv@PZD0`($m1_sFEjtqnZB1S(vk2+? z4)(~8OM<^z7?{~tYrV1blI&5Do;9QU=;=+r($2HXUp&_MBt!i8r;S=_q@PaBVO zcS?(aAZ-eB$Skrj@UPDDnKF9PL+t*3j~=jvkmzv6_i|B(SCa1F%Ft}9JMsZuU-u^1B>RDX{9GF`1N*8Ed$Jr>oriSMwHv%Vf|McW=e}bw&fq~?;^}AWAA-a z6!lo)7u}*I=%_14Og8d1adp!1jVi5Q*4eQM=8j%&y7`ezg4sde!>{E+7N}&^Lh^#j zfSB$4%5aWzTY}79Htnv-F|w&A;I~eGF4ABN_<_S4Ic~}^s|*VHo{Ny`qxcfb+6TCv zey}gwdX^>AH5+?u#01f=`rsCdz$O7o@>PolWnROfPE%2p?@Jml11aOC*^6wf-6)Q2 zB*^vR1o+7Lpr|J_fYs2O*6EV-?+3sZw+jOeC&`=e%GaOITJPxicGozeJ4;i>QFRR8 zxXI(ovDW>j(y&C?!!n2Ieu`0ZTEaoUo$Lt)6>Q>#J=>&|90poyIQXVYe) zOru81(=%l zY(Fbg-eAA=8`x$^-{&9F3XPs{;P>pU*)SDqlg7&7Tn&1n_erG|>PwD02x}zRt zD$}7SyW6gHT2aX%D&dYvuR%{V9UgmbWU{^78=e&=kKzcGDn(IJG#y09HPh-CgJjrB z2&2nQO{)7`ADfb`@vu_b_d-1+#=U41hX_b}m_dEsBL;lo;2HBEBhA3uD& zIDW1$w`iF8L%3V&ph%*cIG@aLYL{;9Wlib>@-na4Y8*|CpK`POhgOwEZIuHdx5t;m zVY9;e2#OHi2zjahO)iEf=W`F(Tr;`sHmH-p$B)ESd;+%=3PdZn2Sl_<_ zcxW5f9*k+Kwl0tay^0jG?E7VHlbWW736yqJuP56Du+M&;j9+Usi)-~Q+RD%Q-c>P@ zE!aW~iMh{Fe8~yxHn@J`N+pJU1{v+Pi08IyHk<@2YrSZvY0Hr)!b@FliWMPfaE=yE z;f?L7Z_YPxi4z!<_N=}e+*|i_s1}-q?)xFKcIe3%m1n$OvgtLAqc9h2Dz`@ZMpR** z?$?|MZ`69P|INd-67)%ap0Ew}=y~JL-Wi)dPhMK+vYF_}$^U zqAX3Fuj1 zg#Zr%R>Y`KKUIq5PA&;A=qC=uY zAC3uZ_6=+@6rjf)5dS1Z1Q5&E3a;FaqVU=uJ33EfRX!t5Uf5sVzi3wa_2l7X^x!@N zynp^?3{whr_@;{i-O<)JoZei^l_EB`N~t8dj}A3u z%9Zoi|L}ZYujlzZ@6Y=?k5_c^!};EpDcgVH>-HJYxcC@CJI@b9QFMZyi!=OXo3UK2 zz_qoqifeGfftP zsrMJVH(rKp-_H{!WQqxx=Lmr+RM))Je0@{>mIU$=obFqnd1Wg9?pg(q+Gait7tAAc1{&C(N|9SSq7}-)sFoNc18ACI%OgIvC3usu-5vKO!=Qy!z(}U(u#m@1Z z^g+o31Ai>3C>@~6lgBDag9MD>9{z3&?%L-S3-e0Vp?KBZ0{uRG7Y*s+^0QC}a?*ho zqH8XnD6Zd`SujeSIK~qMRn;pbRA`?-aJ}Ab1_`RSP>u{eLHzZrC;h`&-@`05wFz?A zS8<+34zF=zu1;JJCQTp&p2R z?#}j}3%~tXW+!tC_4L(!%QCNB!!_a_{&2yIFvtDJ^h-q9o4M37kD71pS<=}e_j2@^ zKL{cXLu%mPN8Zl3GUw*E;?v&85Iqd;lL!CcCUNh+_+ft&HZ0#qL9QM#?+$mxgH}ql zyy>3X$igP8%0m%ks&5@SZBSadv^w1qm52Ok!PmTNHZAi}Z{PAD`p7Bs zQhViCzuGG*SI_SdOK6qlv%eVD7IbroVAHYlR>xCkJ0l*QI4%%x#<2?xxF{6ptXYQU z7R1G2f%i+;&Fv5L+T4LB;~%uLSm3U=FE8bv;k7cV10&1UE3&<)5%(PK;(J}eefZ^< z601HQy%2reR|jhFDD_b$gA)E;d7|*|jj^%-NTfaK+AY~Xb`c2;H60JDE_e*T zQ@kDCmlT0hHA$nQh6PSr%>5&X-wB3)FUwMR^Tyfj=D%kin;U&<_Qs!V2H3jb=bzft z%eoTyU%>@ftTcAN58P{;Dj zWfFZbzk!+0HJfV8-~M$xxOuJ9m3Gf#AN`j7b?%>wR2<7d8~R!BTCFTo4RZdSs9m^z zvTa~%uh9YIng?H{L=Ko}hL)N|h0hS)nz^?pGvrYG8cP>qyP(-54DoF?)MdnTwuc9LWR*~zAN@Tv=tL$; zNA^wvt65dR{Sj=+SGe?ao53y4W2<2>%YNTA%J;nlr$33Mu-_ZzAF-Sg7oh&(T7~g; zSwMMUB++G5+^74706fzFTR|yz3i)x`|MxK?0|70De?U{Jiw$VcKY+a{|I@5?*P(&= zS0EJ}K1=bI-1V+_kXB*`;(h^tL%cqEeAqIzYOM-dA~Ov~?!+>-QqrJiZa|SP=A6dv zRwuX&Vh?o!FL=`jta`!$y+@APOiemF;~}#awrJea$JsqW`X_fZKvF1N0X^;aGJpK; zmH-G>668HBJ`J=}r1N#NLkOaC;v>{k8-X#iQRmL@e5GqSJO}2V3J`1K-LNc_cbM3`Gfs)1S+rU%Ci^rm^)56;7=epkJ%IRI>S57L3W~)C>dF| z;eDSObUbT+AINzaZr{1p1Bz$Zkm*Nz^Tx5I_lg?fW$o`xXcXVFvf58G3C4L5KIw%{ zo+qeKAQ2W3Q)@Tw)ohkrrtWi|E`fL(5m=EP;gw*j{a9k@gQSEJQt}~sgiIVMLF^6b zMqm$!D$$l0W|nmAX7^@~1I?NqJwt^59#uKdo7qwwY9fO%vSS8h3vH-KEYO^+Y=qE; zZd?`(qgp2GJiA(%&{JSuLn33_Z;(pb&k z^Swx>%n{;6h*7ei7Aw*dJ3`mITf?QCY968ldv-2Zma+dKC9PM89^954y7?QC%@MBMhzh#XHy zEh9JnV1ioOwk4PP5tZR@X$Cx;);D^~-(06MXr@)>;z>U(jLvAtECbdvX>mwElNINZU@}Myn!u^CI$H^1u9Y39+@m z5hYm)`uIm)AP61hmlP5#F$9uBwOhpE7W0Li+?|a+{K9!UFKDUlof`&x4N&#>^Cg#E zfO-R9x=%9k5Gj`=k{nVM-Te_h;~HtWw&@X@r%=uJ3uM3$Z~g5eykbhtfwe%O(Q7?I zp8VDIzI4m;>YhhLXu4QMq0iK!_tGx4_BP8q$v*BE&wafVKP{$fR!s=E8~DvY!9u!D zODA{a1j<3-82t=RSr9zA=A|Q6@O6&SoSn$`tyEtPA1LKLz^}z<*|=jeH-B$0MFlQYcRz^AF~{QN{BSKls0ale9j zYRuQk(l3|p;RHZDSzyM*VKsA{)#2uQ{%!&-FyG@Lut<5k_eKE+0k#isy9R>6YW!5B zfK6Y)S^(WvnbMT(OWh1mku=yJr|A>mO-hzLqTXT#j7CW9to8+o0%kV1*@@aptvf3( ze!A0e{wfPfV&Zfim7SaC)PIPcFnsq$8S+=W#zPe3b6FmcV|VPsQ}n{K!p=R1$1i++ z{HS%-@7`gh(A8F)3fHl)lOZtwv|1G=-N*{iWqnaKp`n)=A`-QTW}~WczBUe~9n}&B zs!S@{EWJ8WqE2;T`q^nh{QwQ6@tXedgY-qnqlrsY;`t~jks2R{_UBClEUG@#zk*{H4i7`PoscebG+0*R-n309E~ z`E$BbswWu2=k7boZ*F5uK7V>r8Az}qU#~3`I3sA7xQ0ky?oTanlA@aVL_Mh<3VL*R z7Xj}N3Js>vMPC-Q8I!*$)$7e@*6d;BW%Atst~X~PwLXa~;e8yyoiD%?E_9Y+kGgsE zu94rCany~egr?FQCtLQAJz_#k_=PtfhYJ8%p(YSB(4?(}+eg!(DQTrgx97Je1xB-0 z468gBSxSa)IunINM8{Y%p4+RcuXl^>vu(?gfzcs;{b3BNmvM-4CO^BiDM#3)#<0)u zh1c2q3ndP0wWIXTGWTzlp!%oHY1dk?BBEMP=O=PV!bo_e-$8*J<)=N8YY8hB5t2t3N%BV~S#L&kCDVT(9PgWKL5-OpXHA(E<$bTntjzb0W?@S>F z&P-U#;>b=nQCyZV(`XR7U(y#MH`K0ll?AKuP|u5aujJ$OQ@iT)U6N_969h1fP=oQx zAACkvd~OUY+b>{AimGab$knHnUSjSDO6|?T!JUThxEqJK0)!G55Yb^f{swmrfqa|0 z!pH!BKx{+3n6EdSa8GYZ$xP?qUx(rQ-~V`umh5l2_I^WUA5Qmrrwv-Q{*2l~Ty|YZ zvEol3qJ(jsLMx4)dT4F&oB@yJ$da!`Rv#0e88p6F0V4sytHNkA- zZx~w$QUemWm~V4inm9;Pj7S*r3U06SxWW@8zz%!zZ|wWAl!ei}UB@uj$=iBw`p3uc z9UbYYciZaG%=>%n$p=@$lbgnbqi7(_juj8K(H-_{=?Z7TOt`ZiSINAO?rZ+M3x?m& zpotSFX%fyB(Sc;7;q{xHJLF^gkA8yQkVybMc<~{HVciI7M?mdXBLX-QxAUV-F&tAI zV2p?jOQ<<;Sv(R3^o}Te;-19YVzwkjDMG@CyJ>;J2b0grL(J+k6{h+cppH5;LGur0 zHVNnU=|*IX1I%w^C!yFnbeb(gx$Pij?jo&Qv!yb-5f2fA@_`aE?AW7o%Rt20P2e@~e4zUj#4);XcRLosm zuYtc019wgldft+hLeI6>jGaGl>Xc4>#+tvgG(K{<1ZlI}!}T@0u=d>k(WT(S|6RN{ zR)o{o1Co(%DbMEyA4DE+d}BL;Q@Pq z!26-va4ZL%j^_Pojs~!{{*^s_x%Z$&7~Z69Z5~rU>`l_FUF+up3q4|n26lp*B`ro0 z5SeEQ8A0#D+Usj+2XvFsmW#*#I^=BwJx~pz@4os{zTl=F;RM>XErQo154MxbXm>c?#uoSd;PI zPvqlng%ZW|aFKIe?yJoCtuSVnP0UH5yigFnb^qf$yqSb+xciqYha+SZ;S_=Xxse%! zt54APkBs~9$4(mNPNQdtv z_zi9ZM2MfpF9&eHg4n(CBHL2wS%^mV1f>jBo8if&pee3gDVZA-hZstfQ@J>B+Tnzmb#>Ph8nxa3^=;$@6sp&j~F*NFe804advvvNyQ1 zVD{U4e_7dWMyA=Ks6Th1cMcvBWdl3j?{YVLVx&6EfvG|^cDa8USV`{AhHMHy6>?73 zh9QT+bztDL$^^uJ<6%ikzu@af5POnb+%ZJW`>vVY5%#g?WtQ)4S_DiP#GCeXcHeMd zC$A%RD>1=R;6~r1=0vxI307QZb@aNVm%r7t@lm@v*~_!a6X|Rb7UFTl{sUk2^3B74dSPR4y2q`S>{xJX97~r~<(wdyoh9Xs-pLlA-Q6BP z5h}zykZtEBe@YE2v}c`>#5Ys=GOs>~xz6=Q&T@S%BOO;}mKRt8@I-(=IxnRE=V%i} zHSRSc%XAhq0C-b4si1NgCLOZTS6H0l3G9(&6zz zJm4f|bPq|BA}-TZh?Lnd z_&up1srSjV{8vFgQjK;Uwr`!++)#wd`veSZgh4~;5<0}bO^6fE@=N1zQp)f?npCxI zdy`Po7pB8G$Squ%50I1NG+W{dJh{W?eud)sAK~p|2i<_+UOVZ<8g&1;2%D>nkbeCt zO|0TJYR+)LC5+7#m*s>tB7+5yD!8hXWBM!9h;~H+f=u$L%?K{?v>|oydjSw+c8OLC zXnDONtn)14hc-%GJwQ3!K3NLIFS%s*FpCd<-7F|fk!lrmn-Xqup2?ZIB_5*r3YL@7 z1^)aD(m@vE6T$)xUyH%bbX3#L)(mv{;4Bc`G?kn;GSZ+9Wta)kbh z8_~g0ktN!e0#__?bRc9)LAT*VVz%^I^-Mp&?0z#XZ~dIbIkCpEUdWTZtMQOij-ch_ zA_?9Tsn*Z|l=AB+sT_|-N3XMM^3|tZa+iAgN;(+FEb;{D0z@By7Nen=bj6Z}vyfe3 zC&ph3x)c|-aNjf+T!2JvQpbNKhW&lgk^K--vat?SNbL*Aoo{3R&BugpCE?U>C|4Ri zb}pkO50$`eJ7>Ed+x#oc5&x)2gsec zAEXhi4k(|>(or!s5VS6eXl=Oxm=r(?3hWfT=Lppnfl0h?c&}5B?4DN9{I-qwg-1(T zIA;#(kxugwLc?(q%kJAoiYz+9w_uzVTh`xs;$1*%>sR*M@xwF!)ftMnbt+lRCC zvoTkqOY63JMa%`?HO#**`$RJHTNc3_ZU1~Dh6Q=c8I1V$CuzZNgMG71upSG3JRrC_GRLfrBV&=t9Z-KZ)j-cH@VfxWR|=z_ACdcN5a8r$#aPuU@h|`)3>P$@o?4 zgMAm4nQyX?eS zS|!PRhNR?uxdkc*!JIdN%CulhjmV+*T4q5=sJ!8A&Z~B%E}DFrpC_(WJN?1*Sm;6} zaO*+s$&oE%i4(aZB(g!0Yv@dFmF>2n7?SJ z`-N9?>KRSe`41Z&5&PMC+bes^S!r*-GI!DcY6fTrekLCtHFI-?K17Syq+`=(OAy3px*<~nKyK45ZI0_`H;r0A3DX_IGr2Dag z|EqPS{B@RtFj~Cdu*|b|h#>^?KwS2(SFNmVFo-darxfrGjsStwy}^%#rIuuYAum zpZLtXNw5SzsgtUoIg`e5@kN!zGEhiWCui%^q-D{npZ=I67leArMn||0daV;u{?Cm= zTu(K5$W1He7nCSK1)Vffewp_@{>i=}PuxWvle7rmvqHdm%T3<(l!Sw9!c&~!2D~65oTyLNg7&U)XT^y$2?HAXj9z9|1g6*2 z-a7{IIhGzLXPt0&`NBPLio;V(2R5C}_gHRIH2rgnuFV5ui|r;Yxx>pM#cXvj?@+GR z#w8~?Pe=+Cfk25xK85H9pCCb+^{bJ z72BJvSmxn(H+mbs2TCFi0Pvs0?X~7ea5me%^S)wfwmi6t{ppka+j-_z-txUGr&>op z(Oeq*gzm@R7-0)1!HgR|z7?DwFd+s(TBF?DT+X&4ZfQOlKfa>l2B~ESUCj(HvktntA&P zp|uVnEHQOKJUuxNrmmCd659=GaLyBwCsBFcbe|=F+sa5a!@Mx<-w@6hP1bs02lV_n zB^v4?#u6w2zS#tWqYv=Gy=cjH;5!xPCicKMEPl0H zbj6ry#THN1=1ajI z5IX~UWyM|c?Po54aN>oiUay5D9WtpnrO}b};2FO%|9f%voZ9lsKhURww!845P)KG` z9`GwFJV1o=n$)MH{0(0VUNu z6+~SY%PL>awwJ!COT!50(6_=zdHpc%AGtOOP2W4o7Cq;FJTOkLf z!(ZyBt7^%S6E$f4%7$;e43_p+M*Jt>ARMiT5-b+KaMtN5GPapJ)nuXBm0ya|$e(;% zsC0%PG4E{PdPT=~P8AlN8-bg*fgL7Rz|r{9f{?|+Kt06Uox+H~6af+d*r-l@qMBsL zdU^$0fJ(T)@VkM} z{-^;FvllnW^bujb(hk(0S*cYFp7_PKcw5IdrZ^lRuIOxAvZGNW^tESHAi z*V$g%#QvAUH%-CrP1k+cC{P|o%=gK8cTUxpJl^_{uU{O?`TL`Q>JDT1kU%rG4aDs6 zk&(UOeouQQ7fT#HommiC{bU3rCU+B&Rk6Pn3H9&!yv58{`70Qw{?tBN10A2 z|5}z=#f|87+Z?9%x~wPOhsub~f7fr^f$q9T2ojpv*;cz0{Zu_~;wr_r?h0l!_Ufen zK9-Wd9R|O%bUN)PW+OmqRH0JD*BLvAEvbBr6QoDzs3o^0*dNctn3WC$#&=4~gVv*%o6s!Zgvx_q( z>ne_s2HFAd=F|@>3s_rG$#DtX`rwFae`%51qdI+sZz-p|4Lhwmf5jucnJ)z1%qcK> zv;tNG>JVBAXfm+U>G4stdxg3DG&UTbLt)#S9}38JW(VI>?={?0yz65oo5WU=b8%w! zVZTE1=Tv6;wDOluE`nHuh^1pXDnpQyFxa{9p~{d50OxtYLT=GAshReq_S=}axwamE zEs?r?5-IAX zZjxs;fK`qN5R#Nz*&edfZc_WES|G6h2zl&KD;3R3J6$`&(Jy}1F0WP)O~l+CI6WEe zeo2;gbjXqTRcASjKBq!*NQ1Krh&V zBPzbaAP?v&DR7$xwxUmny)pxL3ZD5qFC%%vzl&@qeys7)6WXt2mD#(=H<<&tL@A>| zxabk*Yk(C>E;r%~Ta|b|tr-4T>X1!ZC3-G5;*nJ17eyJZFqqtcT+nk zVU9zv`aTXx(lT?YiHbkT0nPvGQ*tBr4`|9ka51F?H*DkoNQ&dKB80BUt9Ck#hQrZx zXiZ&=Tut-LKbiVhS!{$AdZW>(=W3&AQSK#e)3VKGYQ#qklVmpO(v_|Ui`4u^VB)qo zHKhMU9C;OD^s-r`|41f61`RX;ND%nvHmOT>P+(k zrYPY6A5p8W6Bj-O3(xbEB!(Rg-#{Mzyt8e3wXUCFc-6ZddlpasjGFmqDkHhpq z>dZfgRCjJXOPP6t|JV+$u|``%1phfAyy&ax6GQhpTLk-@G2|G7`?FadV98^UbF4?p z%J57V>}I?Zduc?rSiIL0@Wkf$c~#gulFw|QZ6i>m(-5m?3PYZGyitMPc1mSItZi2W z7vx4^Ze`Y|>XM5cTSTnhVauV41d+VR8J3mZ$4H3Vqj0upj6Mr~tFIpN87C4O0y2uh zgzKPi-k4QdOP_7Ngaz0S2=0uE=mLfJ^aa4!13AL9wsaEtvW`N^7aww<+FiZwo%!7C zY74)1693xGh8I0Bd{>_^Qt@J4+4m=~v|KNvF zS*@k0vA6xBYSN6X4|v`ukw)9mgrXGVHj#Ip+>td7ki@nF+{-^!u9p;f>{(S!iyw`M z;ED^r5u#S$Kxv1p|MWAh0cy!N$fsUDzB=Y^Ht!3u&^Fp1IQt`nTr;_Mrt)rq_{~Jr zgWeBniu@Itak}u;U35i^urDAm@)Flo>A|gi&(Pw)UEPIo3`(Sd$L2n}w7$dM#J`bC z9~#6Sq}g3k1iK9#=vFM??g;wl-LYkc--l*h{p#=it_#a-lZq*=#st54<9&joqZ-WQ zZV1jr>0~&!HE(5_rQgaH>H21cJsBw62b_6--FG%UF8XML&ULdEakepR98_cXaPrM-&@ff$tF)IW@%uY(cc;>97@J;tVa66WPQkGQjS zf5|Sre_O?#F4_x#OLX^ur_uPaGFza|WmE;a?VsCCNVo#)WQBTpyx0VK%d|so!lM|4 zf9V8f*q6zL`U|jbRe7+&-DWii<2DmQ9Jvrs(U^o={nLqqxCi;MHusn>jl-YZz+?cU zX*-=hwjVP?y=TYh*n#N@&HD&>e?@;7w>tfsl-qZkNArSV=F>*(&SZRH*PhJYD>KT= zaCLi)S4kX#W1oC4xofcHNnualRRL~KkGZhRsBMl3QNby*WUGJA+}}qEh&O#x0@> z2LT=8-IqJL0^8!J4eW(SxeRV>I8NYm%xN@18|Q4$4*()mi~G-ppmFExmG2*<#4Nn3uobB;1j+xi+}@K67UI zM~!r^qT#!MxQ@dQx_($^BiYvAH)CMUYxmFO2@TKgO))OHMEtn()0dPuf$;g3J=dX{ z8N^QQ$G^$_Ten*u1LqA|YVTS2+?Bq*q*@R=EKWIF(gZSFMUs0szhqjgm>3_jg?lF7nIQ?(5}0Xm3Jh zK~193_==js-A_!OB6ACh3rcR;(is*2<$o85ylm`z!s-fDG1Q3{D!!>5tyUzvxwWgfn^9)JOB_lo za|7}aWhhyE`FH5&wI01(UO1 z*p>O|ew`FcKuC)8VcXBWG4?@sTy!gM&ibKOEOo+x0Zk)5+9zC<&i*alPbMqz3o`EY+rPt)}wFXY~- z_3z-f+)ZQ-tf>GlyZIE-sP|OoR|~5csACHqdphrPyT&pRiJqV3Z#{_4K?(?FDOB_w zoJTr*zIpcN!B4oQrh1|CE+Cy!XbcRS{h3e!$yTK1iy|6tbl4}o^!3ZerP16;Jw+&t zE0yYdCJ;0t#NrF{$#Nmr-OfY^+lj$D{S;!{d@!{O%gS~m!T7iL>K-*5 z2Vb&u@~<#6=5>Dk_r2$>kEM^Mr?v zmd||KKb(xx6(oI-sn10jLq(z4O=0gNJv5mcI+@TLE%DI~7TSB_5dSN7D35SUl=c#! zvE?1X34A#2KJ)Xi#u`j6T>?N^Y9Y5z&@PouPAj`_=hb0c)Jv5(Zf^mE0An1Qd zc?LDN=7_p22Hen^Y2V!w97zMTun6XNO1&}MO3;8@=ETkZrnFc5k+uL93n2G3lV=Iv zc&C35dAdKexkW^hRKm5w9)q@^L>c1RW@cm^w(GVYq6+AAvQpVD1<|hEFWT0WeS9m5 ziij+EfvLmM{g!uRZtH~#y?TJA$>Co=X4*ZZ7`?KuG`L17IcFz+2U;Eh4WW?l0Sy;F z_;^MY-URaEvb1|=FwMxYD>qSw;yxl>j8D8~k^v0=HsS8uT5-XS8g(82-WxO5KX=(o z6_Izmr;7)H>aQ3BcJf%>?(X zwAZpQf?0`!RCr4%wZ8tN{lCtl@1O~y8fm&h3_l!37wB9}s`98t$X85AaKxr(*1D&< z0l$DWWJyz(UQ33%fa~$tM$(jQKF6X?N44_M{_0!BJsEg_(#4|?d0!Q!9Plh~e$;gw z9IcFurXMIvv~=sX9J#O(lyC#Wm?Q!lyub+rS^F8EPB8@KR@90*l1|rS2+Y^4MR4XOY248`>~TC1)&hGFE!AVDPx$ z;mn%aLT`lI6<~vjOy3Cj z%K5TRCCSv7NqqqqKDq$9AVBFABwZhSphi)bL|N&aoiB)$yk%hlw&KSD_?F`|`-L*# zgc#uB<*YSjN?iYEdvCYBv&U%(?0YfH90-UW_U9cmB%;z1;?33(PN?{rss15do{k6p z>H~6^^E_qr>4j=+r$0fi!i;a7#C=f2!!k4B{~8=6sk3Dp6m8wB*PjMZ4~-vlvUWk} ze2_&|dcEgsk66eo+W&Ska)?uPGt1)?7WsZW$p9}#S#+QN2?Lwfs=5kkleVv#A&mg{ z>)9gg(c|ExD&de)i@an70Fh=6n#L#1lHWb2zWkMLq-Rq z*}Gw%{HPwlU@1wFeF3Juau-AY5f9p~XvyOH*k~jBC%?~U`qcPSH48Avua71FvD&r~ z$CCh}Ky))VsNf>m7hs;py?X_leA15k;j@ot3k+k)A<4$sd_E|D0-2{%ezV+R@hTo? zTCV0wtbvQ$Hd#gd*&I zUUXNhnaJk@393hCb_H2zo|yGvp!%Tb2MDf5z*-5Jl+06Etz~3%^2Do*6n7jWj=Fyi zC*9~DZ5%;KY3%^`w>zk$U!=HuZFZ^WDg~} z4aeWjbC%ygxlKJzqu$u{U+CWE33!LFR55ht$QnLu z1llz{&|1@1ef0X@eJMWR-}EB6lh5wL8WYLo5n90WZLFWghdL`3Z0&sA{L2`&c2H}w zj~z!e1>u8MVkD2=7W{c-T1hEUMo!KCn4EjafkHcl@ilR^TrEBi+F|k^?!3`4!NImZ zDacZ1L=}g~Z5cjd%z~q5`wvMUk=q9guNh@A$Hde3)eM^*?^m1-;#RM&X>4LF+@{rJ;MWvQI)-r*h^xMbW1gqthH=Fg~Bl(J0=yqA4$2ivC2$ zJeEPSucCwI(E@{Cx95}ph)Fw#)+`2z2acxKG^fZ^ehQ6T5$;YAvQ8`$vE$uAk)NZ8 zgBMo8>%~$jzzr&0ePYtZgIvR>S;-dT+wu`T9nNy7S)K*{88t21zNVwyP znu!*K8L} zBHgTL5&trqR94@T5vKK+g{`49+qnVHg2gV*S^5@V7S({&n)tdp zTnyrTD(6ZkTjV`K_}wL!dL!?nk6Zxxk|H=hOH+(W_DiK2ihGN3$cdp!YD^}I441li zkTZ&~T_eeX@O<1FS(Mdzhd~f!AU+iz&N%A}h_0U6xIk(_0jfR!42e` ze7b;MoMfy0D1Dj~_$dXHKI^_Oul;y9b3s1rVJNQ1p>w- zKBw=VWQGTlP?QS z2cvIA0mG6O#4IRj3Sm?}NNX_Kl?4|$IRlqBAPbWhJ)#Qc#Ud1sYog|AU^q_!o#hr$mf#2*>58U?pxKk z1pbp0r5d=^S7fflN$%M3;tF+Z0Ml!Z2oP0uFgI}v)O{%8HYG~3)HvWxVV>3L+8T)E z!yF;4<#zhK`=f=_AejQ-5Bv7BYK(%e+3*tjAgPfYF=Wh;vpz zRn;5zLIfSG1aVbMU71g}t=ax&CL`0UV+0}l^if56e*B3Fr7j%4BzD!*F2&=$Y`|bQ zuA$32F<=H)WbpJaol->hbDG1P-s}KMJT9FkFxIx;qh|KY^L^b#FMszOi38jN{C4L9 zr@p&tBm5%%cDm}V{^CLId_vEyha4Y7o4gTeK1`|OM-BRs`=HNE&Xrwsh9tcR?0;m= z5cgHRXJzxp5%4;H$++~ry0CaQhI$mVRS|C~o+tlj>YIm zN5-!2pSySN@#Qfy$UiIvU&upbX4l519};{-S>pENmTNFj1|~T0XNaZ&;lBXzkez$1 zZTCIL+M9Rwxvdwhk@ZyB5*87vS_V4L;sGxTzZ#=`ad$FxGL;L~zZP!j&ET8-*uTGF zOI}(iBsNPS6$63TFzr8ub0v+H(!@0aA_={u!`?)>NYZ_Nd;P1USS(c- zW!d2W@mD}v@Ui?${^F?$>C)pBy>~-kC(^smUPP7^plp2lNxG^}&*e+1UlINs;7dHe z7FAnXiuNCz^+jcj2fy+~6u?WC2Y}27lb%IG5*oHct^}` z*1gq(E_!z2k;##&BWN6rBol8d59tV{yKQ)x2$Z<&xmb$yee`-KY98y?UaPMAxlXl4 zOZtB8x?6B~L)eYrGf6S7DzT6U1p0Ss^=_A6`mH&L7iM13u+3La;S2C1B?cRXJP`1n za<(P03}& zA<0~wmi}?(L|hZwyfu(TzF4gxt{}GYj39e$sl+8APXPmIU7n>3k3r!Cz3Jy%vjwF^ zbM~K2G0^;pi_}lLbqIxO=uw+N*a@Rzqq8@cd@C1auh0kq4hQe0KZ}ucxM|1sH~E$O z6GcVM@^sf8^-8az)DMFk!o3=Efd!&38l*o5LS?T7H{=4#MAi<<)YIUNB$}UH4)UDu z#o6P&EKd$7c2Gw-_w^M*fLJk6b$^>ovy|{hakAW81?Nb-!hRLQ71PEp zd@ngpkTQNiU0!z`?kE=1VVCZ|%OkFeFnzlR$uk6T%<3_}q@I+Yl`F#51_W!Be0}xh z+gb^=9|qEyB4<`NcXu?mpbQ%o0cYY)%Dnk88Tq0WM3(d3H#og;7j-mkkq2r0)OI|+ zCbwoZ;Z=el&k`RmM~MZ!?ZE<8AM~G;MJpC&bl!eI#3~b=Hp3sw{3={z05}uGINHZach@5tpkOPvl82l=k z;`a0r;`FL^{E$KDdGZ}x&%A5?AqU95qH??rmc(8)GQ9Q6<^1&T;_pzpT8rrD%cVDJ zhHh~{o`D~N?pQB`N>SCvT~5U57X3PNm>f;W4>>2Yf7hQaD*}6i)8+8CNWcDM#O(;xw1ec@#3B^T z5#2L>wN0=sLy@?%ARoc{R^tOb@iHVhk75&=yP^j7#)b~x4N{9kDB?9G&VNvIKOTYF zFBY4XEopMA)@dh_wtw%JJPhSZUooi)=FWh~vq0Dg&e9(tyCX=-Y{X`h{9mT@8TF=v zxoqlRq^9_EsQnIJdO04_rojNM*^kxqwZC&YOi_@wV{(~81&UHbnfUas8lA6T0C zeZaygVS&8sx81Q+s`i?G{Rav%(O8 z74VQ*xerg+04t?U8Jng;0_KZ=H03{LRVU2>mYlusrkoiFh-;~Lw`3ImSK2z5VfHhn z#POut{m-E#{x0yM`w^&(Zx%xQIMCg)T~DC1V`XwAM;)RcJ68Q**CLcry%4O0XgI27qx$Ha z%nQUou2SnG6U~XPZlAg0#Sw*TtqW#AVWrK|sRV+!+on->UzA+jR>cV!>WX_94 z1#3s~%l#ZkVWYu>n<8hIDEcE)&$hOSy>x+Ib!DNXY2lS3wa2-=CBlOWtBOa99drAw zKr}G36Et+{=!3ss&p?BOc8i1Xz5d`%rC8t!f^c)a1olJ9b+7tELWu(VeO2BwLB}K( zxme6ewHK&HNu0ZwY5RqBB5_XQ`wz(5%vGC53&N(wqKtVF+XI5B$V;L3J%Pou#U^;}9Tx|B)mA%*TO&pY<&EV5y2K(5N2c_bp?$@SE(55JrSFVyLH5H^X*X$* zwh~6sQca=^PY2h`m59ba03`Fy{7dTVy>e7Y5BtVU@8$P*DfU6W7e&R3v-YSV(S`q9 zC)%ihu8kwx_IMMkr3Mj<;~S>3*NuQgjey=X4{^dT|Z%a=RX8FQAhuC-AbMQSE7A za57lHJUvQunqwDv)$p%fy3{p1*B9l&07B%?0FXtrq?Db zi9VHZQZAAemU(1ne8rzd(R}9Uq+OPHxRfk{7PmakeS24Iql}`uj)TKOo|uuvR3{cg zAL|p|fqd?WU3lk$sycd2xeZVh;hIq*elLI-iBy|wpu9~9U4=@XNP#4t@ zw^TcmjyP&@p~JW4V1ea5wBK8`gc_JcRIMgGpvHO#sC1F0cAfDKoE#geBBUyC>XXN$ zynack+AFb1JzD1`zy{F>b2(togGei5Mdr~95TmooorV>XnB<{ii43(yzuPLs_$jA0 zUPIE`c@gj=wagtjULwqIku*uj9}xZptbCQcrhjsx!Sv*_{@()yn8cFMKW}VPQZRvA zTNqcI%F7|Ndg3PMJIP*HJsL#@}BX&;SHd2;v3nTx`kYpRO81(edtXWHbGk*w@H%6TBMPO z;TFO$@Zf!yAYS<&ndz$@&}AkPzi;|L2*7pNWgbFvhzz04SA*ZxL*urGXJ#9lI z=P_2+p1+Z9&y|Y(U%QhV#IoP&aB;7mXFG9OF*)Cz?G7bhQUpQ>ra!YeHKa(y%1c<* z@Y*_`wjI8d_i$bKxEK9wD_avZeRoDqkgOVV-ltDBvr7#u+s$bkk{1#{yp@Lz?y|we!CHw4rGz^zveJtjdlsk19wlpu$JUZlM8(?%YCB!ssh;vXF z4BeNsQ^d63p{J6HTmtfaxxg)~dv5Dlsd`dwU%H ztXM5^?P&w~W+ z(+W{pLMqyQ0G)%M%A+okh$%ow3gcK(whqJ_Z(X(D01OSfLRPnc95>@2r2_32-o7D@ zUXOM_U^WO1l`q}RlU269j2Jd=K=|C}V`+R*S3NH7X8TzQ3=mNkYV-zMMP~`BPm83NuR$3$cuCr~947_3x=^;BAg394Wc(CaWP|CqHNQKUc)VcH7xHb!NBZAF}4 zPj+L?`jGKep>H~LyJ%gK(DuxwAeC+WlFzA3+M96)6@1E^LK_z%nhi|2kPFOylJt@@hcHrT17I*RlA37oAROQx`lWiKEFC9t#)e?*HAUkL= zPrlW$z*hg7qe0oBi&s0ug!Xz>L9c0szl>k=Tmt-q_r0^PKUsO}KE(~Tf+cQ7IQmCna!)ZaNUX6|<{lvLjUwoIb zOCtNgXzCvX8fBOMn9@s}xF_+ePo0CVsxF6f^XO<{da5=!kwQJum3m2%f^TE=y1}`a z9OTZVw0_M)J?@r_A;+W7gW%_~H8v9LLo8N*K6m<_tw`T;aqk`{W;jQB>u)jxFVXU5 zdRLayaC^Ird&8tg{#NMH)6~Nmg%o=>ehwX=jg_wwBwv#gX7Qdwa?8`GENu$@OaIOI( zOMe13cO^bY#JK02nJn+kO1!c){(+VvSOmF^0C+q-I(W&u0$ho}Yf!{Rq@rz2vpqFs zM6{H~Di6;5)VOn;H3_o*fBI1M(Y%=MYsHJo?F$@qu*IUZ)( zk@4SiHz5UF0_iOsTgxYR`4WDa7PaJ!Gp#_$r!5W?v(`ZD4;k;9x4FfGmEUzlD<10d zhJ=t8w)r*48W_s1MGEkvJOgq#@DeVjN>pU3=tme!>f6|>OIR5W;>{EnOQwOJYFAIH z&=d=w@QS-HvVzK=x7FgM;v}oj5k)N6>tQbHKs^E?j`Jhhn;kE5#MY4KO#D>n8*>Zv z4_^(w_>SwcGr;Pg0B1_I`ER_?tco%JK>4AWChh%K&}32FjDp%)9R;cfEAyU|m%Wd+|MKC7hVVCz$qzjrnHbQFlO8no4y4-|sELhz=t4w2-7@$>pF-!*5-+5PQaP+S&;315c-2P{O|(?h zz(G+UW<0-hy^;a+5r0fr&~PfK&jNIb#ed7ijyonuiwSoQTmd@;&*Q++5a0LiBW7D< z>76$n#+~Ol^O=>K91;d-3d}|@VRu!L9wwKLkr;pqQV0!h?kQU&Ea=rU#x+~3K+O$C z(^m_=3p~H0al4{+hln<8I2c9KcTk~NQ8%2eb;4R?p0=&G*1 za}8eSw7y^XU%}JWL@-DV3e!dHd;a+NGg7Zc)%wy97~ewY4t2vonM9 z1*zW|9n%Lgax?Eq2y5_g@$<08n|n4LU)U{b)5PZ{OB)S&DZIBGk>=*2+l6upgJ_M_ zdbi@&;LqTu8qgf)GlQo4C+5Z}rwwiW%;fNX-Z~tUEoftU1T@&S;Q_CNtxph2N5$H4 z!7LXe?#}bi1Gu4JL&4Zk&oOk%Q^sh*Ot7Y)I1w%;o3ojd=Yo^3~M#N z^q+02ruz8MVS@o1MTzrax9{X^m#oK4?ECI1m#&M&EZ12$ON~7yTjbdJ8kU{NP*)W- zOMJJ5Sv(3`_&RRNAb~-9#$71p_o0(3;E6W5svYLjncqplcAvPbEO0RuftClyi+h#v zo~%4L4Y6mhS7`n-@Chxy zsUP^v+_8N>C6{tMfD!_>3EdN~)QKA5I#2`$<(t5cQO>Xv#;N_@f_BYRIMOlU{Zy%@ zPXZa@KTg+RgFDzbW-PHWp#w@PfuHk33q`=fcXv)BKaBl}ZgW3=F^3m@6=MUxt;HuK z28=2yCli774Rpf$$By-=n~{Gu#~JM4R-FR|AeBeCmkjD8{&^zVOK}k;{^aH8B7A_p zJ=((tnISgp;B*c)jGx*B(0L*BpP00cKQz1F`P?y{eawz# zJYX)ipqiixXT@Y64Z*FE;!Lo3_ACDH()euqU&=qF3!)CjB?R-)M#EHIKg#Ba`X|Tl zKx^Cr4JSUn`zE=XokJaDz21?Z4BG#es90Md69%-RLG_6lKUd_J1et6r%ZH8#?noi( zp#aq1Vly=@44#%D>Natzs!a_9W1T(f2RWUh11nz&VYD0+WAau~i0MBc}Dz|jytuH|p+CwjcMu|ev zC#als#H{M7M|_kSYOD$n5D=wJUD@LthB1B?y2s$3N@nyw?@#xm_GX3y`cyup$XvGa zM24(d)g%Vu-$r30;gX53Lve#!lDm8$4Vs2jDjL;C@YUsa(_gE|c3*~Ye+3~^#o88Tg(Gi08 zWc$}(&wpMOx4&4RJm5jPM@0EtD{N9Vo3_vchun09nGw~b#0j;xSPj7jsfuO9`mrJ7 zGFWlId7$Zz=uXUpoQS&(Sks~9!oEY#N`UPTHXTe<0q!H4@F-_!?NA0m@4J8EJaP1H*4U z+L}RuY#C)lIb%o(Fi^${)9mqM+RF~+LHsU7j2CCR`8eCz8oHh=YX#HR+O*fT`ekLF zJ-Z}1F+s{@^maywewJYe#HypYs}}$s(x#2oxE+4E)gt8Fgu9n4$p16syEHU5O6HxGR_^!UY|j?ajG9{eo)f|1(G#sJyveQL z3*D_f;_giC9~=X3%ZVpAj7FQ?p}xUsw3~oz9*$~w9O9`aCP}euz+&YYX&P#d$;pn2tCC z_RnF4@sFG;`_nHsVqeanb1wffm6TxEix8P)zI;-KX5TfDbN0K4Y_x_G(Gm%J{@I)c za)mU@c=v+m-b`DY1wQfrJV#j+>XitvfBYc>lFG18Z`gsk$8MNYJmN}1^E2K<_1G`3H-m_YrQGK5DITBMIl zURHESSHhQb>Rz5+V79nyhfSGmO$0Eo&}!;F_r>Jt0e16(xzN%k;q)K@8IiceE7kPT zRc*09(hB3el4aMp^!xt^Desl>s{&*JO}EkB0^HcbH`46|GQe$%ID~ z#0TCGp*}Nk2Hoit8SGBpX>Gc9Kl%iATZ$@`y44%PAvRJQRJGR%Ei#bJ1J8fg2YTIZ zH#l}5Q>nQPl}SW%(`uoYU~{g_owJZ~*2^r`-C09XD#&*NZc%x)YW4E@bf>Z^e~t^6-&A+EQN zc0==h=MEf3WQMnzy{Y2nzY+<&5tM4!1Acw*T-y@D?!;$lWRsJViiT&fjH_xm#gEu2 zit^Ry;>5eCa9SKMLPA#}dh9e0z0gx|7G~_}eP=%c{m3L$qA=9(K{r(1=(d;MVA__Q zaZHH@BA~46mPe$*pYyVLuMqf#eltuRu;RvVPB0PPH31JlsZ6xJ z$J^GOM7~>@&3vwB_D7seBGlUUSl1mmBhfgU=7=F1p)-Hli(K~`LjY^jclj!N3w=rA z^}iifsD9rLrrf8NIVGbU>Mj&C9fVAVgXm!n1Yg@zEAbHl@}8gj_ykDnu|G%Lj-a@H#j zV~t~i(E5s83wFascTyb}*E`w$8|J+5OqI`JTU$r5wbImsPTVX}W zLS$Q>1kbO)%h@B#D_F^~3XIly*ZdfXdAK_--kTus(ToR_mE*yO_auerMj20-#a z&7|%C9y+IAU^`?hbA-W+#Bj0<`L~(W%4OYB>=Drzlcvf9x3{Udg;(k#*><*A4-Pp= zjCmj9{q#`?Qpxe+snRg)`Ll!-b9#E(%G7b9NaHs{h$0hLlGyD+oKmb37}47}#$}E9 z*qyWdFLZvz6WBA0a_a&o@n-bSWtMkO7o3IEkCXN3C#g0XLF#L##Mbtu>PMW;Tf&)? z!ZJ5ZR{IwG$rfr|i??B0lJ39P5=Gp1r#aiwx%LQV&sgr%AMzcGFK*viQr&5^?c=3h z*I2AQA#U6kr4B~j?+bhtnpX(a$9b}+!-#v~L|XzN^1);7XGW&T7cwE(nWx#RIBAm! z))k@d6~_4_{koDZc9CG2@6c02=yY`X8>a7e=izCLjVgxvnsK>3ncdwiMoHynHJ>LN zq&zRG{Y@qd(REAISL{w{;=Y%1K3||%9tr;3;zEX)PSWHtTh?CiFL0U>Bhoq24W9hM zNR-H2;9Gxz8OI6zo#5AhNHv$+3V!=&vl}#FE@YA`VP@)WDYfN;Ut z!9^3ZCB-Y(?I?T^9)Hfrrbr4b8@y-CsGZ3CKwxxrGF?F^mucdMQcI(mRXIU@5+C&r zfD*leewPM!ENJSLS{X6VNN9#fs*$uALpH3kfA|M!o=lyW*_v?8mTvNBv_x(SFa$)I zO~qylyGlGw%|4w`H)0*rXl`?hdS4)}b`efG!U=BWFinkL$Dhe2X|3@h*WP-aig;2Y zO{6gaDy$2(Qf|cXGw+COvPeQ*_K6GpoG0)u;g`R0N#PmGb#NM=D%)wO(;0B|{nDlC zbh4XmYo$-T9EEIpvT-uTA1Q%l_dBI*MG*P#Ws%6Qi2T43I4lKM#REz`br6RH? zSCH$97)UNZU-`Y&y%Sa^cw2`w#>ec~_HFF8outh9Ba~dX)fFyt9Pc~IAD`@1fg6gxFUheCScsKy5>py43{lXEYvXF0us&<*4Y;@`S2p@04c zN+Y>J9$*_?2Y)ZGw@x~y%&b-AaF_}%-|<2kVKtjoEv-FZ6TiClw#|;bA&puhnK!hO z8ShYiDp#rMkPI14MtK`Yv-bVfE3@&yA66SzFS)icY69gXM6SZ)iX1W&WMmxKKDPmN zv>=asHDa(>*-boSu0)P*%3UT5`fmLF9OmzB#@}hjqj5+1gbf|VKv7co@Lv*=LN|sIc}PmQ=5b_YPbHBG+uv zdIu~p(qj&|-0CtZ8wHdiLQedK{vx@zZ3#uuJ8!FR&ck-96qT)6XtioIIb^?ZhDO?3}H zn)WgBg8uwoB1IYz)9AuI9w$R=fX44H%l#{?=Vq);Cy?<$e}#3P5KIyQs8uEkcXz#m_}9;wGcN3bF z^b3w;sRcUZ&sd=i+9>@y?g?t&NJ4zXC(m$C@jN2Iv{DPTR+-U#V;fxwhQGuyofD|I z#~35Mb_)+*@TiH?Fv|D4EK{iLBCdT-rv8={Ht$Y2J|*m+>vwhpM=MT>F;Ijc{)U>d zlW{H5G2 zY*N~#`8=n(x8>92HXb`Y^Sa-$P`(Pv_IUfVA)BttYMeg(ydR=A1{{2G^Fw&$>uL$6 z#tP;gpj4d)K5?>nSx#q#bS+x+F)Z_4!8u(DM`9Ke7bXC|SWt)aVCSO7sEgTAIx0L^=10{ivt9HJr);^=gEiV!&E6C z;}|*Kd27|U?*`gcdc?nt7HuBRvXSf!f4z{RSVaLYt74b6`Xyn@mJGd4WHG|erJM~#guI*LV!kS_qQ-Z?Olm+355k4Qo5nLKKIbPF*IsOhxu(m zIsWH;5(sF1vANPktE@V+to38=B3qms_ohgy0>M&6X>!jA5)=vI*+B5N$*S<8m2?_o zz~7O&NOM;mwN$;;Z3%G@13zeIBvvaM9;H7 zEo2K`S`P_CO0l(HU=t9o2&)R-7l^5v!nMexp>i70`Ak#xC}sfg(Jd*JQrAyva#p$p zmjVDs5jgP_wJ6we(qD~VrmttMa|T^zK>MXnIMPROGNdk#~3Vs7@A$4P9dVqVtckWejvlIWll&R!<%vI3EQ*&Gx5G z!m(}*nOVN@06)%o_cLe@^@$g&=3c@PR7s^XRAG*Kd+ZV0DJoySKj<=7($x0APAwgN zX{y#&tMAIwDxEqNKkmh;JG&M3v&ItvloSl*y*Kd6*|X?~|9bhKl?+)QolY?OSMEd5 zKK;Hi4>{Yph*&%)X}ML5#0ZGVbLZq%$^4YQw9=DG%>IFNZ9WHx&~PcV9EJ+>eWoqx2*>wVJp5jm$c z>3X|Q_Z8E{{ZByyufq}&B1BaD7TMKryuu)bl>POf3xIQ-%6g$m%QQ_E*i~E&87+S} za0peV12)?Rq-|4R>Vq5-oS)(97DTSJ5LwAFU&$xa|F<37%DZiRV&~G(em5<|Ac6+o>tZP-Jnz{Be_}+4R?XOI07eBg%H!%6{-=p1LII--2vcAwUHUwNQ5GX{e4ls z-95G}oy@BhYkzC6xLjiVD3-2(gBNzEsbCchcH8&|6@;0s0Pe9p`0`a4XOw;hTb~~G zg=T0(r1PyPqo7{|>9Q?dcCU78+f|Y`4s6=y zyMf8K5zj{(IM-Z$(nsO9CFB>^4;QmlzT>vRcFR|N_Z4;^c+K1e#UdA(mDqMl;5l>-n?QaDSqX*revWIds!}QPWSeyu{oRy zRTBdi>1qc@f&2j98{NNz&TVjvdFatC+5y(gey(62^)*1FNxav2_RH(q)F5-Qrp5}o z+Le)9PJzFZ0RWfo5#NecIKEar0bI2{Vr~y?wB}2f>I~JbPq30vj~gmXm^U({s{Ac{%=Ww91yc)%p|e+3~w7UOZXz+Lx80Zrov-!NTA5+6^@ko4M})>aYBMVOu>x zQ+B&D=;OPApVuB3E97XujyBh7CU{sXP65;}0=ab~M!kpZxV<`r#kjJ(gxNLaY^h&a z;_bU=YCA;}Sf#^hy3KH+rCrQ<Wgo0pX{vl+ol#X(6_&ilQ5I5TyGP>l zHP-kZfTv`{WP{vamJ8UV*wpi&IgL88LN_k;ngPwefP*QI=BY=|gGXeAcZwu2r)i36i2* zo$}KUlS$VoD%$Jv*x;~4RK!9b6koSL)~G+(VOj1{ zWPY%6XUmc^XC!4g1$|mw<*-UCUqq1swUbNTs7%a6BTp`&dDfwqewOuQ&{fV~rgCRT zq{BM;M~>T0>E7$suBcILYaS`gBC8H50@NpEEH5DF)*by95fRx2Sw|1o77EWk;I@I` z{I6E?ttQm%K3LTJge#g&vwpb0>$bWEjuhc&R$?ywZ}4)sFOFCe?zr`%2Zu zeBL1_if?j5v$*fxrr4e6OFKWRJVCmt=0ePJ?SQFnvyB=KpWsnG_)S1cPz6tSBZ;g# zIh{!hZgZtm5+!0J0B0RjwqxS<-N42^e<|9Sr@Xds)kJ0d3=>GVG2x6{^w8tB)_EF| z3QLsUg1LBgMask$g@MQ@Zy>_`>g`Ak8nUTgW@dzbizKgpg@@645aHAy0O2p^{p zJ{rv#wCJ zV>v3%&9TF@PTS_>$bJA4W0q3%5qP{E1<0RRx{U+9R2apn>MS}&n)0Z=R798?YL5i} zp?Svf%CN_`G|U72qkN%DJ?Y|P z%{&nZ8^O+aFvU`Tfu;*!KjGOUkVxxz^v{Rbz<37S=;uok?eK>H-pZbRUbws2n} zwEV6A9nX*On;~=SU$R;iJ#zo5!LUuh5vQWX4nfJoRkD)9ch}KxVaD4 z0CCBP*D<%r{1aMSw|f$egh1kBd_0vme&6UOaXjJCqWtYoQHLvNL6(K z)s^`~4pA42(7DBTn*9*H1zEh#nMm;jz%+E~)C}ijXYHMBpj0o`nyc!B!Pyj;yW9!+ zNZ-`kizCLLV8q*xs*Cma?Zs&*`rUOXUOpV2&1x8Cy1np?dAm0RoRC3PHmxJk_a{X1 zZH((hwgtn_)?ASwHba!(20%1A1;S9d7hDQbxp&Gk2pr+yB%3%%`Ol}r9*RnwZ%W=U zQ`5tHl`dS49mw%jITo0XzPu1k3h#LuQcwt2qJdfvY zq$OV~jB24&ogfyti@WpdBq`kRwjNjCli$L0CLL}MBA zIGNhQ;PONlDRb2F1RK4-)&$<81sl5z0X9Vel0qu+qbutkdR!nLdE_+8nn(?#`c|k40QVJh`6JQ@wb5eJbA3P_nJ5zn5ADOoY$I*=ZLP(P9AOQpXfkN@|(}K zhnDC0<{^_r9u{zhbY=*!JuI-s=LNM+pXl@I=;jSr z?5N{bjto|XUa;KCW;Tme53kHJVguJn=8|u~YuD9x@~xD%H^|r*9#$FE|Op-if7lBX}cMz_Dm6(jg&cDx*O^9L!{;SGJYeIXV+=OC+_;bMQ%C? zgUKj1e_jL-vG^iTGOO^P#_0HwnecPR2S~|O(ZH6o>|#p_kc_0(eeF(_Xtj*qu$KoT)#IR4#v=WPMB)|Fi$kfpwW>Xplqzv?sur zRIVE*M|Gg@<^$r-=$$M1_9O|F>T%Awfd6j%==F)_0WL8d)Xr1x>+M-R$CDZPiO%KF zyWXSF;`Uo#wFppRxA%+Fn^bk{?`JNCAKkbeaZfji{}~ruPW{7a&!{;t1;+b}KmLxC z*u^OGdl6ik?MHYkBGfzTieu1;ILA2tOsKDS)b$DeDCl{5iQF~*JC0HJB5InUPx$+x z6JH3UGkQC54|*rQ!mgkE$pwmsVeF_r(T=0uQM-C@E-X~hNIK&B(+I1S?sKr|_eZCN zuHXK-{8a4#02|yqmk$K8p+E>Q3sY+su?@<7#@*+6TGANHyXyUaZfbl4tW)L8Sr^mxWzLY(Z{u{F6biH| z87B1wxyo-FKY#dyAisW&KGQ7!z;E>?BG$L6ts>wZbzRox@9#33@$j))##=9HD|?P< zJH`4HL{|TI$G)U*5k)|FC)z-veRy!AAmeqoUSP#+$j#CS9t(Mi%YckDFkOEjROcXX zJW0a%*9ee%cra5E)fMS$(j#@&9AUS%Zw26h%1BO&O4Ilikn?<#-s4>??Su~4)no&K zjGme9euxNQ+$QIwy7D}`w9adpkM8m`@+HRpa2Wnfa|HyB0jCWhE18ZnBtMRvBoLHq=WItwyn}6()*twz8PHSp^q5$$}Vvr&M*ElYtjbgve`%=d+mqWadJ4+wP zFHwYkP|H&w<8avgobw}4$jsj#spkZKfUW$P<*Vt4JeARwl*3X@p~kCdKD_$5T_x1z zk>^?Sjj^osY(nPEz$-}puOGwFB4h*JZ~&3A^3Y>WT_iu&e;%#oP>KxLSGdkYHjAa5F*$jAKQaN>& zPpgwe>5y(w`7TALv~ja?QUP?-T{qv)66R1CBB`M-KrtqxR%PsBW7yDnn-&&2qeokii4E_YPyZ0U4xkJ{r%35a2 zIm(~RAK3H5UUl<*%BA{o9Ucj2DTmTS+|0tQyPy72p=-$0MJI=4a3_o|{ z`5Fb{DGABPcOLO58jYrajfT?@N?Oldp zY<&WJVGHpr@Dh*>v}XvFpNC;_$NmT*E-}DUUYs&&j>EO-y99NGd>gvt)LM>7PcU$3 z1TZUdB)D{@5(~P)(NwmhaI`z@*FV!Y9Y>#Ev(lao%|K>6WYz~0 z*w&9hTqk%j(4$oG11|e+9R-l!KRli9oTebFL$*6vM26M%m^oj$(wFu1r0Ei73&J+Q zq=jA?q0cs*1N~Ayq;nYo9=Z9EM4Habr?ZWp6J_+1ZxY>ayyxi~e}6Id*k|2s zT9*BI|IE=jA;qP8GX_L>Rf}@ghGO!)k5^pnhy*e*NNPv21)1mJ1QSRPa195N(1s9( zBE!o$2^hO1SeuVT6YxfXX|NQ0P}Y06vG#=a2lx&6>?slH(LC)5u0$SB<aU*K)ohIVKn}I}I|@YYfoN(eI=0%r^Du7zr818e`Y$JF0V;n`4)exCi=i z;osTXR_X7GpiO4E^7nV`d^tyuN6Y-3>j;j0hUY=>?$P0NG;|8|PkT;!UK=&bED(Hv zO8Le3XqyXEff+7-ytq(#xUa!@2Qqmt{YLv;pvK+71?2Bs(^7;|U#>OJeRjFhTVHB1 z$gMd~)ZDjJ*ay(*Q9bElZNBj;eqQ4@oeNePbvMgU+-_;}Sv?daY#U_#Q~HPSLFW=| zx?Uf6+3K*?7T(#J6|{+{+$nGC+|4=9_ye;3D;m4;^TC7r#5V~_=D3|NJ;Jo z)LC``=9g+6fc@5-PZZzwU73067gC5a~HH9zPZPLN_tZfv^pmV zZ?BrT=Q94ud@m z@AfOyJ%8}T{*N&N>GbA8@3e;F=XctuLGT8-GwY`xT73ex1hMsmWx+HOEZA&dUl)S# zsuRL~+gB3&n{4qJU#ljMKK*p)Tv7aCIM-^6=fj214eXCDe}Wx1M7AoEv|YarE=q2~ z79p_ZL04Oa37CF2Y$*aQs`A>BQCCu`^8N-cmvelFhwFH7Cz1FK<8ApBwvPOHO2~>- zA_H0dRL{ZRnFU*h*y8u9Z(sWHZu8)1k+grhEwIy^^u`wdk?m|4s{2P;a_6_BrL}xi zZnh;%_w|$aps*zUzgYyXdP}6 zUBn*DF}ie1paqr*`pIK+KI3<6E}xZ@wHF7MZ-mPG08SLAx>V53(`a<=Fl%h?cd|=! zX;$)HqaxDa%bUT?_;2aFuDEgu*2i^~O(Bc5mjO`W!kYOtMP0G_bCWj~-p|>;|EbTh zb96)UcfW~vp#6*An-(!``Xvqn9WRL@eQ7rmeUOC;bHD$}SFM?y(AjU~+u6*~*c^M6 z-6p655zPbRH*|}iel;8#`{=US4@lDX{8Bdk)rx%l@%LWJf8v7Wb652L3Z8Ut>`D5) z{s#Acca&piQS(Royn+3+l;Y0UO9}Q<#zOW`j;W8kBOG6nwBwk=u2+wg%=z8fw~7#> zyAvEa<=4L?0SoR(mo{*t_HSK!Ys$C#f#aW@VP(m3R)qs9d6lEU`QPp^t8+e(#qqwU zg`?Zc=cLVz`US!&>=V@1qWJCL@oFM3@gt5Y-*#7)cQ%i>Q8>8Rwe+lEzw8{;CWq}# z+iKI>a_6+VvqEHzOrRIZR)^zQ`L*y>WaW~PyMkCu7sRh9Z)jeXy?`1KvdesfJKSyT6iQG0w@=9dLWj>T<< zUpRHF@25dwix(pwl(=Ea){jxXL-(!@F8Qg0OQg^mMWYwiOF=MxPtYol@EY5UXy6v% z%SEB3=XoFNK&KZ2TmnAEW@_%<3a2Mpev%eELs#(kosf%=edN#`kW&#YLQiE9;ZuXR zufq%F=y^y)H*e*pgm{+W(W1XF=&XPLyYz5C3|hL&l^SUViK$Z zu5-7Eb+C@Zi_fSgjwfONUAGF$(b#@eFWhekAkx0ohjhZ1=+_z?75~;=1hi~N9#atV z(87987);a5S>d{-t(vj8<-&J~gRo94LqwAK_z`n}Z0tjO7ajcN(X0F^(MK@T0lIjO z#Bfk&CgERSKP@7khM9@Mah{6S5|UvXxl2XxcBG$Q1yJN|zu8iik40uUOwLYEi0KoW zKsO)NdL2Qa7y~P{oW8HHA%e1Fs>T8u#%d-pK@rQEgx@|yKXSnhtl1<*)n8L3X z%tCP{Zf}aW6(k4<>8k~+@2Riab^2s`<=x3fuLz4>Gk_Ke=$Vvw>iavSx}%_t-Rqmm z-%;7!nWm&0k$cg1sgx=krHiT>LCw&74croXy9-Q`i zw8bX+M}p~a93Fe}<6hWP(B2ozlSLt>aK&Qwx#_#0&P4@YhB{-58}V)bVYj-;g_-D- zV}26;*ZZ~dnYn&OS1FVb7RKaDku>=6i8II}T94m>VBuq;s zLaVV?t@c(LO7qVs{0X>2sdh*eM2HLJN{k~d)v3XJzwVkxuUObn1Z@~4D3=C+fZgs3 zp!?a2SS6ixcKr1$1z4rxODOoi9hsmeHE>JpJ5NL&g~iuo{RRDDyRP`igX#JL>p!!A zgfLd@`s%Y~q-_Jh*9v;Ds3>%iHcb^KVB&X;Ahb@@3(@ z{~kK52OZQWEpyer$QpD z5iRBUzDNlfKDrN3B|25iQoE?>e-xc}JQV&P$8R~eaL3_rID6}CLeAbCG76d1SsC4- zGS197E2GjvMkz{VRn}2f`ev3HqO!^;Bh>x;KL5P`|2#gA&*$-ZzhAG{Q}+nn$NP4o zV@=qpyyB(sEE-!n3KsZRVtDS>ac|HOz#}s?CHYx^nw1p{Wr}>P0V?;K$u=%2RP+sW z$-WO5>dd(e{Qgric&L5E?NktQ>!&;*tT$+viqMu0;bKn(@Pc>e1ca4onSBg(2Nl!6yg77ENzQ-@h_gVwY*Gw1E z>2dh)P_1C}L z+sv$GI-p9(^QifG(rv!fUZi!njgX*`U2PHJ`fMBz9Ff4mdkU=^kzNyLBwz7Zd-|n( z=-^H-R|4bL(sO>+lB2UhD+mtwISB38>hy3E zM)Zrgm#Y(XIP{>PX)w)P1iM;JgYo11^XOowGmYtkET^`D6i&1P+0E2B;B>f27eKc( z^<%!4wN&mGa1ztL&`}j!H^-PN<#h| zhh0YKeW|i#Fx$7jOKfqkxfgOz(aqDgK3nZKxsOtcA~VsQsF@y#Z;yWP-ZS~m)bb_a z@qCTe!|){v3Vm&x>d-GVfv;96;xM3Wi2NmKojwq24m@`~oieTIZq|D!zwnbgo=*`= z4d)XDU{ym-uh>5y%^Rp7#qPI8AnrENEl5SB3p>BP;S^S_8wp?|DUKhym1s z&0u#@9-nu=P2n)5?aidLcvfuCe0Kz&vdEYj zX|7n2#^+ZhmC5e*gts5Dtq8TCdsn-nuRQ(k<;wqn>xmt=4zDh=;8NCYd1lT}{O-N@%NJT|5!duvIL1M2Yf*SqSepB>2MX%Mq<;3w zzN_6m=_DOEHa4d#)Q9CNNb=Z}Y=|M1J@_Af(JwT0f>dm!n=7T8wk;_^ zLAZze;fC*>be_`{4MapE=+U6K<_pP6d51OJ@uj?BdFP&I3FHw>=)=$;sU^h-oPh5z zY8a(U)+GJE8XR#O&>2;Jdb)^>i(64szXYdnJJVtV9|n5l(60p@?iG9|K2BiCBi~UxcmN>~1gO{yyc#bSPZ#SRL|N9e~OYm>V8j2dzD!oj)1uL^3xkj>b+VoIA zDXQ}5R;eO2gDUtRLGJzAml4Evbyq4j&V>0|#`ok;E5+By(XqXyx+|Q@yxmq=z&MmV zwCc*z87FPs=W_CSjhYPwl7+&~xwQYP%4d8uuMehrc;JVzH#Zawsx&=tAJ6ec`FhwZ z$4<0R1R8Vd&3d>5$Q6nrdPkNw1%PCeiv5okVW$+D4=HO@2Z|1-;*jpv`UhvdbtAeX zk4D4=9bLK|lxxT4l0;+Wtxoe3u$XopEFGPLMT`f-hNhA%8gbWy5&WSxL1jZj!7TSP zT{aSS@|7+`pPWyNWq8Jy6dc@Qy~WK)S;wk}Jn^m8DtJPf=c&9rz;y{`=i5;o^2KtM z8Znh^{8&}94k(-8c7Qg(l;%DF3;=TeICJ5@i=HFDgsl~mDp}Nz($A&)E*2vlf#tfv z*x1giwMSkEyy;Evk;F%qp~)z1fla}9U1{mb8q}3MH`eKV-JnF)GQU_bn;l0{ zb?}(~;xW2ImJeF{n4tVyAeX~ko?xcq_T8pccreTY{Gr$;;epcU`X~3d`4Y=E>nf~J z)i1;|=NF6v`0=8LoRv~-yT>S$x_2o&l|%`pY)7`!p~9gm{B4HU2{x+qZ1wJy3uwOm zr^`DTgHazf*&`(L{`M3Kx)0ER+86J>1kM%1?=r2`S&TM!d55O3v2{_7P_rhC= zL#v@W5t=^C)Fi}S*O?3+A|lbw9Ko^O-uwB!c|@F^zs*CLyxwV|OE>@EKzU{I&FtMi(phb`z{MQ)a1RG>C@1|Pe0X34R!CxlmsYQg(Fr?v%3aw;XRttvuk zD-)$FPKe^*Mywye6QUJ5!CRl--Y6RxVUEpTj*LAUf(D`SB#^iT(7p1%Rujl7wjW^d zRzKC0CwH~4pM<*e`2nRG)FvlR$_2mW2#5z}kY-41LmKEef0`2q^D<0=sC%X9KkYI# z{-;+R2Q{}*CyEG|gALhOcmgHMi^ST0{e_2*(+YGLOUlfj+X@i%eV=faCzBxvdmRl_ ziVJ`Bz-4l70NYp{!%G$;Z0L&UZ+IKG-n&lyyb@`Uvwd;m-Rkk#NYF+nWoB?NSR$Aj z{O}sE9(nvh0_snwN&i82)=W0!;;;I#O0YsLMgFQ%t9yr8JM4%8f^ilUS-y&xE4c$T zf{`vtOTi$>nz+u$XZ1Es^^dB*g~ z1s(5%&k*f9Qh;IfRg~1qXdyuZS^nbcXLT4=!WDO11FdSf$Vpb(;Cek@1r0PBkF|~U z@NHV}mw5$P3UDFw)AXc4bO^6bPP;DISd^vILkrRtfwAV8(J(t}Xrk-oHnRC!V;Ifq zRTC*94PtxgA!g7aR`KQ8FpdjuuUoQi#7_O?r-A#~p%vs^g;N|3mp-!2MiL4Y+t0|J zdcb>rqvd)kNy8;0ffQd|dadK9zX(nk*s1gwEi}NIlaasHkmxg`*|USd$s;>6^v)c+ zbiYou`WghgA<$v=5?2*r+GYs?wVY7D(zwAM6|hEwbv->k=Wh^_p=KeRNCR`D4;Ts; zFr)NhZhqt8zx$Y!Jt)-%j;HESPbgnQTLjYD!vISw>+4ph>UelIKsXm`isGs#tuuC# zA|DX7da~Jp75n2`fC-B1>`hZONnYju?Z#oH*jN=Yc}D~5W+z!v%3Z?==rR+ms;muq zOtqR#aT0v(=90(WpG+Enl{YC<@8>G{rRN_9XJ-e9e6W zid9M3Fl3!hFJVBzR?@5Gz98PU%_KrY_@%ED$7)Y^%U~K8l|*0#gyv*9&Y3;V_+>-22%c z7!`z{cuhwNgPOLNNX^grB4P%xO-Ni_jdHJnaO(MUQu$JgTcVoX27e==IGn^jT8(*4cy3UYE1 z^O3o8uG_t>RT8xc1X=s+NHfN#X_4|09RH5R-7gy@owIxcYbW$cj5fM|$EQIXvU#pO zVs&7H*2j2x>Sb|fBM5yD>{*t?NvO`!GE(v&m;!u^&lo^F_n21|nYl)gpBWtb6G{=l zq;C*ziAtWn4U1i$j-ElYCP*}j%FSpB4Uylj>yaF|e}h@lTPq)6pW1{E(o3*W2UYAv z^zgQYBPR;IX~r<>Bh2r&`d&8&PZ)+jGLzM7vO;Rz!;l?Y%=iWx8WwvD-+7yb!Qzbr zyrg@8-3~zetPDxcv%r}116Dr_UYv`GF3pN(z^*6dCAfTGPH5$Us-+JS@m(@&$w>>mtRFbKc@o#6#!h4oR{g}#d&RT3M~si@%c>{%>3|Q`?f z?9CZy?n{}uTw*)*Pxx^#$L;3v+$ zielj3gy0(K4b&a!wHQ3;`44x>!#G!$D~?!AIV%2``5t}asen$(Ur4k%(=fS%m+Sg*^CZ^!{W9ckrmO2V>meq~GIV!uJ3aFV>>OSzqj z?wIpq&fH#%-<3A!-Ea>E{rE(p*e!Su?s8bn{kb0&yQ-7M%qsUS9moL#k+_o{|v39{gr8-x>(cu&WF)plbw!lFJ|MpII) z14#&w#l(eTMS%+Q+4HJ-=Y;&Qr#WsI1PWhsg93@^atuOEicp?JaoRowc84T?*|Mfn z#WW*%9pavc^MaGTQ8iXx{KX;uh%<4nPQlOs>$eUH29yM{i8F3Yi!5_BxyzA~Zmj~8 z&T#8JFAjFl;6Fyd3rjZh!QQPN(~IRYG2kw6KIY`)3zDgFIOgfRf@2RW^QA>1U8L3I+-xVq+pF*L~`0OvaP*{6CU0DLT{L$ zMqumP2XBmAly>Dflf33@h?f@5^7UrT9W&PM5%t=*RNR1(r`kJN*xC0cahfj9W&Ss) z$Vnt~VzaDN!d)8Fa*)T_PiJ3bh{rO0l-ZW>L}~6Uu=lj@rHdHed6-JTYaGotHRz&u zk}l~1HKPJ26K3OUA(2@#})%?jY~P_{t_}VeulTc-DCLI<6GxHH(7;V z0rE-_AD3%0m_sZu+EgzBFmiD7$l2<*eNUmuD5W z_>K)2Q9|}E$66ZfKnTH9DRpL@4*)g^7svo&teKk;a>9Xj>6)eld95%Vf66Qav%GHY zyMZn z{~V!x+kWGW4eJp^Ut>=spfJA4`t=%<9zzq0u(yJ%7AgV|Y2cjj|< zV{MA6llbpdegNj<1t&KL1N)$JQ{QBr4P0!;U{)Wae{kuL2j+ad~n!x+&RBFaytk}iJZQ?!OxYgO#d+S_3zbWI~Mg1Z&}(=yF2`yKAIUB~7I@1d{8k)GX~q|SO5pnCtfeWKTdXptnln%7&@jKxkSCQlrxOj8x5!RbDBddf>$seIF&s(gn98&@0`F3l7T;C#8LV zDQ$0uomRfrjgVDs?$2hfD6HA5bPteScg(cMWs6nF0!}nCV)Eh1gk#Q{XoBda{*&7r zFhb^r{fB#=>iro!rusAgP3iZ<^SAX|YekB)OZC63QhRz>bM>Y5q{Qp|!vot;Na^Tb_Al%MZ%i@rSiV1^$eN;rZ= zo}Q(iDYL&q*`@`8q_rtlyQ7FXG3TdVx!F}muY;$!8}h|B$r~+?>D(l)`RdR!ihh9U ztRypO8V};j=-{4CAngcwTL_by2K0BIN|jSUfBwDHz%Ykpm($ct33c=eH(bRgwnMtZ+op18tehm z#;M|V7Q61WP^k=s(tshKazw!v%`Tpuktq);quW{zxm34`c zuJ>JTw^T+(D7-K`SB~ke?bF8lP2Ifg=V{w2NO0$1TQ%njI*8;=8YG(STJ^MIXH$k1cE|*sJ9<)dA8az|V^_cx4L) z2u+Ljje*zJu+vrb*0PuKa43LWKn!~Ew}h5e@L#C*;`ow;>A2h=9wkKT<*o^wB;2^u za;4sn(0pC4hNtUw;K3cE2XTed*vhOHrNv3Q-Ge*E1B)YKjrQYFvw%p#0 zv!PXU5}X^7Ymypf1l)Ls%2G(BD_600Xid_%%ivSrx+J;Y@0Y5)yrS|$_(RJFroFcW zZYmKC@FK~!PxzHlA}zmI9qD%Uay241LjAy{XR#$~hpz)CWu`|;OWD>{@xERa6Q#~- zbs=(hChpyqzwWigf2XGBiA-@crSL(XTo(9swCSM=ee7+p3Vz4h1^BX zQLs{;sJR5?m+~bvT(E_*%H2hT+u2~wE`|j>IH>$#J1n^JDpk#0wlvd>6qP^32gcti zw-_ygb_ z8*x9G<|yLmUnwKIcOLY0pT-+}f#E(&hrk=^W+FC%Ko_LQA84Y%7uU53mY)K5Sd0?J za$#Qb6@?Pl4ja-@x`|299OY_d5#3hASYx@9(6b@%uFB>3J|dQX0Gf&1!Qm8QUjomjO#-qX z8L4LMsCi9-_rwu|>}aMN*xLT~pDGm&CloY_2HCs)C7yINmR(j_r@G~uh$>}OnJR#h zJCa<7ICm^IKW)`*FmaHr3du-ykI&tg=Sj)=7jQ_VWlnI_db2y-#kg4 zy}HC23=VV1)%Re&6H6PW1a{l4lhaum}eQ0qZi@L9!VrUx6}4guhEjhWb)ZYkrlsJMP#+W zdmh;cu!hEe<Cd8JMWw$4c}z|2a7?Xdu0N*+-J&^CP(Z<;#PZ{~_m(sQh38l?4&wek zQm9&oP-s-bfhKy9tFT{aa$?4x))SO#H_rVcS*^3^#$w(*iFJtfZz3O zP86Q0__=_760wI(zt!_L0fZ3Kojto_aa#Eqr(47%a75g8Jc#gGdc8yalK*)zb95uq zn(!KBnM9OCMO$mV^6=;(h;PKH8bW{#u;F+)G^OyjQ5X~Ze*B4*GUuA4?SsFoHU^Nf zL3vM}%Csq=!K<9oP6(g+K*vIh@@YXA*vZahU7cNhoP&a!VW{#u$vFx^bKL4IOn|e3 zR%9A{fi(hdlP^W^neR7Pm3to?)mYIvaBe9<$-t!U0>2)|l$g&j6dE!$J6(KXVSMdqeE^ zt#zZysOxM5^qP7mCbRRnK*zE`JxNOQofOCCIApeuSLuduj-SqtUi)jtxZ{f^Af*MS zYBK*DRWwy45_H(PXoKt<`g!dJ9vws2nVHU z`RN6@=Kw|(b52RpT?2#E?l|>p?|Qvgm9VI>^PF$;`t(V$NX<{Q$8YPBe_2bX_gRf# z@pw6_$h(!v)PuXaU?szaO*}AijdI(aEQI6A5`y50F_9*|2HcoCb@MV7WR5>%tebPq zh)OR;*Vj$l0^~!_Z0tAOP<>VSibGQ(FEOxBB7hY7yhI|_9Ft>J3XaupdGMUR+N9@= z#wc&C*z^kP|8kF?0HWw(;$2i3-O#F)pz64<@m*uPr;ZcJQDc~ksOCs1`67v^{@-KL ze6IgRDih9)y;lig7Eb+_n20lQHATl@SK;oaVAGy04~tE)3r6p%nKj|@a$%7>uX*bP z;06p8u}#Os1c6M5s%6TTL}Wi4=98QQ*lvo0ZW|@7q+0CGvsO6Hdu1gQCvd##Kghq~ zXeEVyo9kh2x+(2NIh3_FIlTa!36ypKYUhQXT>BIPU0?_94mn$sU73G;m>p6KhLXWTg%Ld!SBTqz7#Z1 zp3q5ceA62e7bBzpF6-J)WLI^*JlXh~CfW5_i z5`Tz8g(oXaWYo1Kk3QFK_y!QX(6Ign-wuWgSDr!HE}lBE5kVzdqH#E2LDDL|mRmg5 zsblJkvnB^YN=_386uZ=+Il-qHSL)s|nRemZCxl3#UsOc3nDOk~oQb$)vA!Nxf)*(Y z!l|GnLB4rfCZ1y#L;w>Cp|OgVl0P08+C7W^yZ)JbChlFk*T+{6KNxL-g<);RX#Gwl z19D7Q&$^kDVpWMh$tULX}LJRx1m0%IRj&bhuA zVcXWu6El~xhwg$M_Qw5STof`zsj4YxK#Yaf_*lIMag1R9XCEKFD5Z;r)p6Xn?RRD% z9gThRU@zU-$KFrnsOBeIX1?%8TU3GTF6G616GxxF;4| zZVw+}0`nb!erc&r0gwiJlebyIQAY^zG?iO_J_x@tdBmP&mHmqmi8R({B_5*`h`kMA zNOlo^333@5-An@=mmivEY=Uj#y`lR)@dk;TXP4xR+@$oovM)m>*zEGSS=3dfE~QT- zrU8PXm$D48qHQ0)I^T-((1Y9xCuuRDxHZRDp7(`48Q3I^2J1oJphW1l3Z;q64|;5* z_F;cS?|4y0u&rYN_wOYnKYS>2=k-}=S6VX?K)lAujN0Q2l3+2ZLO_OwObVT=@0aetLG(rt>We+M6J%t!>lG#|>#thN^no>sJ_8G`cN&s`|91 zJbdF;RH6vQSZO->z!k5{LVhy4Qvq&1zet17H9H`#~WlE3%hsOy_3!NYfe1n3nA%y z$18E(FRi#vnvSu9-Q(ccTo3qT2F^ZlaYhT-)~OMsaqZ3BXrE)WC8WkGG}O7KO5nTZ z1$O8rxEu)4z3~qi=kLrXS9Q{-Y4cbI+ttt|b24Qi(c@RPHE^es?%DJDOGEgW{Ubf* zN9J%t?)1OcKLS|aVaR>sV-kr=tHSZtmuvs|A75*zhhH5+;E}8;8rWf&S!fa)9HNvK zsd&Db&IKXW$l6uq&k^?66>7!Meerk%{fjta@C(?>3cd;# zXKux@=HM^S9*431agw09+G3v)_h_*rY+i4G-MH&+f^cT1^s(A0cB1}n285f+fuf^W z`<#o3-%5DvPKScu+5DA?bJ_&ac+$>wrx-K154n*q5+@RwlZl97i4XfQ_-p@D!k)EPe&bpXR9{sQ;=gfOyrs>ITt{}D%|ze!4oqxt@+Y&sp(w}ue) z_3QyAg8fNr38KW}noAj09Ze9}Q+x8js%z<;+tpEJH14 z8LkNfmVu8{k|Z1xFCySgd;$xCeX_?U*JI)B79gaD4?8!pVePIH^F+2AHVK_=fpc~x zyGd1`0VNt}WBPqGcSPK|PrPSho6&NdowESjG^Wx%_``a5`ZG*AbArm7HWeQM+h-97 zKVE_vXK)^vw6`+~mUb0+iAFw2h@MRd=2uIV5kR*?WYN71QIs~UNgq~8| z?iCwT9V?VA^I|~+T$|$h${cugzhD>A(ircqYR|Qh3UM8@Vf62+n8v{vF4prb^f@l2 zX@6*h=X)2YNAelK{rUOyQS=R<$gKTRW8O^pE5^1Ia_9K3U{eIQ4jxkRm=I-HqLqTAvAJ8||Bkax&u53@)(xRD zg}*sL9CXfo88PWJfKymJ4Auho*QKSCcas&cmDZR)%vVX^%py}{r(6Cs^nQF~XYAhDFMQ(GG@(%5nGTo3)8DsSGsD9@ zKK391`Bdn6c2dI3Pu35p9KWlJ`%V|wn)S6RGe&q4JfpPz=v=0bbnHfq2WzS58@TFU zbXCyg-hN*QONjl6LnSuT7Rd3Fb;!9sJMTyvvpog=Y)!>-AVm17QxJBhDchDchqj&V z%(P{@mhpr`O}iLH*#>3v8#i1a7tQ9$D+6stz#BGHVGbz<-kkQLB;C(}`G?BS+!w5E z)#o@=-2D5;o%P#;j;8$sy-L?y%UcSKQQ0W;5N;H4Hf8QJw)w8gMSjB-zW5aYOI}yn z$iDdz9C#@-ApHElXLCx(P1AKg#dj_E-K7>oxQWyOSs0m99%hNW{LTmc;B()NJc5!9Yy z+@(G41U!gSa%&-SJ0+^b#f_TFhMBB_;<;aPm%5W@<^0ss+|cF>7g5gU@F46_dg|`U z8=0kn+y+DLpLcykSu3y%G#|+agBFdB37%fYDOAa*8|eiSiam5-D2bujN}{n9u*c$4 z?L55W(aX8$P3Rw@5K$8%kT`D#6-e{wY6hGK&7Mr}WS+8V-b;}Sg4i7S;=bQM;ol9N za8K#bH8H~N1%hIGuZ&2Iu`B7h8njObTTG0`-|RvVJ1t3oH)4R*$q61~b^Neo9f1EO zXV>c-Jcb|6{bhBd#Q!oWgJ3wZPI}{~#)^K&L0jUm$0(}@<1Mu=172lA_&gd|uXDNt zUX(Z|7OhLI-m@Rq_;~_*AciuSQmk1YAJLHWovSu*`4K;r&RqSvBK4Cr zr|Yq}a7_E17|QGCy!O|3DCp1N@1zC8Bznv1&p*E}^}c?cqW-OH_4`_bKF$jN?fw=g z_}k0x8^0k$VxI5!0UWH?>BC-Lo)WI@!(qA`ky!e{x1;5ptQBqz0)g^|-usbxKJyB4 zOldVT^byxDFIhaZP?s)zO#0nkUSUir{br?0ixZ!F>ts>!6za_V8#&wTXy@4!|W4 zWMQ$GIDUI?VTqV`|K;i)wFvm)2N7`lN6q-eh@sBX7({7(_jCL0j;T9SHL7#0w@B~` zGoG*R#rCm?-~Wwnmrk%&-l0_j7&Sy<(t`b*mRPs1j{V%M;X@7pQ)W~g}3NDCvH5|NNytyE*PPG3SI|G`_ln3u%{Vl-|VQO;5us z0uEzPt%=<+*Y?W6K+(?A{{u_?My`B&4@ zTtkCrT%+>GrmSzZzV?)`#yKxY2*@k^km+mRK?=vzz;BLghI{f6ebuo|M@4WD)?{#0 z)|M2;qq8{P5}Z)o42AWueGAti@F#pE48u@jxW2j`!IQGpVPmmm-ptVR=Sj2rV~DcS zdDi9?`dry@YZUlxEtJB&MGyymIRt*K@#^Ba<)1nmT-d`2_?dP@v-1UI$iem=9)kCR zbAidnfqDmDC*nD@ZcXLtGx@AFv#uxSPvZytx~iaG1y<4vLql^5PRz7Gr+bT}yBK^3 zlO(uEn=-!I)Rd@si{yc*g!!lfOPBdLLx~-ng4<-saav%Q$L&nb@z*jMAfCljf+Ni* zp&SvQXB$>!^70Zh2J=~Iywimr@1^ZncfQz!t!#IruISe0CO=sfW%-iKo+y`@Y1PS< z9GktT^EBh^?M0v^jlde0*PN5ZsR!NJnSi3(&#Ggii;Z zQZs1|vamB70(Z(T^SAs!k&9=Q)llxHm;IYP3&`RG({~$Al!u~$Rx(a?3zIKzk+yxZ z@Fxs-pD?8qIP~68g=Lmb^7;)N64Gsc^pcd@QC~h11p4a|>s8B4gax0{xZb?2e5P1} zZLj2oMd6HR(K#@_*ci^^wlQR1qQ;NPIjekdrvTNNFAAU^_q?G3W7D^XRVNFzyJGJp z#fTpJjKXIvAs;5QzGA$A)mKrU(A`>6fP2pg4(1O)({1*vit{4R@7OIZxrU9{K)MX% zt4;_eO{lM0I7hjM{wOLtCr{=5G5r_vaqa3(cE6@OsDp${&-N>-PhZ8h;)PXMl1NIn z+mRAA>@vE1q2xWg{5LAaLJrq-ox8gm%D1<_G5hCWP}ufW27||~nP_CSEd2gi_*LD?P`u#Koi`t!o1q*n zKef;QpoLIo&M!6oAir4EP+!HM$7{@=_%9U$o6X3%jSQyl==zUdgGP+e)Z?k`tD)U? zFzVMZ=pEtOh*Be`yR|p4dDsNhCz776ha)2igW1=oDP{ z0L;T}xbBhpwWA zT+vV(!3D#WY9?-I9R+@B`uPx ze)r3#6BL{(Y@W6E@d<)s_d)m0YC0m|2 zzfRoMBOgUEBRH&vA-M#OJ%C|nf=tD{EEJ%H>>yVpBWaxaB`}%anMyoqvSjWh@vqqy zN7@P(-&+Fa7EfqdB_Wyc8jxiPF}Wk{MFL_iM5y@`w=Ss7%S3oqr$>$C?&1>ce!baX zW8fd+D%C|#oEnL?R5t#BE|gE|>TcxY8r0?{UkmGK`)fp4#X2+25KwfFFxQW*f>Imq zCJh5I1?O(7TcLpJ{Vv^Qqa7Lh`g*to$;T&jujlYy6G6+w3BIf6WyVU!0Ov%L#QEIh zS6`^P#YhU{uF7+*^0B7=gQQ+haMMr@x-676ScW!aL?dndG{b1K22V`+1 zYEltJWh0`)X|agng_4rl6ysH46lj$XvWkMOa*bQv<&bwb)jJuEFp8_C0A`+Xk`S-T zWT)ya@eqYrAF50vib)I=jM^f?oWs%uUt;f_w$S9!4comD5lf&CT%dh~n=FXrR|P>= z7x%Y#e2B+EiTTnGAymZKQ0(;`5Js7lR;}SqZ>?VE@>G*I^nWOHM>2=xdb(Y>)p}U8 z%9p{WjNQ;+acnV*o&-)G;P|XN1+X1lkpP2zo}R z!c$AE?QexmdEkfyAxRGjBTSpbo+@mdNHPQo%a;b`l_8A2&nENn0#fFTNwPSZGH(Lc z?az57&mr8Y{VQ(kqLmxUJgI3qRDISh_%XA;BQBYhsgs`6u%}d%gkVerJR~4*Wrzt= z?`!V3Jr}^5P-AMV?O`OkHvdym<;BA~-uiWce+hm*s~KhQs51+L{ZxjXsXS>UuURZf zSh*~%>-*-XiS&Y!eW>vX`JFC^C!y5eZ2UhIzZ|C5$L)mgJ2GJ2z?X{nay}irp1BWu z21+TB>RD9a>CmJ28o~!74xn9&?hwotcOz%6AKdwC41mA!DlHQ zHm_0OHC3v z>;mRiBW3aFId`O7q!x66lRGQVwzK_S${#B2^i<2lAP>JDnr5l&fa)-O!r8B|hBArFuV5e!DBIxHq z+tKp-8o8e_kpyEEZZ7mCPX8cIY(w~EC`w81{5e|kjdy9$RuU+$H=r{xSBzU5?C#TK zH4wtUel47`z2Ss*_EZhnX714P-c+H^vecR92TCu=p86 zehIqog!6IJVm;32NZVCh2Pbz~(kVf~_msGG5Xpwpl>Ur%bF5R8D7BXX{v#0_-1UWl z_GnHywSSGHtQX-@dUsYl!IKl9?$fcqeIdrds=SYI|GbvJ!9~Je$q)2MCkK-G)jfwcdAHT8;2@ASl zes+XldbudHD-VHJ^5o~Z{gHSc>K7*HV?9XpoxL1+YW>#8bgl(#`5NblnpdUu!wj7L zBIS83O4<4G>6|LFw@c(cm72-`tnqi1zIrzWZQ}JaP)pv^<~<4OSQmfgJ@D81P2AH+u`jne zGY-F}a6B)5#uqi*FNX%RJ`C_~g^CTM<%O0lUnujopK@oOSf<=LA1^oQQwsH;*c6BR-Q>RRLm!^*CcKyjZmE#?hfetXBZHBM1&O2*Ay^F}v1R;#^Y$}%Z6=HUp8oKG z!_{3cN#zr-jEpBz_)cFpHa2FNTu*yLkxP)a!_s9Hekf=h2dA0We@yi3R`(V3utH_N zfqqfE&PLyUsL{Eve+G6c>A?DX5W5(VK%khvj0z5wUMHw+|3|g8`$vcN28m@u?(#*j z*1p-3(|+_@pW&zO>Axk?n9d7ws62_)_tc;ypHsHT3H`AIEeU0mZoRANkX=YETEQ+A zvl04R{;}Fd>w=tD3JYyxMVrV!$g6wNyAWq+L*?aIkM`Vy+tAQ(=4H52z8KC@!1?<+ zn|+lbsx;0xanvu+pUF13njp$J#t1)>zaD8{l~L#;rz|C>1mK6+W6|jJNnqMqsg2~f3CW@MUqvAc;BtL5Gs|$NNb7W{R zm?luVs1GirMKCsxni{e8Re#)38zc2^oXCkO2{2%kY7I8d02vH2T4!CkAIbk7dguUw z#9a^Y;6?(l8v_vw5{T=^hRd?j5X{S@RVar`@2u32R+DN9*~XH~Jf!}aB}=~yOLpQAvAJI5>i;-87k8%L|Btf+W5X~Ei_J#EXc&f-VOR`vJ}ri& zktBvyWOE8bsDw@wrBCWZDJs?GES01bIn1G>LiGuy^7H-u0rz#?_jSMT>-BuU4$lWP zi~6Br_KnUF?99W--lMikux!&`A_RL4Hy34Ls6>xHS=*zvW$6Y1gBSjg0wS6muhV*E z4u-xc1|1c;*Y`9}DMYE`{(h%o5G(-sPp4%E& z^KO-$uP=Qaya~d2s~_iO4$S&bTk1M%7Xiw$H(}knAv}EVWpFKOObBj?(wgTxp51JL z>x%`Pv{@eh+Nddda=WH?b*syTky#NW9Qvr&w>kT~e$Zxps#0W8DOvfrTYdOh>rwg6 zEGvh@{jOK^rA~z-(uJdS1xMA(&o?SqJNq94OrN61+Z?OQ{@r!-_w2c%R}Nnf&=j>FdzWv_%19+fpp|%+<(pUjAqj}Oe@&`DIsoQu@5;7kChVhy~ z?mWt9aQ6=$(5~;9xt3`~U$?&pWT^-FxS#*IfzAlg<@c%N-|l?;)o!`=(vftPY*KAd zlU|aV?5&J@kVyq)lMm+TeeGxSZREIdeffHlfIy`MQP=C}T5>z-#_@qg%U}ho3vj(vG$+|s9F85s^>qg$2-Bh_sHy5 zo%ZxPIK|#N$Ml-s2)f7jF%QXo^Pz|QV>mL@=y{>>YMOfxB1Pp9@zT)i263B}P#Mul zDK9~l2T7i-rC6yNg_w(BnG%Pd`Uzo6?h4Y$uMjRD)O`wK2-bQnB3q_;{L+6S@1bf| zJY5v{d-p80m*Kyl)AaZY(@@b7)4rFaf>7|Seyjh`+GE=; zkMfWsWnQRwg^gzxnB^d8hDh zCxF?|W}4qg*`HNGZ`HYf6&D%WHRA%x=sQa{$&^7a%hNB}i})bxLm-=6Oa>;~zpgUM{veA-O}|k2EKWQQRg7w;u9&3n0z&hzx#x zY!lD-Vw6xqG>SU$V>dF$WdtI1%hO{KohAt%bTib6)`!uh&b|XDMwos$Y@K!BS~L5K zd~`|gss$gIN)qM<-BS%q@4gec+cO>_a<+Sbiz1dWuKKH~@N8Fpx&{;E@QpXom!dsS zgdl4bO$6E5VT4jXM1!TR5{2Y!Y+Sh$t<2SNfTwun{FO_0*}&auB!!4?H9G$z5As&^ z2jjXeq5LJ`u`XtWFWT?kbI8KCtwE%hLH-8zSf1YL3Au0lY# zKw=MAkS*J!fcCIMn9HE1IidAHNB}d*!>l+EeTcnBSt|dZmGoh{!#C)|{X-L^ZdlHM z?1GvCU_r?YFpZq+8c>DFEoCXd_5N<%V-nT#(fRHJ1NA!2G9=goLY6)9As&=$+>n38 zj-9GPxP`+j*Rgcu{?384L^4GnW{x!JrP$>c-L)CYKd(vXn%wy8%5k%KGu@}aQZ2lo zZNUWQhqw2Ef|oB?FzT_G2WTI28RY!!E3wNSAgnkJBM-jK2)5V#5M&s@+y>M{n{-RW z&z&-{zGcobXqmt}&WefbM{Fc=5aD73)^0V#SCM z3n+yvJ+BQyjYH|-?(GT(AIpt>)>kP>dQH&1A64e3;I(SlbZN;bU&db`qenhNj zFJ^yT7QpOYqJ>}~b>+?ThCkqiIk}uJMajMYB79045RXfll(!&A zlzsFZ0&yHy#q{^?i2|d(5rh+!`K@+8Cqsw291?#)J3_kKg+qin) z6BsP}J~wrGpxCCriGKTQ?^;yx*sUOdARNKZS*hisI;^(ItBpEGI^m?Y@iy# z6pO1u#X1XH!9L^G@4VyxK^+OH;J&^$8K;Mfk6_0WdH(y<=?>dd=l*3Gqx~@uv~CHa zHM*9|C^wX>^n`5@M8LH&zf1-p5!)o#P;J`^Y+VI#&Vn& z0$nzaV1#I&-5ICdeLAdtYYSf<$$Gm0N?=zpH6CO2YQ&j7sSD+}+hPPl%G}F+I}TMI zkpwe$d4EA%Vl-5r(C>j6cuaj@IyE}^1#ra`?wc^E!7ay&ustw0p>ge-Kmk-*h*d}NOoB#xvNVyJ~ zXr_F!uWz8cN8B==e~HNh@jaE3{Nmxe**YF6S~!068Sd;dByS<}wLlfa3Q-qn-R{Q9 zPK3suidq^`_EJ;*Wmc%V;AsjHYxoj%)^N@1wW%k2tTPY0XKNAo{gEcQ7bSUJZeTBj z^2(@4Zb6q8C>5jjn$y;o#KvQye!*?g#;mEc%mIRYTU_N6iI-Wz-`(b0Hz`pyCu`)& zMCaRZN#OoS*;boxC-nhfpnC*T&Y(oV7}*{^l=Q+9Fb5o|d3#vipR}jMvj41d&aJ(b z`|Y=B{jwVDR5nkp+0}Z@J6%o&x@nv(OJ3Tg3(x?rf*nD{gK6pOdb1x29-sb+$QXhE z-haGjwmd~O(GiXG`XglkLp=JPu@6_ie~~-p?(~)A^{+C0e>_h1%cR3?lOs1*97aDg zuJRZvfW)*>hhB9?pDT0Z0d8ic3x4exnI;}PNPQN?P_{lQ$iB*do%W7$giLQor=^wH zl>pi;0(M;pZr@QJ6#SN`>71nSfKEw$?<;VQ+Uc<`$(po(ADh0*DS&}+?E&xo}BBF}yFH3uYDWk}nmf;*Dq5H2Tz{>;e_Hwj-+PF<>@8W)8{79b!F z$}%gY!WXf&O6xa=cLD9>RI*RgB9Q&9)7;+8i2RVq4+R1(w^Nbp=eF(VKHoX|Nv-TV zMEL_R)W;~&7Pu7%O&rbdlP|hE95amp7jR$a6$1awg2VT}h^hn{=;NgJ$9DUbVij$C zlHhLY+T00ORH_mOR=*YMrQ)irHZv{z7jCF5d!CV7UK#4$_7Yb>rI`EGX&uNF#MdFv zi`g1|xwjBqDJU9OU|-u>@i{Ftij+%y!jU#WSAaJYD5R9{FIb>jl|20Kt|9qUP`uZI z_P#eqofo*?L#amb{$|!m-m>kSM8Na<&+&lMPLgl@-=AFLw=H<3q?oInWcN~#!I_IQ{M)BlZ3m@Ynt*_y4VSJFmS%>2L zcb*5PEVyS=6{k{N!AB)lx4vg-Zhf(H+3Le#eK*r1pUAuX{F&J$*>2l6J!}Ye`I(Wi zcacs}PqSbEx8`xqzQCEVszWm`z8wi$Ih380_ujFL*PIx=J_JxG@U0?gCg8dd~6fybECa6B1Z*Pu2f9f8+kh*$;QFag#);w=!t|#=I09_C^Y|s zed9)Q-o~NqWI+$tbC$kEfc+Vu10(nJ9cEn)*k8|m4=nLqiGow&#y|Xi9wY&!|F_G} z$LY7%?!GO+)fSnC+dALxgB>di(>A=l7h<0E(=%_w-8OR73sv{JeOh)jEkW7mtbD&D89Fh8NvnwbQaz*!w#eyT;r1*vQ z-c*_0^{5=T$Wnc%U34V!oihDC#V>kT@(Fpx?UUboWj>XD>Gc-2jspbCF{p;Y6*=~P zjjH>jYF3iqj_x?QZMK(*Cb{~jPb`-ITAq2{bqNVJd zM53hQMjw@5@XxAVcW8`UCt;^WACWwDNe}o41h}Nn+)si_`tflY$7_fKh8jySN!L%kh@VmGC1JXJi6p9HTlLqQT37kZRb8u(`HMyIazT3ZuhZDJ zyO;A5k_P{MrP~M}TBSoIy$6bo3j-FX-QsBhI2!ifF)Ll)!NYnq_IEg}3JG~Cq1u@< zbR{6HDVgWIW`S~*tjpb0p*rkA05_?bq$ePCo&|zO0WYDCQ;V9n%ue&(FbNnDL=Xdm!VL3@b)FVRMZk%Zio1^-lioGa?V-UaXQkI4*vW zUCsU~_kPb;89O90ZtY9ceh-q>>fVktc_YodCs>`3*qjVhsOy)+!tvm^h}&D=|5 zhiwcpwZ_;mThwx0j*3FDUlDS5qW^Zy)#IqTg|WoY-o%&M)wMiMI0e62bw4joxw*Pe zgr;bMHV&r?gw=GawxJ8Ne{tS0Eh1i+z=eA z-UIUIzoJoS776GU#w+@OYCoQCsjF@0&I+MI2?&DRF@Wb&7=wi{4O*C+W@~F-sCq>s zf>&DrnM=nkuBByO1f_=*UPK|%*}Osrgjw0x=I;fnAw48i3p;Yv7AKqhoi(@nx^3+CWXYws{6w`PU&x17*XXfTox9_oHtvHJH)^ zysQTLDR>l}f0UF%LL%TiOG_LU#R&ODx3r`ZY#6tMlX3CzhUOjDk=hmIWA_>mynt2Y zaMRb5H0)ZvW6=GGrr67cn_;LgJFWCw!jFSXj~Il@aaTgN$X#g%)15r>VH639$)-OU*dG(nsaq$VdiQ50Z7-D4#-iPP)ioL`%TGXW4F07p;96gPk9FU&j>0T^%VQ@X}cSx zYiohkr+oIj7oOy{{B&ejc{;hxM1dtel=G%llQ#yv@dWzuG8q_a8}QobjADX`Y6JOD zc|a`)s_8JKJL5q_9y~p5rH4p*P24^=4;l z;unjoB_Fm3*spd)S34HgCSB1|WGy=!ZP-c1IfdbPTv>fW! zGji$KpW`x30E^qHvdu88`tSpr;VZKS?Vk*I$GaG!;~P7i7%^P+K!XC@L7wJRaX|T% zn~TpgmEB3qoAg2&;7Rg~$>o42Q2fUtTg}4XH=bahb|b)-b$Ixv_c|@$xVt+Td5W*6 zLjJ2feKM;zq~}^^He#f@KY(O{K>U3)we{kCn`>9MLdqC=wv6DRN0(`eEADO5Do>mY~iO*}0_+m6#3z0q8EOYsEy>9EMw=!ZVfp!8>%r_(Z zKO^YkPQr_$6~}-sS4dC7lab|gB)oc(K0?If$IJO;7;SAlkFUH~@{U0=VYd)Cn*Z!1 z%${Y-lq~KK{G5qhIF4(6v!a$ z-A!^y4xA|7J47BRD<%=h$D0C{Pu_~W5N!?F>cgpPXF>2RQ=@_4aM66!EmE4Wj*4!%SGD~ zz9LfD9`d*qyX68f|IfhJ{KygfmoY0=M&EErtAo5Pm=l-WlcO4OSicaypbJTTldEU% z99$e~Pv11EfB|0}R+^CXDikVoYH8|td(4z#wX{`0$H)nHUxkuuRoTG0fN0en`I4qt zzj3SSs4rlZoRCiPuejg9@v6c;ojT|GB~J+RJMdW^X#UeS6n62so4B8({o(|tSe9Ow zdVZfI0i<|`bJ-8Fd893CaiFUXOTVk6gN)A%=-+JYA6rC{zx>~B{W$HF4+r#a?>(WF z!rR|bP0B+2#6r>*Kpfqgo9FIdk&*DqVX={g1K^}2(x)dhaPWtIS}1%==gEoPSEA{k zz9U}crN};^QmL_03;wAQ1W-ghMVdhKN8&*OpD2*SG0`FquypZ%Dbibf=3@_m~BY00NSe7Whb^r~nRSey= z2i*{)oj84s+Af2yB()-odSV6=jPCQ^o%Ah>QDQ!&C(8vtx_kdDQH^@Z<7Vnxq_T0y zr!(jXRED+FU3Phz9Dbg?QdZYQa<1mjnV8=}@^-P^ooj?DR01%miJ(O012K0>!|Q>6 zVXn?K6yhqSD4dBhuv)EOm8*Ad`Sy!VLN3U}p{dR&jkemQ#wC^k=81re+oGYJKS!&c z3qc1Gs#|z-IF}x0{W*G1k)c+A*PH;A$6zpXQRpW$Vt~9Q(<|dWJp*$bhL{V zl?h(1)lI76ETzJNRFil=Dstj!pg&myOw}aGk6!|*KsMUO*W-$kZofpfK9>zQ6@OL; z?}@&p1%Ldg@)K^g)4ESdTp*ZHY7Mz!MHsk#BCL#^)Nt<-MHT}}O+$X83<=2rMBELO zEHL9Sk2mlQ#L7tH5rNC7em*7Sl5lenfaIDgrdDQT* zdUB)`e8WpX%~3Ir0(p*oXTP#GR~kL^wLa9T#-$Mh7!R+R7-hWsbC`$0R)DmI`usQwMv@af%+pX4_W5CY6J6Rxr z%f5V~hTSKVaaQLJ9zY{J`R4CrF4G}9XV9!2z7}SwIJWA3(R z)JxB#2J=6#->-wAQJ~`gG&7u~WMJ)xn#8?TQ|L=H^L$``zEq%y<_Eldd2Uwu;L9$9 zc11e)=VRI2k-QH3$DodUp;mOc-67?48L#-a3ajC@9 z!eGd>GAuzR;W`TQPG%q5wz-5i!XvQJ085tzp!qk1SkL^TgWfeHE7vl8KX)k*T8$ z-z3fUKM((iZa?V+3fqY#I0cVlQT>Jkqq;spP|3D(5V8i|SyFFyQmx-kyTh*dw+n((juW-zpE zXF~Ny_`n3ih!&Tx<-n=y>Q;-Gr9)O3EBO?KOJqTxjo@%vO$Mq+F+;Ss><;p*zDmqD zimbw~3^ryc_^u8E+lo!Nl0f31?}uR0!MIQxKC(p$Z`JQMY^Du1_hC#PVrg>nrENOK5 zbqGx>h0fD3<gmidS7y_viTFE+b zJxufci+*!e^4@-6H!84DkxYF>!C*UgzVFhbED@(jz9_g)65O_{_Z>3%82;t4L8e4z62v%(0fyn|EoY_-uu z$VOCU41);&0>4cE1AVgmRF_I^dc@F9zHTWdjTjKi9L2R z=>=)F?gr#sZ&dd!{naVG^cx2nF5%MTMC#^6d#HK{|1F}tSFZT)wl%(0F~F1```R!} zPI=R1_#Pdy8z@rkyJephYjN)nRl@VS*A`UuHEm>Km-h9wf3MvfIGNFeppamv<&fZi z(U?+Q!f%?nlGXOTh(BtpP|CByJ~U76(5F1~Nc2B(+F#j3;N=_0Alb1!O)bphuc)fa zRb&8@27HMj!w&v#(pmcHBoqQ$e>ZZCB-!AKL2NAEPgkHh8u0Q8JX)DWzPiJTbA|=W z59JC%-hKk?!JJki^PteVMiwIg^%jCCh=@Z*TlOEOQ2TUHtu8UKr?~&~K(l%Nnzeu5 zZmvv#4(HS!khFO8I*_Z0mZPo0bk9HmAqM!6<@&)Zuj@m8J{h=$nMSn0UlGt=BP0YI z&lrd)r^%RZ*jQzH2Ic#qy_apD-5-V3*Lsh7{p>oWQlt>jmdsme&W`*1i4orFPWf; zFGG?KZZ5rf^fNITdA5nnJQ*`!D33sv#nSUtUQzLysA^^EX`qBu+}ZH>BEh|g|MBT&PU|1XFLXXi+y{|O@Q z9KEI8wcY(e%Obv4&UxX}T)lQ#4h4sowNtF7Fiq{KH3TA)CA0v)MFg_o9+)KHd!>1@ zJRS8B6TAPSaocx&lx`2*+v3wutBIjbu-o`AMJkQ2xGPNBfpW!j=St3sORRQZEmjgE z#a8Q9i*&NgFlEQ}viElY;Y{9DYD!*)MXL8^+N&P&9ympbjxWezFQyQSC-|EM{Xp(K;!) z0~;HCYzamk%wh#L%@0;NqQl@+z2~61qcrWfns*#70tpw71=Mp0rzr9#Y^h9!1YWH9 z$S54)PqakK!@0y$sD48m1fAUP)Q@DTP;q5lFZ&Vk8g|@bK0G;TJ2K7Q2 zpN|^{HGTQGsVvbwp1hAJOCM>iJERQUUYm2W+4 zIS3X)2`q=T>-LG!F#n(zEGN8LrT}ybsG%z3Z8^BoAcZe;do+=g!?hqR_Iqmx;Ht~9 zAB{$S3dp4Yc3@jWkr%HXr)V4dYEH`*Bbz|i^DX|`0^GzVn5rCxA-c?#6F?XmFhp|@ zT+4pp84ekZ9UVu`#&DS36lw#Pf>e2BtiG3z2b30}%t_&hxkW{q%u z_Yf=EdP&fbb;4_r69$-}0snM|C21^-Xw%Imr~>Uw($d zg)>i4f-Na50=!>vhQi?nKreyh^vQ<8y*Uw;QL!rIPD%D8V5)|qYE-Xg`Wo)??(TV3 z7WK^udS#4FnM^P`4_nT%s|6){nFe^Wm0&E>bMHgXF#@=p00h&n!imep45}yXkVVs6 zL8t)~Cng7#(+_XPYgT8AWcJ|o8Gz_Oaho>4B|zL3@DrqLUnS>FgxFO8;oNq>F6v$K z9Lhy%WZa6!PbJK1dYy{8P;k0y~)^!)059cOSJ`ImN5<|w&@Q({vtOBNQ=PpEQ0siFJ1 z4d)DrG{7CS>Cnw$791XcAQ1+I6f&H{H41d7+;W%FZFM6@(o&#j_)NGZls09OMi2~e zpJH}i50ec9Hi`R`%@rp(XC*Id+3rA_L&Dk#HjOjmkh;{tF24wNeNu-hX8Z>ql5)tND&eqf&fesY6M@H zG{yngND`pKSW;+*^;5NNKDFzP$*0(|Jv8Gs;H=?fkh5`mwz|wO{ba*)9~w6KZwm`+ zvdz>A#oJWuA|mmtA)C>+BZ1NT*s1SF^>eTlrr`8cy85EsOZ@cd@8BYmOmGe)l&&ti z$WcW5!(|qs@^qr*tCl9rWZVn<=co4sIdCgqOLdSMOpf~Ajll_)C^(6}Es-0)HTE^oao+m9gw?Vtf+Nn%gYn^7swvEi1X- z;vj{@N$$s`D5#GH%&RuLru9v(Jc3N<^z}^NeBMjtUA^ua+~4{y2Of2Xa!2^0n;AeK z_zvlsR97V<#QZjBM8oB{hpiDH<-)1 z`MnF_UoRM0dIf2UWuLdtbrXNSheOJqM6vY-nM8nbmnzxW(*Av1K}gT~bJsb8hFNWd!`U-tJX|ZXD?RdZ}e}KcaTHMC>NU z9UTJ{szQeU0RV_yP!Bk^xvM)K#F7raCfm<`1CUg1B#r>Z&U-fo_W z4oA;d?4cvLa1JC?8AoQt#9)atzn;xg&mlNmo7*>|2;SA_JdNyr1<(%*XM~&SJN`Ae~&>#U$ZyyS#dK%NJNw2P11BP;}K0;8!?;j?L#qbcVyCXz^j&SH= z9tu3i(u6>c$Y%cmeiB51#DfNns`QfKLAI(caMgefQVSjw$8B!AXgSQcWKe(CM(>}s!d zY?tc0Bx8=EKeB6OG%az`hwzs1lwPPv-c;=Gv?fX2TStMKiEN$QFBjbFJ)&psSJmlz z$Fs>3V(ak=ZZ1=6AWT_42S_R&Mu&wvSL}q7EN+*{K87lW{}VY-kef090`KUHhlgO~ zJGM3%Ho|M|!o=cEEA49;PW%TKGmHbxu!I)J5PE#}0=hd@L9!*EX!MZ!D}yf0@!B2_ zjOEH)p!V;e{V9WF?;Fcx#{(`>t%Kv=w>F2Q1Ii%?Ovwr#tg)prv z@91ZRb~u*Rc59$;!|;}cOU}BY%CTgtkE&Lsrh!NJ_$Z7#C)d0CbJTQ z7%WQ}Cvuj?bFYlJ8GCN6j7$RN7_iaXa$92TwJ!^75tWrJPeIe-|`g92HH z!{ck-at^~h```yY<6mSgVL>1lzvC>_jWT`Ee#V^cE>gv313lRg&{f0fjh5RMcTZnR zK65>Px%D46UZCs2&ei#GWx@pkU*lC;y7$|Cb7}R`i=jBH)3|w*#hh;3XZT=Z;0s z*!Y-s1YgAsy0<~UgeebIfmmMMdgyEpDH@^GQdpe5zd5F*D{`rXeoy_ZGyxf#hDG|V zRtU7wl^v)^@cA*Z@dhMCJ~+?Xue&R14Lk!)$XSAzPQ8~b?a17g9r^@j)#XZ(^&45f z9E3XoZzM`aZe4zxn`y@+s-MSYolLl2h9x*kkqc1m3XwjuV54TQ=OiRd0mO5r^Op7* zX&<0{TZ8Zn6<{-_@If9LZoHejCRu)yzm^oAx#3Jc*)Zlr9KYJ^9eKo=SSV{4P3jm^ z@7oH?I~%2Ae4e;OUkkNqf~m}IT1}R-G)x~7DHT`dFFYnTqRO_)3yJ@raw!!+;y<60 z>E`p|g*D=5rBfAJ+|TV|!jl4RSV&vbe3wSDO#b;tO*nbT!J*&7zvrX2s6W?_s1?mT z%YUs8|8m~)xc>nC%Zp+;x}0?5<)m`30rLFD^ye=7&6>7;L`9v_fS_G}88(oI!Y{I` zg1-H;;5f^AW*96t1w**3Hn+;x;EQ?ey7`oV0L}E&Em5w5pvieBihAK^!@oSm{Q?73 zr3*^-spYvE^=?%40vC^I1TTIg$lvVuALkg2pm?B;FhkVaJF~CUSRTkU5Cl+XCUZ*9 zoaFmhaliXgZ*GU^;2Y+#3D3Bvad4kI3Gw@yv%SjT>3xVWqf2MSq4Q^RD>VZm0B3!l zX9ocrwhLxkSI^wPW3T&_s>wfPNC7KRWRw*$PfB(QXJj;eM*fv}IOhfV26xXzobG%n zjC8ckZ&nUq=sOaT2=X7L@5V0_VfddBOoBRMt-`;MNjwk#2QLM_OmQkcwX=8kG-S|+ ze0*;SKc^&)SR$d=EF-J}{Z@hRq_Eu--e)nqOe@LpJt4VP=JfQ&4~8$~pvEd}dZ0&n z;2C5|pIY>+490(*`=9OgtPkf}ankNC!`PQbgY<|kx-MOSYHZBG%k`SFd6>P6>Zi-=zx@Sgl^_4a1{5Bk6>f?WNz`X600SBavr zdwz*1W#|_%)fI_3^YQb-Z`8?t&~w%4h+Ej)tVCa~-|Qb4%(|1Y0eg66lPtLCV$Lkd zX|7QmiY_pnw5386DMfzM zr*FPUWOr1%RhhMIMsTllaKtyzSs{15I9FT7oRcPM|&2Vt#t z*EDR`pXsuIqgCGN^96?@ai5dQ_?URjEk$hH_48;=47Wj{jsO^6v5`!}FPl7eb$s{B zpc=r{+L9Cl`}kXWT(Pew16jWu%{+TVuAMm2l>? z^4<4kDJsP~c_J^FPYs@UpY6n$7Nue*cZ`iU$YvY8`BapVA)GAwF%R1BrfU_vT{-Td z{~*21RI<$tR;eF8*;)mPkfMbUfL2Z8y;+=Zj6PNoX3O^-;R9k2P1)J0H)oB`^@d|uC-_ItY{X756rF?#s( zIGaSBh{-Rnd;1Im{i42p?1wjpQa^#yAe1l*PId`v;e7tX%(v^ z$)+j{>v0Kgn%CjJ9k&6_@Gdo;HhEalG1bg;G*#-U%-rVrAN;^sH8=Msj9}sp&zPrg zlFt-URWypRg;phmF77C>I=eR|Nd)|IAv>ySzs1q#;~K?@hMLS-MBA6v)X$f%;tqT~ zA)FY*sV1deb~eskFG7YDO?VEf%!mYj04g-; z&jYSc2o}vsTv9`{&SC-Cqpx{d&D*8%gTeIR(C79};*}qrpR-k`^@{VYZP-d9fA}^n zl}T@oWPQmMzH0vp&Rj^HK5LU$K-1aimGh)KWc~1O-==_JVBlwrjzp#gIa8k86OS>p zKmh6p!RICfNP>eNe7YVsmUg4WtYy$-MSj|Jgr5NFXZ z;E1f;J8;UAUEuU}NB^}WDuThNBIk|ga|T@nO1xKFi|65g!fT*xbR-H$*s&AhwnKSh z2P6{`o{4Rrs8h;KJO`pO;}0LawEWiNuN0}R3;CndTzr7uaB_RMrpp6}*xw}#=C1EK zljN+Xm3vRYCAlwrlOE0F>v_V`X4XQ^M(ryWy;Q&Llv-aO7L|4{`|G~bURs4-XjJmD zN@-!hgTT*5V&{Pfx-ECa8Z?dO$74#~@>G#$-^g9xt=~3Fz}Dpinkhb6Vs`^01&=n) znS?ZN@C%;LZpUvJJStGk`&WUI{iONp0_;3U_v9bttA(bhHN4D!66VHlkQxzx&jr%w z0?H74I+XTV-xpnP0BkR`knhwfqCG@9Aw}?Sng*_<|?wWM8HV{aB2ymnlPC7qGA z`?Ortkn}49@A?m>2qgda=xGUa=iMVdkt4Ga2G3TUeuv-=ua1j45wWWG$|En@SlIl< z`aonZ$d|c*_Q4*#b_FhR?8I6N?HNEy%|@ zNAn?;TLSH&?%4NRh2?V)f)V@|VvOO26`zu}9)xv~o`oczCpfAa zvXbA(8CW_7sD@JA1D_K;T!$y(}JI}sWu)vmWiq* z4ncAAOR;{Y{kF=}udE8M@*InNXOH~?P>|e-RO|fhcTv%~q?|O9 zsQ%!6r$gJ*ug;I>qEF8`BO|ZtJRh_IAx$d|{CLHh{?e(Y@Xf1G1$Dd~m46D4Q)~{@ zPd{`S4C~ZyQgnJPC)u2R-cJaNd-bL;hRZihX06T^EMOoHgTEpmqMy_7RPq66R5$o9 zNlZ648jp=P5X4?+souk+I?ZkQWA(7l3+Xh;Xx_QSaJWUJ0-|MkM4J% zj&^8oO4IwxH+DWSP%J0PO~%TrrKj3f?mwG0C()>lVtKpxQlC?)R?aiT<5k`nUm#^Y&MO<9s9D)MnN2vP(S9)lao8$kb*HlGS�LrF1@zn14Tn+T~3I} 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�GP2Tm*aW(yeI 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 Thf*UzQ#D6 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±+pw5+CuUHyJO9TYr=Re^PC}g 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
APACHE_LICENSE_HEADER
+ + SLASHSTAR_STYLE + SLASHSTAR_STYLE + + + cpp/**/*.h + cpp/**/*.cpp + + + cpp/libs/include/opendnp3/gen/* + cpp/libs/src/opendnp3/gen/* + cpp/libs/src/opendnp3/objects/* + + + + + + check + + + + + + + + + + diff --git a/utils/dnp3_src/config/gecapache.licenseheader b/utils/dnp3_src/config/gecapache.licenseheader new file mode 100644 index 0000000..a998814 --- /dev/null +++ b/utils/dnp3_src/config/gecapache.licenseheader @@ -0,0 +1,23 @@ + +extensions: .cs .cpp .h + +// +// Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +// more contributor license agreements. See the NOTICE file distributed +// with this work for additional information regarding copyright ownership. +// Green Energy Corp licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file was forked on 01/01/2013 by Automatak, LLC and modifications +// have been made to this file. Automatak, LLC licenses these modifications to +// you under the terms of the License. +// diff --git a/utils/dnp3_src/config/src-footer.inc b/utils/dnp3_src/config/src-footer.inc new file mode 100644 index 0000000..9e9e30d --- /dev/null +++ b/utils/dnp3_src/config/src-footer.inc @@ -0,0 +1,2 @@ + +/* vim: set ts=4 sw=4: */ diff --git a/utils/dnp3_src/config/src-header.inc b/utils/dnp3_src/config/src-header.inc new file mode 100644 index 0000000..a9bfa01 --- /dev/null +++ b/utils/dnp3_src/config/src-header.inc @@ -0,0 +1,17 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. Green Enery + * Corp licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + diff --git a/utils/dnp3_src/cpp/examples/decoder/main.cpp b/utils/dnp3_src/cpp/examples/decoder/main.cpp new file mode 100644 index 0000000..bcc542c --- /dev/null +++ b/utils/dnp3_src/cpp/examples/decoder/main.cpp @@ -0,0 +1,92 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace openpal; +using namespace opendnp3; +using namespace asiodnp3; + +enum class Mode +{ + Link, + Transport, + App +}; + +Mode GetMode(const std::string& mode) +{ + if (mode == "link") + { + return Mode::Link; + } + else if (mode == "transport") + { + return Mode::Transport; + } + else + { + return Mode::App; + } +} + +int main(int argc, char* argv[]) +{ + openpal::Logger logger(ConsoleLogger::Create(), "decoder", LogFilters(~0)); + IDecoderCallbacks callback; + Decoder decoder(callback, logger); + + Buffer buffer(4096); + + const Mode MODE = (argc > 1) ? GetMode(argv[1]) : Mode::Link; + + while (true) + { + const size_t NUM_READ = fread(buffer(), 1, buffer.Size(), stdin); + + if (NUM_READ == 0) + { + return 0; + } + + switch (MODE) + { + case(Mode::Link): + decoder.DecodeLPDU(buffer.ToRSlice().Take(NUM_READ)); + break; + case(Mode::Transport) : + decoder.DecodeTPDU(buffer.ToRSlice().Take(NUM_READ)); + break; + default: + decoder.DecodeAPDU(buffer.ToRSlice().Take(NUM_READ)); + break; + } + } + + return 0; +} + diff --git a/utils/dnp3_src/cpp/examples/master-gprs/main.cpp b/utils/dnp3_src/cpp/examples/master-gprs/main.cpp new file mode 100644 index 0000000..1b3661a --- /dev/null +++ b/utils/dnp3_src/cpp/examples/master-gprs/main.cpp @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace openpal; +using namespace asiopal; +using namespace asiodnp3; +using namespace opendnp3; + +int main(int argc, char* argv[]) +{ + // Specify what log levels to use. NORMAL is warning and above + // You can add all the comms logging by uncommenting below + const uint32_t FILTERS = levels::NORMAL | levels::ALL_COMMS; + + const auto NUM_THREAD = std::thread::hardware_concurrency(); + + auto callbacks = std::make_shared(); + + // This is the main point of interaction with the stack + DNP3Manager manager(NUM_THREAD, ConsoleLogger::Create()); + + std::error_code ec; + auto server1 = manager.CreateListener("server-20000", FILTERS, IPEndpoint::AllAdapters(20000), callbacks, ec); + + if (ec) + { + std::cout << ec.message() << std::endl; + return ec.value(); + } + + do + { + std::cout << "Enter a command" << std::endl; + std::cout << "x - exits program" << std::endl; + + char cmd; + std::cin >> cmd; + switch(cmd) + { + case('x'): + return 0; + default: + std::cout << "Unknown action: " << cmd << std::endl; + break; + } + } + while(true); + + return 0; +} + diff --git a/utils/dnp3_src/cpp/examples/master/main.cpp b/utils/dnp3_src/cpp/examples/master/main.cpp new file mode 100644 index 0000000..798b329 --- /dev/null +++ b/utils/dnp3_src/cpp/examples/master/main.cpp @@ -0,0 +1,165 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace openpal; +using namespace asiopal; +using namespace asiodnp3; +using namespace opendnp3; + +int main(int argc, char* argv[]) +{ + // Specify what log levels to use. NORMAL is warning and above + // You can add all the comms logging by uncommenting below + const uint32_t FILTERS = levels::NORMAL | levels::ALL_APP_COMMS; + + // This is the main point of interaction with the stack + DNP3Manager manager(1, ConsoleLogger::Create()); + + // Connect via a TCPClient socket to a outstation + auto channel = manager.AddTCPClient("tcpclient", FILTERS, ChannelRetry::Default(), "127.0.0.1", "0.0.0.0", 20000, PrintingChannelListener::Create()); + + // The master config object for a master. The default are + // useable, but understanding the options are important. + MasterStackConfig stackConfig; + + // you can override application layer settings for the master here + // in this example, we've change the application layer timeout to 2 seconds + stackConfig.master.responseTimeout = TimeDuration::Seconds(2); + stackConfig.master.disableUnsolOnStartup = true; + + // You can override the default link layer settings here + // in this example we've changed the default link layer addressing + stackConfig.link.LocalAddr = 1; + stackConfig.link.RemoteAddr = 10; + + // Create a new master on a previously declared port, with a + // name, log level, command acceptor, and config info. This + // returns a thread-safe interface used for sending commands. + auto master = channel->AddMaster( + "master", // id for logging + PrintingSOEHandler::Create(), // callback for data processing + asiodnp3::DefaultMasterApplication::Create(), // master application instance + stackConfig // stack configuration + ); + + + // do an integrity poll (Class 3/2/1/0) once per minute + auto integrityScan = master->AddClassScan(ClassField::AllClasses(), TimeDuration::Minutes(1)); + + // do a Class 1 exception poll every 5 seconds + auto exceptionScan = master->AddClassScan(ClassField(ClassField::CLASS_1), TimeDuration::Seconds(2)); + + // Enable the master. This will start communications. + master->Enable(); + + bool channelCommsLoggingEnabled = true; + bool masterCommsLoggingEnabled = true; + + while (true) + { + std::cout << "Enter a command" << std::endl; + std::cout << "x - exits program" << std::endl; + std::cout << "a - performs and ad-hoc range scan" << std::endl; + std::cout << "i - integrity demand scan" << std::endl; + std::cout << "e - exception demand scan" << std::endl; + std::cout << "d - diable unsolcited" << std::endl; + std::cout << "r - cold restart" << std::endl; + std::cout << "c - send crob" << std::endl; + + char cmd; + std::cin >> cmd; + switch(cmd) + { + case('a') : + master->ScanRange(GroupVariationID(1, 2), 0, 3); + break; + case('d') : + master->PerformFunction("disable unsol", FunctionCode::DISABLE_UNSOLICITED, + { Header::AllObjects(60, 2), Header::AllObjects(60, 3), Header::AllObjects(60, 4) } + ); + break; + case('r') : + { + auto print = [](const RestartOperationResult & result) + { + if(result.summary == TaskCompletion::SUCCESS) + { + std::cout << "Success, Time: " << result.restartTime.GetMilliseconds() << std::endl; + } + else + { + std::cout << "Failure: " << TaskCompletionToString(result.summary) << std::endl; + } + }; + master->Restart(RestartType::COLD, print); + break; + } + case('x'): + // C++ destructor on DNP3Manager cleans everything up for you + return 0; + case('i'): + integrityScan->Demand(); + break; + case('e'): + exceptionScan->Demand(); + break; + case('c'): + { + ControlRelayOutputBlock crob(ControlCode::LATCH_ON); + master->SelectAndOperate(crob, 0, PrintingCommandCallback::Get()); + break; + } + case('t') : + { + channelCommsLoggingEnabled = !channelCommsLoggingEnabled; + auto levels = channelCommsLoggingEnabled ? levels::ALL_COMMS : levels::NORMAL; + channel->SetLogFilters(levels); + std::cout << "Channel logging set to: " << levels << std::endl; + break; + } + case('u') : + { + masterCommsLoggingEnabled = !masterCommsLoggingEnabled; + auto levels = masterCommsLoggingEnabled ? levels::ALL_COMMS : levels::NORMAL; + master->SetLogFilters(levels); + std::cout << "Master logging set to: " << levels << std::endl; + break; + } + default: + std::cout << "Unknown action: " << cmd << std::endl; + break; + } + } + + return 0; +} + diff --git a/utils/dnp3_src/cpp/examples/outstation/main.cpp b/utils/dnp3_src/cpp/examples/outstation/main.cpp new file mode 100644 index 0000000..17a9f52 --- /dev/null +++ b/utils/dnp3_src/cpp/examples/outstation/main.cpp @@ -0,0 +1,166 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; +using namespace asiopal; +using namespace asiodnp3; + +void ConfigureDatabase(DatabaseConfig& config) +{ + // example of configuring analog index 0 for Class2 with floating point variations by default + config.analog[0].clazz = PointClass::Class2; + config.analog[0].svariation = StaticAnalogVariation::Group30Var5; + config.analog[0].evariation = EventAnalogVariation::Group32Var7; +} + +struct State +{ + uint32_t count = 0; + double value = 0; + bool binary = false; + DoubleBit dbit = DoubleBit::DETERMINED_OFF; +}; + +void AddUpdates(UpdateBuilder& builder, State& state, const std::string& arguments); + + + +int main(int argc, char* argv[]) +{ + + // Specify what log levels to use. NORMAL is warning and above + // You can add all the comms logging by uncommenting below. + const uint32_t FILTERS = levels::NORMAL | levels::ALL_COMMS; + + // This is the main point of interaction with the stack + // Allocate a single thread to the pool since this is a single outstation + // Log messages to the console + DNP3Manager manager(1, ConsoleLogger::Create()); + + // Create a TCP server (listener) + auto channel = manager.AddTCPServer("server", FILTERS, ChannelRetry::Default(), "0.0.0.0", 20000, PrintingChannelListener::Create()); + + // The main object for a outstation. The defaults are useable, + // but understanding the options are important. + OutstationStackConfig config(DatabaseSizes::AllTypes(10)); + + // Specify the maximum size of the event buffers + config.outstation.eventBufferConfig = EventBufferConfig::AllTypes(10); + + // you can override an default outstation parameters here + // in this example, we've enabled the oustation to use unsolicted reporting + // if the master enables it + config.outstation.params.allowUnsolicited = true; + + // You can override the default link layer settings here + // in this example we've changed the default link layer addressing + config.link.LocalAddr = 10; + config.link.RemoteAddr = 1; + + config.link.KeepAliveTimeout = openpal::TimeDuration::Max(); + + // You can optionally change the default reporting variations or class assignment prior to enabling the outstation + ConfigureDatabase(config.dbConfig); + + // Create a new outstation with a log level, command handler, and + // config info this returns a thread-safe interface used for + // updating the outstation's database. + auto outstation = channel->AddOutstation("outstation", SuccessCommandHandler::Create(), DefaultOutstationApplication::Create(), config); + + // Enable the outstation and start communications + outstation->Enable(); + + // variables used in example loop + string input; + State state; + + while (true) + { + std::cout << "Enter one or more measurement changes then press " << std::endl; + std::cout << "c = counter, b = binary, d = doublebit, a = analog, 'quit' = exit" << std::endl; + std::cin >> input; + + if (input == "quit") return 0; // DNP3Manager destructor cleanups up everything automatically + else + { + // update measurement values based on input string + UpdateBuilder builder; + AddUpdates(builder, state, input); + outstation->Apply(builder.Build()); + } + } + + return 0; +} + +void AddUpdates(UpdateBuilder& builder, State& state, const std::string& arguments) +{ + for (const char& c : arguments) + { + switch (c) + { + case('c'): + { + builder.Update(Counter(state.count), 0); + ++state.count; + break; + } + case('a'): + { + builder.Update(Analog(state.value), 0); + state.value += 1; + break; + } + case('b'): + { + builder.Update(Binary(state.binary), 0); + state.binary = !state.binary; + break; + } + case('d'): + { + builder.Update(DoubleBitBinary(state.dbit), 0); + state.dbit = (state.dbit == DoubleBit::DETERMINED_OFF) ? DoubleBit::DETERMINED_ON : DoubleBit::DETERMINED_OFF; + break; + } + default: + break; + } + } +} diff --git a/utils/dnp3_src/cpp/examples/tls/master-gprs/main.cpp b/utils/dnp3_src/cpp/examples/tls/master-gprs/main.cpp new file mode 100644 index 0000000..9cc0869 --- /dev/null +++ b/utils/dnp3_src/cpp/examples/tls/master-gprs/main.cpp @@ -0,0 +1,104 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace openpal; +using namespace asiopal; +using namespace asiodnp3; +using namespace opendnp3; + +int main(int argc, char* argv[]) +{ + if (argc != 4) + { + std::cout << "usage: master-gprs-tls-demo " << std::endl; + return -1; + } + + std::string caCertificate(argv[1]); + std::string certificateChain(argv[2]); + std::string privateKey(argv[3]); + + + std::cout << "Using CA certificate: " << caCertificate << std::endl; + std::cout << "Using certificate chain: " << certificateChain << std::endl; + std::cout << "Using private key file: " << privateKey << std::endl; + + // Specify what log levels to use. NORMAL is warning and above + // You can add all the comms logging by uncommenting below + const uint32_t FILTERS = levels::NORMAL | levels::ALL_COMMS; + + const auto NUM_THREAD = std::thread::hardware_concurrency(); + + auto callbacks = std::make_shared(); + + // This is the main point of interaction with the stack + DNP3Manager manager(NUM_THREAD, ConsoleLogger::Create()); + + std::error_code ec; + auto server1 = manager.CreateListener( + "server-20001", + FILTERS, + IPEndpoint::AllAdapters(20001), + TLSConfig( + caCertificate, + certificateChain, + privateKey, + 2 + ), + callbacks, + ec + ); + + if (ec) + { + std::cout << ec.message() << std::endl; + return ec.value(); + } + + do + { + std::cout << "Enter a command" << std::endl; + std::cout << "x - exits program" << std::endl; + + char cmd; + std::cin >> cmd; + switch(cmd) + { + case('x'): + return 0; + default: + std::cout << "Unknown action: " << cmd << std::endl; + break; + } + } + while(true); + + return 0; +} + diff --git a/utils/dnp3_src/cpp/examples/tls/master/main.cpp b/utils/dnp3_src/cpp/examples/tls/master/main.cpp new file mode 100644 index 0000000..ba60f7b --- /dev/null +++ b/utils/dnp3_src/cpp/examples/tls/master/main.cpp @@ -0,0 +1,178 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace openpal; +using namespace asiopal; +using namespace asiodnp3; +using namespace opendnp3; + +int main(int argc, char* argv[]) +{ + if (argc != 3) + { + std::cout << "usage: master-tls-demo " << std::endl; + return -1; + } + + std::string peerCertificate(argv[1]); + std::string privateKey(argv[2]); + + std::cout << "Using peer cert: " << peerCertificate << std::endl; + std::cout << "Using private key file: " << privateKey << std::endl; + + + // Specify what log levels to use. NORMAL is warning and above + // You can add all the comms logging by uncommenting below + const uint32_t FILTERS = levels::NORMAL | levels::ALL_APP_COMMS; + + // This is the main point of interaction with the stack + // send log messages to the console + DNP3Manager manager(1, ConsoleLogger::Create()); + + std::error_code ec; + + // Connect via a TCPClient socket to a outstation + auto channel = manager.AddTLSClient( + "tls-client", + FILTERS, + ChannelRetry::Default(), + "127.0.0.1", + "0.0.0.0", + 20001, + TLSConfig(peerCertificate, privateKey, privateKey), + PrintingChannelListener::Create(), + ec + ); + + if (ec) + { + std::cout << "Unable to create tls client: " << ec.message() << std::endl; + return ec.value(); + } + + // The master config object for a master. The default are + // useable, but understanding the options are important. + MasterStackConfig stackConfig; + + // you can override application layer settings for the master here + // in this example, we've change the application layer timeout to 2 seconds + stackConfig.master.responseTimeout = TimeDuration::Seconds(2); + stackConfig.master.disableUnsolOnStartup = true; + + // You can override the default link layer settings here + // in this example we've changed the default link layer addressing + stackConfig.link.LocalAddr = 1; + stackConfig.link.RemoteAddr = 10; + + // Create a new master on a previously declared port, with a + // name, log level, command acceptor, and config info. This + // returns a thread-safe interface used for sending commands. + auto master = channel->AddMaster( + "master", // id for logging + PrintingSOEHandler::Create(), // callback for data processing + asiodnp3::DefaultMasterApplication::Create(), // master application instance + stackConfig // stack configuration + ); + + + // do an integrity poll (Class 3/2/1/0) once per minute + auto integrityScan = master->AddClassScan(ClassField::AllClasses(), TimeDuration::Minutes(1)); + + // do a Class 1 exception poll every 5 seconds + auto exceptionScan = master->AddClassScan(ClassField(ClassField::CLASS_1), TimeDuration::Seconds(2)); + + // Enable the master. This will start communications. + master->Enable(); + + do + { + std::cout << "Enter a command" << std::endl; + std::cout << "x - exits program" << std::endl; + std::cout << "a - performs and ad-hoc range scan" << std::endl; + std::cout << "i - integrity demand scan" << std::endl; + std::cout << "e - exception demand scan" << std::endl; + std::cout << "d - diable unsolcited" << std::endl; + std::cout << "r - cold restart" << std::endl; + std::cout << "c - send crob" << std::endl; + + char cmd; + std::cin >> cmd; + switch(cmd) + { + case('a') : + master->ScanRange(GroupVariationID(1, 2), 0, 3); + break; + case('d') : + master->PerformFunction("disable unsol", FunctionCode::DISABLE_UNSOLICITED, + { Header::AllObjects(60, 2), Header::AllObjects(60, 3), Header::AllObjects(60, 4) } + ); + break; + case('r') : + { + auto print = [](const RestartOperationResult & result) + { + if(result.summary == TaskCompletion::SUCCESS) + { + std::cout << "Success, Time: " << result.restartTime.GetMilliseconds() << std::endl; + } + else + { + std::cout << "Failure: " << TaskCompletionToString(result.summary) << std::endl; + } + }; + master->Restart(RestartType::COLD, print); + break; + } + case('x'): + // C++ destructor on DNP3Manager cleans everything up for you + return 0; + case('i'): + integrityScan->Demand(); + break; + case('e'): + exceptionScan->Demand(); + break; + case('c'): + { + ControlRelayOutputBlock crob(ControlCode::LATCH_ON); + master->SelectAndOperate(crob, 0, PrintingCommandCallback::Get()); + break; + } + default: + std::cout << "Unknown action: " << cmd << std::endl; + break; + } + } + while(true); + + return 0; +} diff --git a/utils/dnp3_src/cpp/examples/tls/outstation/main.cpp b/utils/dnp3_src/cpp/examples/tls/outstation/main.cpp new file mode 100644 index 0000000..86e8d03 --- /dev/null +++ b/utils/dnp3_src/cpp/examples/tls/outstation/main.cpp @@ -0,0 +1,196 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; +using namespace asiopal; +using namespace asiodnp3; + +void ConfigureDatabase(DatabaseConfig& config) +{ + // example of configuring analog index 0 for Class2 with floating point variations by default + config.analog[0].clazz = PointClass::Class2; + config.analog[0].svariation = StaticAnalogVariation::Group30Var5; + config.analog[0].evariation = EventAnalogVariation::Group32Var7; +} + +struct State +{ + uint32_t count = 0; + double value = 0; + bool binary = false; + DoubleBit dbit = DoubleBit::DETERMINED_OFF; +}; + +void AddUpdates(UpdateBuilder& builder, State& state, const std::string& arguments); + +int main(int argc, char* argv[]) +{ + if (argc != 4) + { + std::cout << "usage: master-gprs-tls-demo " << std::endl; + return -1; + } + + std::string caCertificate(argv[1]); + std::string certificateChain(argv[2]); + std::string privateKey(argv[3]); + + std::cout << "Using CA certificate: " << caCertificate << std::endl; + std::cout << "Using certificate chain: " << certificateChain << std::endl; + std::cout << "Using private key file: " << privateKey << std::endl; + + // Specify what log levels to use. NORMAL is warning and above + // You can add all the comms logging by uncommenting below. + const uint32_t FILTERS = levels::NORMAL; // | levels::ALL_COMMS; + + // This is the main point of interaction with the stack + // Allocate a single thread to the pool since this is a single outstation + DNP3Manager manager(1, ConsoleLogger::Create()); + + std::error_code ec; + + // Create a TCP server (listener) + auto channel = manager.AddTLSClient( + "server", + FILTERS, + ChannelRetry::Default(), + "127.0.0.1", + "0.0.0.0", + 20001, + TLSConfig( + caCertificate, + certificateChain, + privateKey, + 2 + ), + PrintingChannelListener::Create(), + ec + ); + + if (ec) + { + std::cout << "Unable to create tls server: " << ec.message() << std::endl; + return ec.value(); + } + + // The main object for a outstation. The defaults are useable, + // but understanding the options are important. + OutstationStackConfig stackConfig(DatabaseSizes::AllTypes(10)); + + // specify the maximum size of the event buffers + stackConfig.outstation.eventBufferConfig = EventBufferConfig::AllTypes(10); + + // you can override an default outstation parameters here + // in this example, we've enabled the oustation to use unsolicted reporting + // if the master enables it + stackConfig.outstation.params.allowUnsolicited = true; + + // You can override the default link layer settings here + // in this example we've changed the default link layer addressing + stackConfig.link.LocalAddr = 10; + stackConfig.link.RemoteAddr = 1; + + // You can optionally change the default reporting variations or class assignment prior to enabling the outstation + ConfigureDatabase(stackConfig.dbConfig); + + // Create a new outstation with a log level, command handler, and + // config info this returns a thread-safe interface used for + // updating the outstation's database. + auto outstation = channel->AddOutstation("outstation", SuccessCommandHandler::Create(), DefaultOutstationApplication::Create(), stackConfig); + + // Enable the outstation and start communications + outstation->Enable(); + + // variables used in example loop + string input; + State state; + + while (true) + { + std::cout << "Enter one or more measurement changes then press " << std::endl; + std::cout << "c = counter, b = binary, d = doublebit, a = analog, 'quit' = exit" << std::endl; + std::cin >> input; + + if (input == "quit") return 0; + else + { + UpdateBuilder builder; + AddUpdates(builder, state, input); + outstation->Apply(builder.Build()); + } + } + + return 0; +} + +void AddUpdates(UpdateBuilder& builder, State& state, const std::string& arguments) +{ + for (const char& c : arguments) + { + switch (c) + { + case('c'): + { + builder.Update(Counter(state.count), 0); + ++state.count; + break; + } + case('a'): + { + builder.Update(Analog(state.value), 0); + state.value += 1; + break; + } + case('b'): + { + builder.Update(Binary(state.binary), 0); + state.binary = !state.binary; + break; + } + case('d'): + { + builder.Update(DoubleBitBinary(state.dbit), 0); + state.dbit = (state.dbit == DoubleBit::DETERMINED_OFF) ? DoubleBit::DETERMINED_ON : DoubleBit::DETERMINED_OFF; + break; + } + default: + break; + } + } +} diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/ConsoleLogger.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/ConsoleLogger.h new file mode 100644 index 0000000..3b8e085 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/ConsoleLogger.h @@ -0,0 +1,61 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_CONSOLELOGGER_H +#define ASIODNP3_CONSOLELOGGER_H + +#include +#include + +#include +#include + +namespace asiodnp3 +{ + +std::ostringstream& operator<<(std::ostringstream& ss, const openpal::LogFilters& filters); + +/** +* LogHandler that prints all log messages to the console +*/ +class ConsoleLogger final : public openpal::ILogHandler, private openpal::Uncopyable +{ + +public: + + virtual void Log(const openpal::LogEntry& entry) override; + + static std::shared_ptrCreate(bool printLocation = false) + { + return std::make_shared(printLocation); + }; + + ConsoleLogger(bool printLocation) : printLocation(printLocation) {} + +private: + + bool printLocation; + + std::mutex mutex; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/DNP3Manager.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/DNP3Manager.h new file mode 100644 index 0000000..51b54a9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/DNP3Manager.h @@ -0,0 +1,221 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_DNP3MANAGER_H +#define ASIODNP3_DNP3MANAGER_H + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace asiodnp3 +{ + +class DNP3ManagerImpl; + + +/** +* Root DNP3 object used to create channels and sessions. +*/ +class DNP3Manager +{ + +public: + + /** + * Construct a manager + * + * @param concurrencyHint How many threads to allocate in the thread pool + * @param handler Callback interface for log messages + * @param onThreadStart Action to run when a thread pool thread starts + * @param onThreadExit Action to run just before a thread pool thread exits + */ + DNP3Manager( + uint32_t concurrencyHint, + std::shared_ptr handler = std::shared_ptr(), + std::function onThreadStart = []() {}, + std::function onThreadExit = []() {} + ); + + ~DNP3Manager(); + + + /** + * Permanently shutdown the manager and all sub-objects that have been created. Stop + * the thead pool. + */ + void Shutdown(); + + /** + * Add a persistent TCP client channel. Automatically attempts to reconnect. + * + * @param id Alias that will be used for logging purposes with this channel + * @param levels Bitfield that describes the logging level for this channel and associated sessions + * @param retry Retry parameters for failed channels + * @param host IP address of remote outstation (i.e. 127.0.0.1 or www.google.com) + * @param local adapter address on which to attempt the connection (use 0.0.0.0 for all adapters) + * @param port Port of remote outstation is listening on + * @param listener optional callback interface (can be nullptr) for info about the running channel + * @return shared_ptr to a channel interface + */ + std::shared_ptr AddTCPClient( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + std::shared_ptr listener); + + /** + * Add a persistent TCP server channel. Only accepts a single connection at a time. + * + * @param id Alias that will be used for logging purposes with this channel + * @param levels Bitfield that describes the logging level for this channel and associated sessions + * @param retry Retry parameters for failed channels + * @param endpoint Network adapter to listen on, i.e. 127.0.0.1 or 0.0.0.0 + * @param port Port to listen on + * @param listener optional callback interface (can be nullptr) for info about the running channel + * @return shared_ptr to a channel interface + */ + std::shared_ptr AddTCPServer( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + std::shared_ptr listener); + + /** + * Add a persistent TCP serial channel + * + * @param id Alias that will be used for logging purposes with this channel + * @param levels Bitfield that describes the logging level for this channel and associated sessions + * @param retry Retry parameters for failed channels + * @param settings settings object that fully parameterizes the serial port + * @param listener optional callback interface (can be nullptr) for info about the running channel + * @return shared_ptr to a channel interface + */ + std::shared_ptr AddSerial( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + asiopal::SerialSettings settings, + std::shared_ptr listener); + + /** + * Add a TLS client channel + * + * @throw std::system_error Throws underlying ASIO exception of TLS configuration is invalid + * + * @param id Alias that will be used for logging purposes with this channel + * @param levels Bitfield that describes the logging level for this channel and associated sessions + * @param retry Retry parameters for failed channels + * @param host IP address of remote outstation (i.e. 127.0.0.1 or www.google.com) + * @param local adapter address on which to attempt the connection (use 0.0.0.0 for all adapters) + * @param port Port of remote outstation is listening on + * @param config TLS configuration information + * @param listener optional callback interface (can be nullptr) for info about the running channel + * @param ec An error code. If set, a nullptr will be returned + * @return shared_ptr to a channel interface + */ + std::shared_ptr AddTLSClient( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + const asiopal::TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec); + + + /** + * Add a TLS server channel + * + * @throw std::system_error Throws underlying ASIO exception of TLS configuration is invalid + * + * @param id Alias that will be used for logging purposes with this channel + * @param levels Bitfield that describes the logging level for this channel and associated sessions + * @param retry Retry parameters for failed channels + * @param endpoint Network adapter to listen on, i.e. 127.0.0.1 or 0.0.0.0 + * @param port Port to listen on + * @param config TLS configuration information + * @param listener optional callback interface (can be nullptr) for info about the running channel + * @param ec An error code. If set, a nullptr will be returned + * @return shared_ptr to a channel interface + */ + std::shared_ptr AddTLSServer( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + const asiopal::TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec); + + /** + * Create a TCP listener that will be used to accept incoming connections + */ + std::shared_ptr CreateListener( + std::string loggerid, + openpal::LogFilters loglevel, + asiopal::IPEndpoint endpoint, + std::shared_ptr callbacks, + std::error_code& ec + ); + + /** + * Create a TLS listener that will be used to accept incoming connections + */ + std::shared_ptr CreateListener( + std::string loggerid, + openpal::LogFilters loglevel, + asiopal::IPEndpoint endpoint, + const asiopal::TLSConfig& config, + std::shared_ptr callbacks, + std::error_code& ec + ); + +private: + + std::unique_ptr impl; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/DatabaseConfig.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/DatabaseConfig.h new file mode 100644 index 0000000..7d6ccea --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/DatabaseConfig.h @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_DATABASECONFIG_H +#define ASIODNP3_DATABASECONFIG_H + +#include "opendnp3/outstation/MeasurementConfig.h" + +#include "opendnp3/outstation/DatabaseSizes.h" + +#include "openpal/container/Array.h" + +namespace asiodnp3 +{ + +class DatabaseConfig +{ +public: + + DatabaseConfig(const opendnp3::DatabaseSizes& sizes) : + sizes(sizes), + binary(sizes.numBinary), + doubleBinary(sizes.numDoubleBinary), + analog(sizes.numAnalog), + counter(sizes.numCounter), + frozenCounter(sizes.numFrozenCounter), + boStatus(sizes.numBinaryOutputStatus), + aoStatus(sizes.numAnalogOutputStatus), + timeAndInterval(sizes.numTimeAndInterval) + { + InitIndices(binary); + InitIndices(doubleBinary); + InitIndices(analog); + InitIndices(counter); + InitIndices(frozenCounter); + InitIndices(boStatus); + InitIndices(aoStatus); + InitIndices(timeAndInterval); + } + + const opendnp3::DatabaseSizes sizes; + + openpal::Array binary; + openpal::Array doubleBinary; + openpal::Array analog; + openpal::Array counter; + openpal::Array frozenCounter; + openpal::Array boStatus; + openpal::Array aoStatus; + openpal::Array timeAndInterval; + +private: + + template + void InitIndices(T& values) + { + for (auto i = 0; i < values.Size(); ++i) + { + values[i].vIndex = i; + } + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultListenCallbacks.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultListenCallbacks.h new file mode 100644 index 0000000..a187898 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultListenCallbacks.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_DEFAULTLISTENCALLBACKS_H +#define ASIODNP3_DEFAULTLISTENCALLBACKS_H + +#include "asiodnp3/IListenCallbacks.h" +#include "asiodnp3/PrintingSOEHandler.h" +#include "asiodnp3/DefaultMasterApplication.h" + +namespace asiodnp3 +{ + +/** +* Callback interface invoked when a new connection is accepted +*/ +class DefaultListenCallbacks final : public IListenCallbacks +{ +public: + + DefaultListenCallbacks(); + + virtual ~DefaultListenCallbacks() {} + + virtual bool AcceptConnection(uint64_t sessionid, const std::string& ipaddress) override; + + virtual bool AcceptCertificate(uint64_t sessionid, const X509Info& info) override; + + virtual openpal::TimeDuration GetFirstFrameTimeout() override; + + virtual void OnFirstFrame(uint64_t sessionid, const opendnp3::LinkHeaderFields& header, ISessionAcceptor& acceptor) override; + + virtual void OnConnectionClose(uint64_t sessionid, const std::shared_ptr& session) override; + + virtual void OnCertificateError(uint64_t sessionid, const X509Info& info, int error) override; + +private: + + std::string SessionIdToString(uint64_t id); +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultMasterApplication.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultMasterApplication.h new file mode 100644 index 0000000..946ebc9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/DefaultMasterApplication.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_DEFAULTMASTERAPPLICATION_H +#define ASIODNP3_DEFAULTMASTERAPPLICATION_H + +#include + +#include + +namespace asiodnp3 +{ + +class DefaultMasterApplication : public opendnp3::IMasterApplication +{ +public: + + DefaultMasterApplication() {} + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + virtual void OnReceiveIIN(const opendnp3::IINField& iin) override final {} + + virtual void OnTaskStart(opendnp3::MasterTaskType type, opendnp3::TaskId id) override final {} + + virtual void OnTaskComplete(const opendnp3::TaskInfo& info) override final {} + + virtual bool AssignClassDuringStartup() override final + { + return false; + } + + virtual void ConfigureAssignClassRequest(const opendnp3::WriteHeaderFunT& fun) override final {} + + virtual openpal::UTCTimestamp Now() override final; + + virtual void OnStateChange(opendnp3::LinkStatus value) override final {} + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/ErrorCodes.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/ErrorCodes.h new file mode 100644 index 0000000..2590479 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/ErrorCodes.h @@ -0,0 +1,79 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIODNP3_ERRORCODES_H +#define ASIODNP3_ERRORCODES_H + +#include + + +namespace asiodnp3 +{ + +enum class Error : int +{ + SHUTTING_DOWN, + NO_TLS_SUPPORT, + NO_SERIAL_SUPPORT +}; + +class ErrorCategory final : public std::error_category +{ +public: + + static const std::error_category& Instance() + { + return instance; + } + + virtual const char* name() const noexcept + { + return "dnp3"; + } + + virtual std::string message(int ev) const; + +private: + + ErrorCategory() {} + ErrorCategory(const ErrorCategory&) = delete; + + static ErrorCategory instance; +}; + +inline std::error_code make_error_code(Error err) +{ + return std::error_code(static_cast(err), ErrorCategory::Instance()); +} + +} + + +namespace std +{ + +template <> +struct is_error_code_enum : public true_type {}; + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IChannel.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IChannel.h new file mode 100644 index 0000000..0f9bf12 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IChannel.h @@ -0,0 +1,105 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_ICHANNEL_H +#define ASIODNP3_ICHANNEL_H + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "asiopal/IResourceManager.h" + +#include "IMaster.h" +#include "IOutstation.h" +#include "MasterStackConfig.h" +#include "OutstationStackConfig.h" + +#include + +namespace asiodnp3 +{ + +/** +* Represents a communication channel upon which masters and outstations can be bound. +*/ +class IChannel : public asiopal::IResource +{ +public: + + virtual ~IChannel() {} + + /** + * Synchronously read the channel statistics + */ + virtual opendnp3::LinkStatistics GetStatistics() = 0; + + /** + * @return The current logger settings for this channel + */ + virtual openpal::LogFilters GetLogFilters() const = 0; + + /** + * @param filters Adjust the filters to this value + */ + virtual void SetLogFilters(const openpal::LogFilters& filters) = 0; + + /** + * Add a master to the channel + * + * @param id An ID that gets used for logging + * @param SOEHandler Callback object for all received measurements + * @param application The master application bound to the master session + * @param config Configuration object that controls how the master behaves + * + * @return shared_ptr to the running master + */ + virtual std::shared_ptr AddMaster(const std::string& id, + std::shared_ptr SOEHandler, + std::shared_ptr application, + const MasterStackConfig& config) = 0; + + /** + * Add an outstation to the channel + * + * @param id An ID that gets used for logging + * @param commandHandler Callback object for handling command requests + * @param application Callback object for user code + * @param config Configuration object that controls how the outstation behaves + * @return shared_ptr to the running outstation + */ + virtual std::shared_ptr AddOutstation( const std::string& id, + std::shared_ptr commandHandler, + std::shared_ptr application, + const OutstationStackConfig& config) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IChannelListener.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IChannelListener.h new file mode 100644 index 0000000..f34fa38 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IChannelListener.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_ICHANNELLISTENER_H +#define ASIODNP3_ICHANNELLISTENER_H + +#include + +namespace asiodnp3 +{ + +/** +* Callback interface for receiving information about a running channel +*/ +class IChannelListener +{ +public: + + virtual ~IChannelListener() {} + + /* + * Receive callbacks for state transitions on the channels executor + */ + virtual void OnStateChange(opendnp3::ChannelState state) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IListenCallbacks.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IListenCallbacks.h new file mode 100644 index 0000000..a19e797 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IListenCallbacks.h @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_ILISTENCALLBACKS_H +#define ASIODNP3_ILISTENCALLBACKS_H + +#include +#include + +#include "asiodnp3/ISessionAcceptor.h" +#include "asiodnp3/X509Info.h" + +namespace asiodnp3 +{ + +/** +* Callback interface invoked when a new connection is accepted +*/ +class IListenCallbacks +{ +public: + + virtual ~IListenCallbacks() {} + + /** + * Ask user code if the following connection should be accepted + * + * @param sessionid Incrementing id used to uniquely identify the session + * @param ipaddress The IP address of the connecting host. Can optionally be used for connection filtering + * + * @return If true, the connection is accepted and a link frame parser is created to handle incoming frame data + */ + virtual bool AcceptConnection(uint64_t sessionid, const std::string& ipaddress) = 0; + + /** + * Ask user code if the following preverified certificate should be accepted + * + * @param sessionid Incrementing id used to uniquely identify the session + * @param info Information from the x509 certificate + * + * @return If true, if the certificate should be accepted, false otherwise. + */ + virtual bool AcceptCertificate(uint64_t sessionid, const X509Info& info) = 0; + + /// return the amount of time the session should wait for the first frame + virtual openpal::TimeDuration GetFirstFrameTimeout() = 0; + + /** + * Called when the first link-layer frame is received for a session + */ + virtual void OnFirstFrame( + uint64_t sessionid, + const opendnp3::LinkHeaderFields& header, + ISessionAcceptor& acceptor + ) = 0; + + /** + * Called when a socket closes + * + * @param sessionid Incrementing id used to uniquely identify the session + * @param session Possibly NULL shared_ptr to the master session if it was created + */ + virtual void OnConnectionClose(uint64_t sessionid, const std::shared_ptr& session) = 0; + + /** + * Called when a certificate fails verification + * + * @param sessionid Incrementing id used to uniquely identify the session + * @param info Information from the x509 certificate + * @param error Error code with reason for failed verification + */ + virtual void OnCertificateError(uint64_t sessionid, const X509Info& info, int error) = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IMaster.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMaster.h new file mode 100644 index 0000000..76c1315 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMaster.h @@ -0,0 +1,44 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_IMASTER_H +#define ASIODNP3_IMASTER_H + +#include "asiodnp3/IStack.h" +#include "asiodnp3/IMasterOperations.h" + +namespace asiodnp3 +{ + +/** +* Interface that represents a running master session. +*/ +class IMaster : public IMasterOperations, public IStack +{ +public: + + virtual ~IMaster() {} + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterOperations.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterOperations.h new file mode 100644 index 0000000..f056323 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterOperations.h @@ -0,0 +1,124 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_IMASTEROPERATIONS_H +#define ASIODNP3_IMASTEROPERATIONS_H + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace asiodnp3 +{ + +/** +* All the operations that the user can perform on a running master +*/ +class IMasterOperations : public opendnp3::ICommandProcessor +{ +public: + + virtual ~IMasterOperations() {} + + /** + * @param filters Adjust the filters to this value + */ + virtual void SetLogFilters(const openpal::LogFilters& filters) = 0; + + /** + * Add a recurring user-defined scan from a vector of headers + * @ return A proxy class used to manipulate the scan + */ + virtual std::shared_ptr AddScan(openpal::TimeDuration period, const std::vector& headers, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Add a scan that requests all objects using qualifier code 0x06 + * @ return A proxy class used to manipulate the scan + */ + virtual std::shared_ptr AddAllObjectsScan(opendnp3::GroupVariationID gvId, openpal::TimeDuration period, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Add a class-based scan to the master + * @return A proxy class used to manipulate the scan + */ + virtual std::shared_ptr AddClassScan(const opendnp3::ClassField& field, openpal::TimeDuration period, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Add a start/stop (range) scan to the master + * @return A proxy class used to manipulate the scan + */ + virtual std::shared_ptr AddRangeScan(opendnp3::GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Initiate a single user defined scan via a vector of headers + */ + virtual void Scan(const std::vector& headers, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Initiate a single scan that requests all objects (0x06 qualifier code) for a certain group and variation + */ + virtual void ScanAllObjects(opendnp3::GroupVariationID gvId, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Initiate a single class-based scan + */ + virtual void ScanClasses(const opendnp3::ClassField& field, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + /** + * Initiate a single start/stop (range) scan + */ + virtual void ScanRange(opendnp3::GroupVariationID gvId, uint16_t start, uint16_t stop, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Write a time and interval object to a specific index + */ + virtual void Write(const opendnp3::TimeAndInterval& value, uint16_t index, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Perform a cold or warm restart and get back the time-to-complete value + */ + virtual void Restart(opendnp3::RestartType op, const opendnp3::RestartOperationCallbackT& callback, opendnp3::TaskConfig config = opendnp3::TaskConfig::Default()) = 0; + + /** + * Perform any operation that requires just a function code + */ + virtual void PerformFunction(const std::string& name, opendnp3::FunctionCode func, const std::vector& headers, const opendnp3::TaskConfig& config = opendnp3::TaskConfig::Default()) = 0; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterScan.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterScan.h new file mode 100644 index 0000000..fa56897 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterScan.h @@ -0,0 +1,43 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_IMASTERSCAN_H +#define ASIODNP3_IMASTERSCAN_H + +namespace asiodnp3 +{ + +/** +* Interface for interacting w/ a permanently bound scan +*/ +class IMasterScan +{ +public: + + virtual ~IMasterScan() {} + + /// Request that the scan be performed as soon as possible + virtual bool Demand() = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterSession.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterSession.h new file mode 100644 index 0000000..8528360 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IMasterSession.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_IMASTERSESSION_H +#define ASIODNP3_IMASTERSESSION_H + +#include "asiodnp3/IMasterOperations.h" + +namespace asiodnp3 +{ + +/** +* Interface that represents an emphemeral master session +*/ +class IMasterSession : public IMasterOperations +{ +public: + + virtual ~IMasterSession() {} + + virtual opendnp3::StackStatistics GetStackStatistics() = 0; + + virtual void BeginShutdown() = 0; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IOutstation.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IOutstation.h new file mode 100644 index 0000000..5a19f45 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IOutstation.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_IOUTSTATION_H +#define ASIODNP3_IOUTSTATION_H + +#include "asiodnp3/IStack.h" +#include "asiodnp3/Updates.h" + +#include + +namespace asiodnp3 +{ + +/** +* Interface representing a running outstation. +*/ +class IOutstation : public IStack +{ + friend class MeasUpdate; + +public: + + virtual ~IOutstation() {} + + /** + * @param filters Adjust the filters to this value + */ + virtual void SetLogFilters(const openpal::LogFilters& filters) = 0; + + /** + * Sets the restart IIN bit. Normally applications should not + * touch this bit, but it is provided for simulating restarts. + */ + virtual void SetRestartIIN() = 0; + + /** + * Apply a set of measurement updates to the outstation + */ + virtual void Apply(const Updates& updates) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/ISessionAcceptor.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/ISessionAcceptor.h new file mode 100644 index 0000000..bbb0fb3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/ISessionAcceptor.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_ISESSION_ACCEPTOR_H +#define ASIODNP3_ISESSION_ACCEPTOR_H + +#include +#include + +#include "asiodnp3/MasterStackConfig.h" +#include "asiodnp3/IMasterSession.h" + +#include + +namespace asiodnp3 +{ + +/** +* Callback interface invoked when a new connection is accepted +*/ +class ISessionAcceptor +{ +public: + + virtual ~ISessionAcceptor() {} + + virtual std::shared_ptr AcceptSession( + const std::string& sessionid, + std::shared_ptr SOEHandler, + std::shared_ptr application, + const MasterStackConfig& config + ) = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/IStack.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/IStack.h new file mode 100644 index 0000000..fd39a87 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/IStack.h @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_ISTACK_H +#define ASIODNP3_ISTACK_H + +#include + +#include "asiopal/IResourceManager.h" + +namespace asiodnp3 +{ + +/** +* Base class for masters or outstations +*/ +class IStack : public asiopal::IResource +{ +public: + + virtual ~IStack() {} + + /** + * Synchronously enable communications + */ + virtual bool Enable() = 0; + + /** + * Synchronously disable communications + */ + virtual bool Disable() = 0; + + /** + * @return stack statistics counters + */ + virtual opendnp3::StackStatistics GetStackStatistics() = 0; + +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/MasterStackConfig.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/MasterStackConfig.h new file mode 100644 index 0000000..7bcc534 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/MasterStackConfig.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_MASTERSTACKCONFIG_H +#define ASIODNP3_MASTERSTACKCONFIG_H + +#include "opendnp3/master/MasterParams.h" +#include "opendnp3/link/LinkConfig.h" + +namespace asiodnp3 +{ + +/** A composite configuration struct that contains all the config + information for a dnp3 master stack +*/ +struct MasterStackConfig +{ + MasterStackConfig() : link(true, false) + {} + + /// Master config + opendnp3::MasterParams master; + + /// Link layer config + opendnp3::LinkConfig link; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/MasterTCPServer.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/MasterTCPServer.h new file mode 100644 index 0000000..b3ff0fb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/MasterTCPServer.h @@ -0,0 +1,89 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_MASTERTCPSERVER_H +#define ASIOPAL_MASTERTCPSERVER_H + +#include + +#include +#include +#include +#include + +#include "asiodnp3/IListenCallbacks.h" + +namespace asiodnp3 +{ +/** +* Binds and listens on an IPv4 TCP port +* +* Meant to be used exclusively as a shared_ptr +*/ +class MasterTCPServer final : public asiopal::TCPServer +{ + +public: + + MasterTCPServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const std::shared_ptr& callbacks, + const std::shared_ptr& manager, + std::error_code& ec + ); + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const std::shared_ptr& callbacks, + const std::shared_ptr& manager, + std::error_code& ec) + { + auto server = std::make_shared(logger, executor, endpoint, callbacks, manager, ec); + + if (!ec) + { + server->StartAccept(); + } + + return server; + } + + +private: + + std::shared_ptr callbacks; + std::shared_ptr manager; + + static std::string SessionIdToString(uint64_t sessionid); + + // implement the virutal methods from TCPServer + + virtual void OnShutdown() override; + + virtual void AcceptConnection(uint64_t sessionid, const std::shared_ptr& executor, asio::ip::tcp::socket) override; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/OutstationStackConfig.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/OutstationStackConfig.h new file mode 100644 index 0000000..38ca8d5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/OutstationStackConfig.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONSTACKCONFIG_H +#define OPENDNP3_OUTSTATIONSTACKCONFIG_H + +#include "opendnp3/outstation/OutstationConfig.h" +#include "opendnp3/outstation/EventBufferConfig.h" +#include "opendnp3/outstation/DatabaseSizes.h" +#include "asiodnp3/DatabaseConfig.h" +#include "opendnp3/link/LinkConfig.h" + +namespace asiodnp3 +{ + +/** + A composite configuration struct that contains all the config + information for a dnp3 outstation stack +*/ +struct OutstationStackConfig +{ + + OutstationStackConfig(const opendnp3::DatabaseSizes& dbSizes) : + dbConfig(dbSizes), + link(false, false) + { + + } + + OutstationStackConfig() = delete; + + // Configuration of the database + DatabaseConfig dbConfig; + + /// Outstation config + opendnp3::OutstationConfig outstation; + + /// Link layer config + opendnp3::LinkConfig link; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingChannelListener.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingChannelListener.h new file mode 100644 index 0000000..1b88570 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingChannelListener.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_PRINTINGCHANNELLISTENER_H +#define ASIODNP3_PRINTINGCHANNELLISTENER_H + +#include "asiodnp3/IChannelListener.h" + +#include "openpal/util/Uncopyable.h" + +#include +#include + +namespace asiodnp3 +{ + +/** +* Callback interface for receiving information about a running channel +*/ +class PrintingChannelListener final : public IChannelListener, private openpal::Uncopyable +{ +public: + + virtual void OnStateChange(opendnp3::ChannelState state) override + { + std::cout << "channel state change: " << opendnp3::ChannelStateToString(state) << std::endl; + } + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + PrintingChannelListener() {} + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingCommandCallback.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingCommandCallback.h new file mode 100644 index 0000000..f67e583 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingCommandCallback.h @@ -0,0 +1,41 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_PRINTINGCOMMANDCALLBACK_H +#define ASIODNP3_PRINTINGCOMMANDCALLBACK_H + +#include + +#include + +namespace asiodnp3 +{ + +class PrintingCommandCallback : public openpal::StaticOnly +{ + +public: + static opendnp3::CommandCallbackT Get(); + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingSOEHandler.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingSOEHandler.h new file mode 100644 index 0000000..9e6cc58 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/PrintingSOEHandler.h @@ -0,0 +1,126 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_PRINTINGSOEHANDLER_H +#define ASIODNP3_PRINTINGSOEHANDLER_H + +#include + +#include +#include +#include + +namespace asiodnp3 +{ + +/** +* ISOEHandler singleton that prints to the console. +*/ +class PrintingSOEHandler final : public opendnp3::ISOEHandler +{ + +public: + + PrintingSOEHandler() + {} + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) override; + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection& values) override; + + +protected: + + void Start() final {} + void End() final {} + +private: + + template + static void PrintAll(const opendnp3::HeaderInfo& info, const opendnp3::ICollection>& values) + { + auto print = [&](const opendnp3::Indexed& pair) + { + Print(info, pair.value, pair.index); + }; + values.ForeachItem(print); + } + + template + static void Print(const opendnp3::HeaderInfo& info, const T& value, uint16_t index) + { + std::cout << "[" << index << "] : " << + ValueToString(value) << " : " << + static_cast(value.flags.value) << " : " << + value.time << std::endl; + } + + template + static std::string ValueToString(const T& meas) + { + std::ostringstream oss; + oss << meas.value; + return oss.str(); + } + + static std::string GetTimeString(opendnp3::TimestampMode tsmode) + { + std::ostringstream oss; + switch (tsmode) + { + case(opendnp3::TimestampMode::SYNCHRONIZED) : + return "synchronized"; + break; + case(opendnp3::TimestampMode::UNSYNCHRONIZED) : + oss << "unsynchronized"; + break; + default: + oss << "no timestamp"; + break; + } + + return oss.str(); + } + + static std::string ValueToString(const opendnp3::DoubleBitBinary& meas) + { + return opendnp3::DoubleBitToString(meas.value); + } + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/UpdateBuilder.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/UpdateBuilder.h new file mode 100644 index 0000000..21f202e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/UpdateBuilder.h @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_UPDATEBUILDER_H +#define ASIODNP3_UPDATEBUILDER_H + +#include "asiodnp3/Updates.h" + +namespace asiodnp3 +{ + +class UpdateBuilder +{ + +public: + + UpdateBuilder& Update(const opendnp3::Binary& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::DoubleBitBinary& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::Analog& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::Counter& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::FrozenCounter& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::BinaryOutputStatus& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::AnalogOutputStatus& meas, uint16_t index, opendnp3::EventMode mode = opendnp3::EventMode::Detect); + UpdateBuilder& Update(const opendnp3::TimeAndInterval& meas, uint16_t index); + UpdateBuilder& Modify(opendnp3::FlagsType type, uint16_t start, uint16_t stop, uint8_t flags); + + Updates Build() const; + +private: + + template + UpdateBuilder& AddMeas(const T& meas, uint16_t index, opendnp3::EventMode mode); + + void Add(const update_func_t& fun); + + std::shared_ptr updates; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/Updates.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/Updates.h new file mode 100644 index 0000000..f432197 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/Updates.h @@ -0,0 +1,66 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_UPDATES_H +#define ASIODNP3_UPDATES_H + +#include +#include +#include + +#include "opendnp3/outstation/IUpdateHandler.h" + +namespace asiodnp3 +{ + +typedef std::function update_func_t; +typedef std::vector shared_updates_t; + +class Updates +{ + friend class UpdateBuilder; + +public: + + void Apply(opendnp3::IUpdateHandler& handler) const + { + if (!updates) return; + + for(auto& update : *updates) + { + update(handler); + } + } + + bool IsEmpty() const + { + return updates ? updates->empty() : true; + } + +private: + + Updates(const std::shared_ptr& updates) : updates(updates) {} + + const std::shared_ptr updates; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiodnp3/X509Info.h b/utils/dnp3_src/cpp/libs/include/asiodnp3/X509Info.h new file mode 100644 index 0000000..b043720 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiodnp3/X509Info.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_X509_INFO_H +#define ASIODNP3_X509_INFO_H + +#include +#include +#include + + +namespace asiodnp3 +{ + +/** +* Select information from a preverified x509 certificate +* that user can can inspect an optionally reject +*/ +class X509Info : private openpal::Uncopyable +{ +public: + + X509Info(int depth_, const openpal::RSlice sha1thumbprint_, std::string subjectName_) : + depth(depth_), + sha1thumbprint(sha1thumbprint_), + subjectName(subjectName_) + {} + + // the depth of the certificate in the chain + int depth; + + // the sha1 thumbprint + openpal::RSlice sha1thumbprint; + + // the extracted subject name + std::string subjectName; + +private: + + X509Info(); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/ASIOSerialHelpers.h b/utils/dnp3_src/cpp/libs/include/asiopal/ASIOSerialHelpers.h new file mode 100644 index 0000000..7b6c20a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/ASIOSerialHelpers.h @@ -0,0 +1,37 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_ASIOSERIALHELPERS_H +#define ASIOPAL_ASIOSERIALHELPERS_H + +#include +#include + +#include "SerialTypes.h" + +namespace asiopal +{ + +// Serial port configuration functions "free" to keep the classes simple. +bool Configure(const SerialSettings& settings, asio::serial_port& port, std::error_code& ec); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/ChannelRetry.h b/utils/dnp3_src/cpp/libs/include/asiopal/ChannelRetry.h new file mode 100644 index 0000000..b3e3369 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/ChannelRetry.h @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CHANNEL_RETRY_H +#define OPENDNP3_CHANNEL_RETRY_H + +#include + +#include "asiopal/IOpenDelayStrategy.h" + + +namespace asiopal +{ + +/// Class used to configure how channel failures are retried +class ChannelRetry +{ + +public: + + /* + * Construct a channel retry config class + * + * @param minOpenRetry minimum connection retry interval on failure + * @param maxOpenRetry maximum connection retry interval on failure + */ + ChannelRetry( + openpal::TimeDuration minOpenRetry, + openpal::TimeDuration maxOpenRetry, + IOpenDelayStrategy& strategy = ExponentialBackoffStrategy::Instance() + ); + + /// Return the default configuration of exponential backoff from 1 sec to 1 minute + static ChannelRetry Default(); + + /// minimum connection retry interval on failure + openpal::TimeDuration minOpenRetry; + /// maximum connection retry interval on failure + openpal::TimeDuration maxOpenRetry; + + openpal::TimeDuration NextDelay(const openpal::TimeDuration& current) const + { + return strategy.GetNextDelay(current, maxOpenRetry); + } + +private: + + //// Strategy to use (default to exponential backoff) + IOpenDelayStrategy& strategy; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/Executor.h b/utils/dnp3_src/cpp/libs/include/asiopal/Executor.h new file mode 100644 index 0000000..ec725bc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/Executor.h @@ -0,0 +1,120 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_EXECUTOR_H +#define ASIOPAL_EXECUTOR_H + +#include +#include + +#include "asiopal/IO.h" +#include "asiopal/SteadyClock.h" + +#include + +namespace asiopal +{ + +/** +* +* Implementation of openpal::IExecutor backed by asio::strand +* +* Shutdown life-cycle guarantees are provided by using std::shared_ptr +* +*/ +class Executor final : + public openpal::IExecutor, + public std::enable_shared_from_this, + private openpal::Uncopyable +{ + +public: + + Executor(const std::shared_ptr& io); + + static std::shared_ptr Create(const std::shared_ptr& io) + { + return std::make_shared(io); + } + + /// ---- Implement IExecutor ----- + + virtual openpal::MonotonicTimestamp GetTime() override; + virtual openpal::ITimer* Start(const openpal::TimeDuration&, const openpal::action_t& runnable) override; + virtual openpal::ITimer* Start(const openpal::MonotonicTimestamp&, const openpal::action_t& runnable) override; + virtual void Post(const openpal::action_t& runnable) override; + + template + T ReturnFrom(const std::function& action); + + void BlockUntil(const std::function& action); + + void BlockUntilAndFlush(const std::function& action); + +private: + + // we hold a shared_ptr to the pool so that it cannot dissapear while the strand is still executing + std::shared_ptr io; + +public: + + // Create a new Executor that shares the underling std::shared_ptr + std::shared_ptr Fork() const + { + return Create(this->io); + } + + asio::strand strand; + +private: + + openpal::ITimer* Start(const steady_clock_t::time_point& expiration, const openpal::action_t& runnable); + +}; + +template +T Executor::ReturnFrom(const std::function& action) +{ + if (strand.running_in_this_thread()) + { + return action(); + } + + std::promise ready; + + auto future = ready.get_future(); + + auto run = [&] + { + ready.set_value(action()); + }; + + strand.post(run); + + future.wait(); + + return future.get(); +} + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IAsyncChannel.h b/utils/dnp3_src/cpp/libs/include/asiopal/IAsyncChannel.h new file mode 100644 index 0000000..83acc69 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IAsyncChannel.h @@ -0,0 +1,168 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_IASYNCCHANNEL_H +#define ASIOPAL_IASYNCCHANNEL_H + +#include +#include +#include + +#include "asiopal/Executor.h" +#include "asiopal/IChannelCallbacks.h" + +#include +#include + +namespace asiopal +{ + +class IAsyncChannel : public std::enable_shared_from_this, private openpal::Uncopyable +{ +public: + + IAsyncChannel(const std::shared_ptr& executor) : executor(executor) + {} + + virtual ~IAsyncChannel() {} + + void SetCallbacks(const std::shared_ptr& callbacks) + { + assert(callbacks); + this->callbacks = callbacks; + } + + inline bool BeginRead(const openpal::WSlice& buffer) + { + assert(callbacks); + if (this->CanRead()) + { + this->reading = true; + this->BeginReadImpl(buffer); + return true; + } + else + { + return false; + } + } + + inline bool BeginWrite(const openpal::RSlice& buffer) + { + assert(callbacks); + if (this->CanWrite()) + { + this->writing = true; + this->BeginWriteImpl(buffer); + return true; + } + else + { + return false; + } + } + + inline bool Shutdown() + { + if (this->is_shutting_down) return false; + + this->is_shutting_down = true; + + this->ShutdownImpl(); + + // keep the channel alive until it's not reading or writing + auto action = [self = shared_from_this()]() + { + self->CheckForShutdown(self); + }; + + this->executor->strand.post(action); + + return true; + } + + inline bool CanRead() const + { + return callbacks && !is_shutting_down && !reading; + } + + + inline bool CanWrite() const + { + return callbacks && !is_shutting_down && !writing; + } + + const std::shared_ptr executor; + +protected: + + inline void OnReadCallback(const std::error_code& ec, size_t num) + { + this->reading = false; + if (this->callbacks && !is_shutting_down) + { + this->callbacks->OnReadComplete(ec, num); + } + } + + + inline void OnWriteCallback(const std::error_code& ec, size_t num) + { + this->writing = false; + if (this->callbacks && !is_shutting_down) + { + this->callbacks->OnWriteComplete(ec, num); + } + } + +private: + + void CheckForShutdown(std::shared_ptr self) + { + if (self->reading || self->writing) + { + auto action = [self]() + { + self->CheckForShutdown(self); + }; + + self->executor->strand.post(action); + } + else + { + self->callbacks.reset(); // drop the callbacks + } + } + + + std::shared_ptr callbacks; + + bool is_shutting_down = false; + bool reading = false; + bool writing = false; + + virtual void BeginReadImpl(openpal::WSlice buffer) = 0; + virtual void BeginWriteImpl(const openpal::RSlice& buffer) = 0; + virtual void ShutdownImpl() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IChannelCallbacks.h b/utils/dnp3_src/cpp/libs/include/asiopal/IChannelCallbacks.h new file mode 100644 index 0000000..f6ecd2e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IChannelCallbacks.h @@ -0,0 +1,40 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_ICHANNELCALLBACKS_H +#define ASIOPAL_ICHANNELCALLBACKS_H + +#include + +namespace asiopal +{ + +struct IChannelCallbacks +{ + virtual ~IChannelCallbacks() {}; + + virtual void OnReadComplete(const std::error_code& ec, size_t num) = 0; + virtual void OnWriteComplete(const std::error_code& ec, size_t num) = 0; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IListener.h b/utils/dnp3_src/cpp/libs/include/asiopal/IListener.h new file mode 100644 index 0000000..9e0ed2e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IListener.h @@ -0,0 +1,43 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_ILISTENER_H +#define ASIOPAL_ILISTENER_H + +#include "asiopal/IResourceManager.h" + +namespace asiopal +{ + +/** +* Represents a running TCP or TLS listener that can be shutdown +* so that no new connections are accepted. +*/ +class IListener : public IResource +{ +public: + + virtual ~IListener() {} + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IO.h b/utils/dnp3_src/cpp/libs/include/asiopal/IO.h new file mode 100644 index 0000000..e5eafaa --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IO.h @@ -0,0 +1,46 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_IO_H +#define ASIOPAL_IO_H + +#include + +namespace asiopal +{ + +/** +* Container class for an asio::io_service +*/ +class IO +{ + +public: + + virtual ~IO() {} + + asio::io_service service; + +}; + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IOpenDelayStrategy.h b/utils/dnp3_src/cpp/libs/include/asiopal/IOpenDelayStrategy.h new file mode 100644 index 0000000..33b7a4e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IOpenDelayStrategy.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_IOPENDELAYSTRATEGY_H +#define ASIOPAL_IOPENDELAYSTRATEGY_H + +#include + +#include + +namespace asiopal +{ + +/** +* A strategy interface for controlling how connection are retried +*/ +class IOpenDelayStrategy +{ + +public: + + virtual ~IOpenDelayStrategy() {} + + /** + * The the next delay based on the current and the maximum. + */ + virtual openpal::TimeDuration GetNextDelay(const openpal::TimeDuration& current, const openpal::TimeDuration& max) const = 0; +}; + +/** +* Implements IOpenDelayStrategy using exponential-backoff. +*/ +class ExponentialBackoffStrategy : public IOpenDelayStrategy, private openpal::Uncopyable +{ + static ExponentialBackoffStrategy instance; + +public: + + static IOpenDelayStrategy& Instance(); + + virtual openpal::TimeDuration GetNextDelay(const openpal::TimeDuration& current, const openpal::TimeDuration& max) const override final; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IPEndpoint.h b/utils/dnp3_src/cpp/libs/include/asiopal/IPEndpoint.h new file mode 100644 index 0000000..841ce95 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IPEndpoint.h @@ -0,0 +1,55 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_IPENDPOINT_H +#define ASIOPAL_IPENDPOINT_H + +#include +#include + +namespace asiopal +{ +class IPEndpoint +{ + +public: + + IPEndpoint(const std::string& address, uint16_t port) : + address(address), + port(port) + {} + + static IPEndpoint AllAdapters(uint16_t port) + { + return IPEndpoint("0.0.0.0", port); + } + + static IPEndpoint Localhost(uint16_t port) + { + return IPEndpoint("127.0.0.1", port); + } + + std::string address; + uint16_t port; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/IResourceManager.h b/utils/dnp3_src/cpp/libs/include/asiopal/IResourceManager.h new file mode 100644 index 0000000..a78b6d1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/IResourceManager.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_IRESOURCEMANAGER_H +#define ASIOPAL_IRESOURCEMANAGER_H + +#include + +namespace asiopal +{ + +/** +* Anything that can be shutdown +*/ +struct IResource +{ +public: + + virtual ~IResource() {} + + virtual void Shutdown() = 0; + +}; + +struct IResourceManager +{ + +public: + + virtual ~IResourceManager() {} + + /// notify the handler that the resource is shutting down, and it doesn't + /// have to track it anymore + virtual void Detach(const std::shared_ptr& resource) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/LoggingConnectionCondition.h b/utils/dnp3_src/cpp/libs/include/asiopal/LoggingConnectionCondition.h new file mode 100644 index 0000000..ab40fbf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/LoggingConnectionCondition.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_LOGGING_CONNECTION_CONDITION_H +#define ASIOPAL_LOGGING_CONNECTION_CONDITION_H + +#include +#include +#include + +namespace asiopal +{ + +class LoggingConnectionCondition +{ + +public: + + LoggingConnectionCondition(openpal::Logger logger) : logger(logger) + {} + + template + Iterator operator()(const std::error_code& ec, Iterator next) + { + if (ec) + { + FORMAT_LOG_BLOCK(logger, openpal::logflags::WARN, "connection error: %s", ec.message().c_str()); + } + + return next; + } + +private: + + openpal::Logger logger; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/ResourceManager.h b/utils/dnp3_src/cpp/libs/include/asiopal/ResourceManager.h new file mode 100644 index 0000000..8cfcdff --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/ResourceManager.h @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_RESOURCEMANAGER_H +#define ASIOPAL_RESOURCEMANAGER_H + +#include "IResourceManager.h" + +#include +#include +#include + +namespace asiopal +{ + +class ResourceManager final : public IResourceManager +{ + +public: + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + virtual void Detach(const std::shared_ptr& resource) override; + + void Shutdown(); + + template + std::shared_ptr Bind(const T& create) + { + std::lock_guard lock(this->mutex); + + if (this->is_shutting_down) + { + return nullptr; + } + else + { + auto item = create(); + if (item) + { + this->resources.insert(item); + } + return item; + } + } + +private: + + std::mutex mutex; + bool is_shutting_down = false; + std::set> resources; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/SerialChannel.h b/utils/dnp3_src/cpp/libs/include/asiopal/SerialChannel.h new file mode 100644 index 0000000..d01b1f4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/SerialChannel.h @@ -0,0 +1,59 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_SERIALCHANNEL_H +#define ASIOPAL_SERIALCHANNEL_H + +#include "IAsyncChannel.h" + +#include "asiopal/SerialTypes.h" + +#include + +namespace asiopal +{ + +class SerialChannel final : public IAsyncChannel +{ + +public: + + static std::shared_ptr Create(std::shared_ptr executor) + { + return std::make_shared(executor); + } + + SerialChannel(std::shared_ptr executor); + + bool Open(const SerialSettings& settings, std::error_code& ec); + +private: + + virtual void BeginReadImpl(openpal::WSlice buffer) override; + virtual void BeginWriteImpl(const openpal::RSlice& buffer) override; + virtual void ShutdownImpl() override; + + asio::basic_serial_port<> port; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/SerialTypes.h b/utils/dnp3_src/cpp/libs/include/asiopal/SerialTypes.h new file mode 100644 index 0000000..67aa06f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/SerialTypes.h @@ -0,0 +1,74 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_SERIALTYPES_H +#define ASIOPAL_SERIALTYPES_H + +#include "openpal/executor/TimeDuration.h" + +#include "opendnp3/gen/Parity.h" +#include "opendnp3/gen/FlowControl.h" +#include "opendnp3/gen/StopBits.h" + +#include + +namespace asiopal +{ + +/// Settings structure for the serial port +struct SerialSettings +{ + + /// Defaults to the familiar 9600 8/N/1, no flow control + SerialSettings() : + baud(9600), + dataBits(8), + stopBits(opendnp3::StopBits::One), + parity(opendnp3::Parity::None), + flowType(opendnp3::FlowControl::None), + asyncOpenDelay(openpal::TimeDuration::Milliseconds(500)) + {} + + /// name of the port, i.e. "COM1" or "/dev/tty0" + std::string deviceName; + + /// Baud rate of the port, i.e. 9600 or 57600 + int baud; + + /// Data bits, usually 8 + int dataBits; + + /// Stop bits, usually set to 1 + opendnp3::StopBits stopBits; + + /// Parity setting for the port, usually PAR_NONE + opendnp3::Parity parity; + + /// Flow control setting, usually FLOW_NONE + opendnp3::FlowControl flowType; + + /// Some physical layers need time to "settle" so that the first tx isn't lost + openpal::TimeDuration asyncOpenDelay; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/SocketChannel.h b/utils/dnp3_src/cpp/libs/include/asiopal/SocketChannel.h new file mode 100644 index 0000000..4521d5e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/SocketChannel.h @@ -0,0 +1,55 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_SOCKETCHANNEL_H +#define ASIOPAL_SOCKETCHANNEL_H + +#include "IAsyncChannel.h" + +namespace asiopal +{ + +class SocketChannel final : public IAsyncChannel +{ + +public: + + static std::shared_ptr Create(std::shared_ptr executor, asio::ip::tcp::socket socket) + { + return std::make_shared(executor, std::move(socket)); + } + + SocketChannel(std::shared_ptr executor, asio::ip::tcp::socket socket); + +protected: + + virtual void BeginReadImpl(openpal::WSlice buffer) override; + virtual void BeginWriteImpl(const openpal::RSlice& buffer) override; + virtual void ShutdownImpl() override; + +private: + + asio::ip::tcp::socket socket; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/SocketHelpers.h b/utils/dnp3_src/cpp/libs/include/asiopal/SocketHelpers.h new file mode 100644 index 0000000..522691c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/SocketHelpers.h @@ -0,0 +1,59 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#ifndef ASIOPAL_SOCKET_HELPERS_H +#define ASIOPAL_SOCKET_HELPERS_H + +#include + +#include +#include + +namespace asiopal +{ +class SocketHelpers : private openpal::StaticOnly +{ + +public: + /** + * Bind a socket object to a local endpoint given an address. If the address is empty, 0.0.0.0 is used + */ + template + static void BindToLocalAddress(const std::string& address, asio::ip::tcp::endpoint& endpoint, SocketType& socket, std::error_code& ec) + { + auto string = address.empty() ? "0.0.0.0" : address; + auto addr = asio::ip::address::from_string(string, ec); + if (!ec) + { + endpoint.address(addr); + socket.open(asio::ip::tcp::v4(), ec); + if (!ec) + { + socket.bind(endpoint, ec); + } + } + } +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/SteadyClock.h b/utils/dnp3_src/cpp/libs/include/asiopal/SteadyClock.h new file mode 100644 index 0000000..2813fa0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/SteadyClock.h @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_STEADYCLOCK_H +#define ASIOPAL_STEADYCLOCK_H + +#include + +namespace asiopal +{ + +#if (defined WIN32 && (_MSC_VER < 1900)) // Windows with VS eariler than 2015, e.g. 2013 + +#include + +/* +Custom steady clock implementation to handle the situation where the Windows steady clock +implementation is not monotonic. Normal steady clock implementation is used on other platforms. +*/ +struct SteadyClockWindows +{ + // Type defininitions for this clock - ticks are in nanoseconds for this clock + typedef LONGLONG representation; + typedef std::ratio_multiply, std::nano> period; + typedef std::chrono::duration duration; + typedef std::chrono::time_point time_point; + + + static time_point now() + { + // Special case for WIN32 because std::chrono::steady_clock is broken + LARGE_INTEGER freq; + LONGLONG nanoSecondsPerTick = 0; + if (QueryPerformanceFrequency(&freq)) + { + nanoSecondsPerTick = LONGLONG(1000000000.0L / freq.QuadPart); + } + + LARGE_INTEGER performanceCount; + if (nanoSecondsPerTick <= 0 || !QueryPerformanceCounter(&performanceCount)) + { + // Error condition, return 0 time + return time_point(); + } + + // Return time in nanoseconds + LONGLONG timeNanos = performanceCount.QuadPart * nanoSecondsPerTick; + return time_point(duration(timeNanos)); + } +}; + +// use this custom steady clock +typedef SteadyClockWindows steady_clock_t; + +#else + +// In all other situations use the normal steady clock +typedef std::chrono::steady_clock steady_clock_t; + +#endif + +} + +#endif \ No newline at end of file diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/Synchronized.h b/utils/dnp3_src/cpp/libs/include/asiopal/Synchronized.h new file mode 100644 index 0000000..fae0041 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/Synchronized.h @@ -0,0 +1,78 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_SYNCHRONIZED_H +#define ASIOPAL_SYNCHRONIZED_H + +#include +#include +#include + +namespace asiopal +{ + +/** +* Provides thread-safe access to a value that can be set once. +*/ +template +class Synchronized +{ +public: + + Synchronized() : value(), isSet(false) + {} + + T WaitForValue() + { + std::unique_lock lock(mutex); + while (!isSet) + { + auto complete = [this]() + { + return isSet; + }; + condition.wait(lock, complete); + } + return value; + } + + void SetValue(T value_) + { + std::unique_lock lock(mutex); + this->value = value_; + isSet = true; + condition.notify_all(); + } + +private: + + T value; + bool isSet; + + std::mutex mutex; + std::condition_variable condition; +}; + +} + +#endif + + + diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/TCPClient.h b/utils/dnp3_src/cpp/libs/include/asiopal/TCPClient.h new file mode 100644 index 0000000..518a831 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/TCPClient.h @@ -0,0 +1,84 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TCPCLIENT_H +#define ASIOPAL_TCPCLIENT_H + +#include "asiopal/Executor.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/LoggingConnectionCondition.h" + +namespace asiopal +{ + +class TCPClient final : public std::enable_shared_from_this, private openpal::Uncopyable +{ + +public: + + typedef std::function& executor, asio::ip::tcp::socket, const std::error_code& ec)> connect_callback_t; + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& remote, + const std::string& adapter) + { + return std::make_shared(logger, executor, remote, adapter); + } + + TCPClient( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& remote, + const std::string& adapter + ); + + bool Cancel(); + + bool BeginConnect(const connect_callback_t& callback); + +private: + + void HandleResolveResult( + const connect_callback_t& callback, + const asio::ip::tcp::resolver::iterator& endpoints, + const std::error_code& ec + ); + + bool PostConnectError(const connect_callback_t& callback, const std::error_code& ec); + + bool connecting = false; + bool canceled = false; + + LoggingConnectionCondition condition; + const std::shared_ptr executor; + const std::string host; + const std::string adapter; + asio::ip::tcp::socket socket; + asio::ip::tcp::endpoint remoteEndpoint; + asio::ip::tcp::endpoint localEndpoint; + asio::ip::tcp::resolver resolver; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/TCPServer.h b/utils/dnp3_src/cpp/libs/include/asiopal/TCPServer.h new file mode 100644 index 0000000..95e4c13 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/TCPServer.h @@ -0,0 +1,86 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TCPSERVER_H +#define ASIOPAL_TCPSERVER_H + +#include "asiopal/IPEndpoint.h" +#include "asiopal/Executor.h" +#include "asiopal/IListener.h" + +#include +#include + +#include + +namespace asiopal +{ + +/** +* Binds and listens on an IPv4 TCP port +* +* Meant to be used exclusively as a shared_ptr +*/ +class TCPServer : + public std::enable_shared_from_this, + public IListener, + private openpal::Uncopyable +{ + +public: + + TCPServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& endpoint, + std::error_code& ec + ); + + /// Implement IListener + void Shutdown() override final; + +protected: + + /// Inherited classes must define these functions + + virtual void OnShutdown() = 0; + + virtual void AcceptConnection(uint64_t sessionid, const std::shared_ptr& executor, asio::ip::tcp::socket) = 0; + + /// Start asynchronously accepting connections on the strand + void StartAccept(); + + openpal::Logger logger; + std::shared_ptr executor; + +private: + + void Configure(const std::string& adapter, std::error_code& ec); + + asio::ip::tcp::endpoint endpoint; + asio::ip::tcp::acceptor acceptor; + asio::ip::tcp::socket socket; + asio::ip::tcp::endpoint remote_endpoint; + uint64_t session_id = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/TLSConfig.h b/utils/dnp3_src/cpp/libs/include/asiopal/TLSConfig.h new file mode 100644 index 0000000..4e90ec8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/TLSConfig.h @@ -0,0 +1,98 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_TLS_CONFIG_H +#define ASIOPAL_TLS_CONFIG_H + +#include + +namespace asiopal +{ + +/** +* TLS configuration information +*/ +struct TLSConfig +{ + /** + * Construct a TLS configuration + * + * @param peerCertFilePath Certificate file used to verify the peer or server. Can be CA file or a self-signed cert provided by other party. + * @param localCertFilePath File that contains the certificate (or certificate chain) that will be presented to the remote side of the connection + * @param privateKeyFilePath File that contains the private key corresponding to the local certificate + * @param maxVerifyDepth The maximum certificate chain verification depth (0 == self-signed only) + * @param allowTLSv10 Allow TLS version 1.0 (default false) + * @param allowTLSv11 Allow TLS version 1.1 (default false) + * @param allowTLSv12 Allow TLS version 1.2 (default true) + * @param cipherList The openssl cipher-list, defaults to "" which does not modify the default cipher list + * + * localCertFilePath and privateKeyFilePath can optionally be the same file, i.e. a PEM that contains both pieces of data. + * + */ + TLSConfig( + const std::string& peerCertFilePath, + const std::string& localCertFilePath, + const std::string& privateKeyFilePath, + int maxVerifyDepth = 0, + bool allowTLSv10 = false, + bool allowTLSv11 = false, + bool allowTLSv12 = true, + const std::string& cipherList = "" + ) : + peerCertFilePath(peerCertFilePath), + localCertFilePath(localCertFilePath), + privateKeyFilePath(privateKeyFilePath), + maxVerifyDepth(maxVerifyDepth), + allowTLSv10(allowTLSv10), + allowTLSv11(allowTLSv11), + allowTLSv12(allowTLSv12), + cipherList(cipherList) + {} + + /// Certificate file used to verify the peer or server. Can be CA file or a self-signed cert provided by other party. + std::string peerCertFilePath; + + /// File that contains the certificate (or certificate chain) that will be presented to the remote side of the connection + std::string localCertFilePath; + + /// File that contains the private key corresponding to the local certificate + std::string privateKeyFilePath; + + /// max verification depth (defaults to 0 - peer certificate only) + int maxVerifyDepth; + + /// Allow TLS version 1.0 (default false) + bool allowTLSv10; + + /// Allow TLS version 1.1 (default false) + bool allowTLSv11; + + /// Allow TLS version 1.2 (default true) + bool allowTLSv12; + + /// openssl format cipher list + std::string cipherList; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/ThreadPool.h b/utils/dnp3_src/cpp/libs/include/asiopal/ThreadPool.h new file mode 100644 index 0000000..e18e1ec --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/ThreadPool.h @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_THREADPOOL_H +#define ASIOPAL_THREADPOOL_H + +#include + +#include "asiopal/SteadyClock.h" +#include "asiopal/Executor.h" + +#include +#include +#include + +namespace asiopal +{ + +/** +* A thread pool that calls asio::io_service::run +*/ +class ThreadPool +{ +public: + + friend class ThreadPoolTest; + + ThreadPool( + const openpal::Logger& logger, + const std::shared_ptr& io, + uint32_t concurrency, + std::function onThreadStart = []() {}, + std::function onThreadExit = []() {} + ); + + ~ThreadPool(); + + inline std::shared_ptr CreateExecutor() const + { + return Executor::Create(io); + } + + void Shutdown(); + +private: + + openpal::Logger logger; + const std::shared_ptr io; + + std::function onThreadStart; + std::function onThreadExit; + + bool isShutdown; + + void Run(int threadnum); + + asio::basic_waitable_timer< asiopal::steady_clock_t > infiniteTimer; + std::vector> threads; +}; + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/TimeConversions.h b/utils/dnp3_src/cpp/libs/include/asiopal/TimeConversions.h new file mode 100644 index 0000000..0c7c117 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/TimeConversions.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_TIMECONVERSIONS_H +#define ASIOPAL_TIMECONVERSIONS_H + +#include "SteadyClock.h" + +#include "openpal/util/Uncopyable.h" + +#include "openpal/executor/MonotonicTimestamp.h" + +namespace asiopal +{ + + +class TimeConversions : private openpal::StaticOnly +{ + static const int64_t MAX_MILLISECONDS = std::chrono::duration_cast(steady_clock_t::duration::max()).count(); + +public: + + static steady_clock_t::time_point Convert(const openpal::MonotonicTimestamp& timestamp); + static openpal::MonotonicTimestamp Convert(const steady_clock_t::time_point& timestamp); +}; + + +} + +#endif \ No newline at end of file diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/Timer.h b/utils/dnp3_src/cpp/libs/include/asiopal/Timer.h new file mode 100644 index 0000000..3f47aab --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/Timer.h @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_TIMER_H +#define ASIOPAL_TIMER_H + +#include + +#include +#include + +#include "asiopal/SteadyClock.h" + + +namespace asiopal +{ + +/** +* +* Implementation of openpal::ITimer backed by asio::basic_waitable_timer +* +*/ +class Timer final : public openpal::ITimer, private openpal::Uncopyable +{ + friend class Executor; + +public: + + Timer(asio::io_service& service); + + virtual void Cancel() override; + + virtual openpal::MonotonicTimestamp ExpiresAt() override; + +private: + + asio::basic_waitable_timer< asiopal::steady_clock_t > timer; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/asiopal/UTCTimeSource.h b/utils/dnp3_src/cpp/libs/include/asiopal/UTCTimeSource.h new file mode 100644 index 0000000..1af3b5d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/asiopal/UTCTimeSource.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIOPAL_UTCTIMESOURCE_H +#define ASIOPAL_UTCTIMESOURCE_H + +#include + +namespace asiopal +{ + +/** +* Interface that defines a method to get UTC timestamps +*/ +class UTCTimeSource : public openpal::IUTCTimeSource +{ + +public: + static openpal::IUTCTimeSource& Instance(); + openpal::UTCTimestamp Now(); + +private: + UTCTimeSource() {} + static UTCTimeSource instance; +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/dnp3decode/Decoder.h b/utils/dnp3_src/cpp/libs/include/dnp3decode/Decoder.h new file mode 100644 index 0000000..f9b1525 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/dnp3decode/Decoder.h @@ -0,0 +1,55 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DECODER_H +#define OPENDNP3_DECODER_H + +#include +#include + +#include "IDecoderCallbacks.h" + +namespace opendnp3 +{ +class DecoderImpl; + +// stand-alone DNP3 decoder +class Decoder +{ +public: + + Decoder(IDecoderCallbacks& callbacks, openpal::Logger logger); + ~Decoder(); + + void DecodeLPDU(const openpal::RSlice& data); + void DecodeTPDU(const openpal::RSlice& data); + void DecodeAPDU(const openpal::RSlice& data); + + + +private: + + DecoderImpl* impl; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/dnp3decode/IDecoderCallbacks.h b/utils/dnp3_src/cpp/libs/include/dnp3decode/IDecoderCallbacks.h new file mode 100644 index 0000000..08b38ef --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/dnp3decode/IDecoderCallbacks.h @@ -0,0 +1,41 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IDECODERCALLBACKS_H +#define OPENDNP3_IDECODERCALLBACKS_H + +#include + +namespace opendnp3 +{ +class IDecoderCallbacks : openpal::Uncopyable +{ + friend class Indent; + +protected: + + virtual void PushIndent() {}; + virtual void PopIndent() {}; +}; +} + +#endif + + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/LogLevels.h b/utils/dnp3_src/cpp/libs/include/opendnp3/LogLevels.h new file mode 100644 index 0000000..d890db9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/LogLevels.h @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_LOGLEVELS_H +#define OPENDNP3_LOGLEVELS_H + +#include + +namespace opendnp3 +{ + +const char* LogFlagToString(int32_t flag); + +namespace flags +{ + +// define most of these in terms of the base openpal filters +const int32_t EVENT = openpal::logflags::EVENT; +const int32_t ERR = openpal::logflags::ERR; +const int32_t WARN = openpal::logflags::WARN; +const int32_t INFO = openpal::logflags::INFO; +const int32_t DBG = openpal::logflags::DBG; + +// up-shift the custom dnp3 filters + +const int32_t LINK_RX = DBG << 1; +const int32_t LINK_RX_HEX = DBG << 2; + +const int32_t LINK_TX = DBG << 3; +const int32_t LINK_TX_HEX = DBG << 4; + +const int32_t TRANSPORT_RX = DBG << 5; +const int32_t TRANSPORT_TX = DBG << 6; + +const int32_t APP_HEADER_RX = DBG << 7; +const int32_t APP_HEADER_TX = DBG << 8; + +const int32_t APP_OBJECT_RX = DBG << 9; +const int32_t APP_OBJECT_TX = DBG << 10; + +const int32_t APP_HEX_RX = DBG << 11; +const int32_t APP_HEX_TX = DBG << 12; + +} + +namespace levels +{ + +const int32_t NOTHING = 0; +const int32_t ALL = ~NOTHING; +const int32_t NORMAL = flags::EVENT | flags::ERR | flags::WARN | flags::INFO; +const int32_t ALL_APP_COMMS = flags::APP_HEADER_RX | flags::APP_HEADER_TX | flags::APP_OBJECT_RX | flags::APP_OBJECT_TX | flags::APP_HEX_RX | flags::APP_HEX_TX; +const int32_t ALL_COMMS = flags::LINK_RX | flags::LINK_TX | flags::TRANSPORT_RX | flags::TRANSPORT_TX | ALL_APP_COMMS; + +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/StackStatistics.h b/utils/dnp3_src/cpp/libs/include/opendnp3/StackStatistics.h new file mode 100644 index 0000000..94af5de --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/StackStatistics.h @@ -0,0 +1,97 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_STACKSTATISTICS_H +#define OPENDNP3_STACKSTATISTICS_H + +#include + +namespace opendnp3 +{ + +/** +* Statistics related to both a master or outstation session +*/ +struct StackStatistics +{ + struct Link + { + /// number of unexpected frames + uint32_t numUnexpectedFrame = 0; + + /// frames received w/ wrong master bit + uint32_t numBadMasterBit = 0; + + /// frames received for an unknown destination + uint32_t numUnknownDestination = 0; + + /// frames received for an unknown source + uint32_t numUnknownSource = 0; + }; + + struct Transport + { + struct Rx + { + /// Number of valid TPDU's received + uint32_t numTransportRx = 0; + + /// Number of TPDUs dropped due to malformed contents + uint32_t numTransportErrorRx = 0; + + /// Number of times received data was too big for reassembly buffer + uint32_t numTransportBufferOverflow = 0; + + /// number of times transport buffer is discard due to new FIR + uint32_t numTransportDiscard = 0; + + /// number of segments ignored due to bad FIR/FIN or SEQ + uint32_t numTransportIgnore = 0; + }; + + struct Tx + { + /// Number of TPDUs transmitted + uint32_t numTransportTx = 0; + }; + + Transport() = default; + Transport(const Rx& rx, const Tx& tx) : rx(rx), tx(tx) {} + + Rx rx; + Tx tx; + }; + + StackStatistics() = default; + + StackStatistics(const Link& link, const Transport& transport) : + link(link), + transport(transport) + { + + } + + Link link; + Transport transport; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogCommandEvent.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogCommandEvent.h new file mode 100644 index 0000000..c4d87e5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogCommandEvent.h @@ -0,0 +1,53 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ANALOGCOMMANDEVENT_H +#define OPENDNP3_ANALOGCOMMANDEVENT_H + +#include "opendnp3/gen/CommandStatus.h" + +#include "opendnp3/app/DNPTime.h" + +namespace opendnp3 +{ + +/** +* Occurs when an outstation receives and analog command. Maps to Group43. +*/ +class AnalogCommandEvent +{ +public: + + AnalogCommandEvent(); + + AnalogCommandEvent(double value, CommandStatus status); + + AnalogCommandEvent(double value, CommandStatus status, DNPTime time); + + double value; + CommandStatus status; + DNPTime time; + + bool operator==(const AnalogCommandEvent& rhs) const; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogOutput.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogOutput.h new file mode 100644 index 0000000..9846c92 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/AnalogOutput.h @@ -0,0 +1,127 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ANALOGOUTPUT_H +#define OPENDNP3_ANALOGOUTPUT_H + +#include "opendnp3/gen/CommandStatus.h" + +namespace opendnp3 +{ + +/** + * The object to represent a setpoint request from the master. Think of + * this like turning a dial on the front of a machine to desired setting. + */ +template +class AnalogOutput +{ +public: + + AnalogOutput() : + value(0), + status(CommandStatus::SUCCESS) + {} + + AnalogOutput(T value_) : + value(value_), + status(CommandStatus::SUCCESS) + {} + + AnalogOutput(T value_, CommandStatus status_) : + value(value_), + status(status_) + {} + + bool ValuesEqual(const AnalogOutput& lhs) const + { + return value == lhs.value; + } + + T value; + + /** + * The status value defaults to CS_SUCCESS for requests + */ + CommandStatus status; +}; + +/** +* 16-bit signed integer analog output. The underlying serialization is Group41, Variation 2 +*/ +class AnalogOutputInt16 : public AnalogOutput +{ +public: + + AnalogOutputInt16(); + AnalogOutputInt16(int16_t); + AnalogOutputInt16(int16_t, CommandStatus); + + bool operator==(const AnalogOutputInt16& arRHS) const; +}; + +/** +* 32-bit signed integer analog output. The underlying serialization is Group41, Variation 1 +*/ +class AnalogOutputInt32 : public AnalogOutput +{ +public: + + AnalogOutputInt32(); + AnalogOutputInt32(int32_t); + AnalogOutputInt32(int32_t, CommandStatus); + + bool operator==(const AnalogOutputInt32& arRHS) const; +}; + +/** +* Single precision analog output. The underlying serialization is Group41, Variation 3 +*/ +class AnalogOutputFloat32 : public AnalogOutput +{ +public: + + AnalogOutputFloat32(); + AnalogOutputFloat32(float); + AnalogOutputFloat32(float, CommandStatus); + + bool operator==(const AnalogOutputFloat32& arRHS) const; +}; + +/** +* Double precision analog output. The underlying serialization is Group41, Variation 3 +*/ +class AnalogOutputDouble64 : public AnalogOutput +{ +public: + + AnalogOutputDouble64(); + AnalogOutputDouble64(double); + AnalogOutputDouble64(double, CommandStatus); + + bool operator==(const AnalogOutputDouble64& arRHS) const; +}; + + +} + + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/AppConstants.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/AppConstants.h new file mode 100644 index 0000000..bb53643 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/AppConstants.h @@ -0,0 +1,38 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_APPCONSTANTS_H +#define OPENDNP3_APPCONSTANTS_H + +#include + +#include + +namespace opendnp3 +{ +// the default size for an APDU +const uint32_t DEFAULT_MAX_APDU_SIZE = 2048; + +// default timeout in milliseconds for the application layer +const openpal::TimeDuration DEFAULT_APP_TIMEOUT = openpal::TimeDuration::Milliseconds(5000); +} + +#endif \ No newline at end of file diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/BaseMeasurementTypes.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/BaseMeasurementTypes.h new file mode 100644 index 0000000..1f15907 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/BaseMeasurementTypes.h @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_BASEMEASUREMENTTYPES_H +#define OPENDNP3_BASEMEASUREMENTTYPES_H + +#include + +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/Flags.h" + +namespace opendnp3 +{ + +/** + Base class shared by all of the DataPoint types. +*/ +class Measurement +{ +public: + + Flags flags; // bitfield that stores type specific quality information + DNPTime time; // timestamp associated with the measurement + +protected: + + Measurement() + {} + + Measurement(Flags flags) : flags(flags) + {} + + Measurement(Flags flags, DNPTime time) : flags(flags), time(time) + {} + +}; + + +/// Common subclass to analogs and counters +template +class TypedMeasurement : public Measurement +{ +public: + + T value; + + typedef T Type; + +protected: + + TypedMeasurement(): Measurement(), value(0) {} + TypedMeasurement(Flags flags) : Measurement(flags), value(0) {} + TypedMeasurement(T value, Flags flags) : Measurement(flags), value(value) {} + TypedMeasurement(T value, Flags flags, DNPTime time) : Measurement(flags, time), value(value) {} +}; + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/BinaryCommandEvent.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/BinaryCommandEvent.h new file mode 100644 index 0000000..6f5f525 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/BinaryCommandEvent.h @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_BINARYCOMMANDEVENT_H +#define OPENDNP3_BINARYCOMMANDEVENT_H + +#include "opendnp3/gen/CommandStatus.h" + +#include "opendnp3/app/Flags.h" +#include "opendnp3/app/DNPTime.h" + +namespace opendnp3 +{ + +/** +Maps to Group13Var1/2 +*/ +class BinaryCommandEvent +{ +public: + + BinaryCommandEvent(); + + BinaryCommandEvent(Flags flags); + + BinaryCommandEvent(Flags flags, DNPTime time); + + BinaryCommandEvent(bool value, CommandStatus status); + + BinaryCommandEvent(bool value, CommandStatus status, DNPTime time); + + bool value; + CommandStatus status; + DNPTime time; + + Flags GetFlags() const; + + bool operator==(const BinaryCommandEvent& rhs) const; + +private: + + static const uint8_t ValueMask = 0x80; + static const uint8_t StatusMask = 0x7F; + + static bool GetValueFromFlags(Flags flags); + static CommandStatus GetStatusFromFlags(Flags flags); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/ClassField.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/ClassField.h new file mode 100644 index 0000000..4c1a409 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/ClassField.h @@ -0,0 +1,93 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CLASSFIELD_H +#define OPENDNP3_CLASSFIELD_H + +#include + +#include "opendnp3/app/EventType.h" +#include "opendnp3/gen/PointClass.h" + +namespace opendnp3 +{ + +/** +* Specifies a set of event classes e.g. some subset of {0, 1, 2, 3} +*/ +class ClassField +{ +public: + + ClassField(); + + ClassField(PointClass pc); + + ClassField(uint8_t mask_); + + ClassField(bool class0, bool class1, bool class2, bool class3); + + bool IsEmpty() const; + + bool Intersects(const ClassField& other) const; + + uint8_t GetBitfield() const + { + return bitfield; + }; + + ClassField OnlyEventClasses() const; + + void Clear(const ClassField& field); + + void Set(const ClassField& field); + + void Set(PointClass pc); + + static const uint8_t CLASS_0 = static_cast(PointClass::Class0); + static const uint8_t CLASS_1 = static_cast(PointClass::Class1); + static const uint8_t CLASS_2 = static_cast(PointClass::Class2); + static const uint8_t CLASS_3 = static_cast(PointClass::Class3); + static const uint8_t EVENT_CLASSES = CLASS_1 | CLASS_2 | CLASS_3; + static const uint8_t ALL_CLASSES = EVENT_CLASSES | CLASS_0; + + bool HasEventType(EventClass ec) const; + + bool HasClass0() const; + bool HasClass1() const; + bool HasClass2() const; + bool HasClass3() const; + + bool HasEventClass() const; + bool HasAnyClass() const; + + static ClassField None(); + static ClassField AllClasses(); + static ClassField AllEventClasses(); + +private: + uint8_t bitfield; +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/ControlRelayOutputBlock.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/ControlRelayOutputBlock.h new file mode 100644 index 0000000..2fdde6c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/ControlRelayOutputBlock.h @@ -0,0 +1,89 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CONTROLRELAYOUTPUTBLOCK_H +#define OPENDNP3_CONTROLRELAYOUTPUTBLOCK_H + +#include "opendnp3/gen/CommandStatus.h" +#include "opendnp3/gen/ControlCode.h" + +namespace opendnp3 +{ + +/** + * Describes an incoming control request from the master. It is the + * applications responsibility to handle the request and return an + * approiate status code.The PULSE_CLOSE and PULSE_TRIP ControlCodes + * require setting the mOnTimeMS, mOffTimeMS and mCount variables, otherwise + * just use the defaults. + */ +class ControlRelayOutputBlock +{ +public: + + // primary constructor where the control code is set by enumeration + ControlRelayOutputBlock( + ControlCode code = ControlCode::LATCH_ON, + uint8_t count = 1, + uint32_t onTime = 100, + uint32_t offTime = 100, + CommandStatus status = CommandStatus::SUCCESS); + + // overloaded constructor that allows the user to set a raw control code for non-standard codes + ControlRelayOutputBlock( + uint8_t rawCode, + uint8_t count = 1, + uint32_t onTime = 100, + uint32_t offTime = 100, + CommandStatus status = CommandStatus::SUCCESS); + + /// allows matching of exact code + ControlCode functionCode; + /// The raw code in bytes + uint8_t rawCode; + /// the number of times to repeat the operation + uint8_t count; + /// the 'on' time for the pulse train + uint32_t onTimeMS; + /// the 'off' time for the pulse train + uint32_t offTimeMS; + /// status of the resulting operation + CommandStatus status; + + bool ValuesEqual(const ControlRelayOutputBlock& lhs) const + { + return (functionCode == lhs.functionCode) && + (count == lhs.count) && + (onTimeMS == lhs.onTimeMS) && + (offTimeMS == lhs.offTimeMS); + } + + bool operator==(const ControlRelayOutputBlock& lhs) const + { + return this->ValuesEqual(lhs) && (this->status == lhs.status); + } +}; + + +} + + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/DNPTime.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/DNPTime.h new file mode 100644 index 0000000..cf62b8c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/DNPTime.h @@ -0,0 +1,34 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DNPTIME_H +#define OPENDNP3_DNPTIME_H + +#include + +namespace opendnp3 +{ + +typedef openpal::UInt48Type DNPTime; + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventCells.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventCells.h new file mode 100644 index 0000000..dc52f00 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventCells.h @@ -0,0 +1,80 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTCELLS_H +#define OPENDNP3_EVENTCELLS_H + +#include "opendnp3/app/EventType.h" +#include "opendnp3/gen/PointClass.h" + +namespace opendnp3 +{ + +/// A null object for types that have no metadata +struct EmptyEventCell +{ + +}; + +/// Base class for different types of event metadata +template +struct EventCellBase +{ + PointClass clazz; + typename Spec::meas_t lastEvent; + typename Spec::event_variation_t evariation; + + void SetEventValue(const typename Spec::meas_t& value) + { + lastEvent = value; + } + +protected: + + EventCellBase() : clazz(PointClass::Class1), lastEvent(), evariation(Spec::DefaultEventVariation) + {} +}; + +/// Metatype w/o a deadband +template +struct SimpleEventCell : EventCellBase +{ + bool IsEvent(const typename Spec::config_t& config, const typename Spec::meas_t& newValue) const + { + return Spec::IsEvent(this->lastEvent, newValue); + } +}; + +/// Structure for holding metadata information on points that have support deadbanding +template +struct DeadbandEventCell : SimpleEventCell +{ + bool IsEvent(const typename Spec::config_t& config, const typename Spec::meas_t& newValue) const + { + return Spec::IsEvent(this->lastEvent, newValue, config.deadband); + } +}; + + +} //end namespace + + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventTriggers.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventTriggers.h new file mode 100644 index 0000000..76a863a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventTriggers.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTTRIGGERS_H +#define OPENDNP3_EVENTTRIGGERS_H + +#include "opendnp3/app/BaseMeasurementTypes.h" + +namespace opendnp3 +{ +namespace measurements +{ +template +bool IsEvent(const T& val1, const T& val2, T deadband) +{ + // T can be unsigned data type so std::abs won't work since it only directly supports signed data types + // If one uses std::abs and T is unsigned one will get an ambiguous override error. + + U diff = (val2 > val1) ? (static_cast(val2) - static_cast(val1)) : (static_cast(val1) - static_cast(val2)); + + return diff > deadband; +} + + +bool IsEvent(const TypedMeasurement& newMeas, const TypedMeasurement& oldMeas, double deadband); + +} +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventType.h new file mode 100644 index 0000000..c2bbf29 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/EventType.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTTYPE_H +#define OPENDNP3_EVENTTYPE_H + +#include + +namespace opendnp3 +{ + +static const int NUM_OUTSTATION_EVENT_TYPES = 8; + +enum class EventType : uint16_t +{ + Binary = 0, + Analog = 1, + Counter = 2, + FrozenCounter = 3, + DoubleBitBinary = 4, + BinaryOutputStatus = 5, + AnalogOutputStatus = 6, + SecurityStat = 7 +}; + +enum class EventClass : uint8_t +{ + EC1 = 0, + EC2 = 1, + EC3 = 2 +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/Flags.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/Flags.h new file mode 100644 index 0000000..9853c58 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/Flags.h @@ -0,0 +1,112 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_FLAGS_H +#define OPENDNP3_FLAGS_H + +#include "opendnp3/app/QualityMasks.h" + +namespace opendnp3 +{ + +/** + Measurement Flags +*/ +class Flags +{ +public: + + Flags() : value(0) + {} + + Flags(uint8_t value) : value(value) + {} + + inline bool IsSet(BinaryQuality flag) const + { + return IsSetAny(flag); + } + inline bool IsSet(AnalogQuality flag) const + { + return IsSetAny(flag); + } + inline bool IsSet(CounterQuality flag) const + { + return IsSetAny(flag); + } + inline bool IsSet(FrozenCounterQuality flag) const + { + return IsSetAny(flag); + } + inline bool IsSet(BinaryOutputStatusQuality flag) const + { + return IsSetAny(flag); + } + inline bool IsSet(AnalogOutputStatusQuality flag) const + { + return IsSetAny(flag); + } + + inline void Set(BinaryQuality flag) + { + SetAny(flag); + } + inline void Set(AnalogQuality flag) + { + SetAny(flag); + } + inline void Set(CounterQuality flag) + { + SetAny(flag); + } + inline void Set(FrozenCounterQuality flag) + { + SetAny(flag); + } + inline void Set(BinaryOutputStatusQuality flag) + { + SetAny(flag); + } + inline void Set(AnalogOutputStatusQuality flag) + { + SetAny(flag); + } + + uint8_t value; + +protected: + + template + bool IsSetAny(T flag) const + { + return (value & static_cast(flag)) != 0; + } + + template + void SetAny(T flag) + { + value |= static_cast(flag); + } +}; + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/GroupVariationID.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/GroupVariationID.h new file mode 100644 index 0000000..7d6606b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/GroupVariationID.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_GROUPVARIATIONID_H +#define OPENDNP3_GROUPVARIATIONID_H + +#include + +namespace opendnp3 +{ + +/// Simple uint8_t/uint8_t tuple for group and variation +struct GroupVariationID +{ + GroupVariationID() : group(0xFF), variation(0xFF) + {} + + GroupVariationID(uint8_t aGroup, uint8_t aVariation): + group(aGroup), + variation(aVariation) + { + + } + + uint8_t group; + uint8_t variation; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/IINField.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/IINField.h new file mode 100644 index 0000000..3619639 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/IINField.h @@ -0,0 +1,198 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IINFIELD_H +#define OPENDNP3_IINFIELD_H + +#include + +namespace opendnp3 +{ + +enum class IINBit +{ + ALL_STATIONS = 0, + CLASS1_EVENTS, + CLASS2_EVENTS, + CLASS3_EVENTS, + NEED_TIME, + LOCAL_CONTROL, + DEVICE_TROUBLE, + DEVICE_RESTART, + FUNC_NOT_SUPPORTED, + OBJECT_UNKNOWN, + PARAM_ERROR, + EVENT_BUFFER_OVERFLOW, + ALREADY_EXECUTING, + CONFIG_CORRUPT, + RESERVED1, + RESERVED2 = 15 +}; + +/** DNP3 two-byte IIN field. +*/ +class IINField +{ + +private: + + enum class LSBMask : uint8_t + { + ALL_STATIONS = 0x01, + CLASS1_EVENTS = 0x02, + CLASS2_EVENTS = 0x04, + CLASS3_EVENTS = 0x08, + NEED_TIME = 0x10, + LOCAL_CONTROL = 0x20, + DEVICE_TROUBLE = 0x40, + DEVICE_RESTART = 0x80, + }; + + enum class MSBMask : uint8_t + { + FUNC_NOT_SUPPORTED = 0x01, + OBJECT_UNKNOWN = 0x02, + PARAM_ERROR = 0x04, + EVENT_BUFFER_OVERFLOW = 0x08, + ALREADY_EXECUTING = 0x10, + CONFIG_CORRUPT = 0x20, + RESERVED1 = 0x40, + RESERVED2 = 0x80, + + //special mask that indicates if there was any error processing a request + REQUEST_ERROR_MASK = FUNC_NOT_SUPPORTED | OBJECT_UNKNOWN | PARAM_ERROR + }; + + +public: + + static IINField Empty() + { + return IINField(0, 0); + } + + IINField(IINBit bit) : LSB(0), MSB(0) + { + this->SetBit(bit); + } + + IINField(uint8_t aLSB, uint8_t aMSB) : LSB(aLSB), MSB(aMSB) + {} + + IINField() : LSB(0), MSB(0) + {} + + bool IsSet(IINBit bit) const; + + bool IsClear(IINBit bit) const + { + return !IsSet(bit); + } + + void SetBit(IINBit bit); + void ClearBit(IINBit bit); + + void SetBitToValue(IINBit bit, bool value); + + bool operator==(const IINField& arRHS) const; + + bool Any() const + { + return (LSB | MSB) != 0; + } + + void Clear() + { + LSB = MSB = 0; + } + + bool HasRequestError() const + { + return Get(MSBMask::REQUEST_ERROR_MASK); + } + + IINField operator|(const IINField& aIIN) const + { + return IINField(LSB | aIIN.LSB, MSB | aIIN.MSB); + } + + IINField& operator|=(const IINField& aIIN) + { + MSB |= aIIN.MSB; + LSB |= aIIN.LSB; + return *this; + } + + IINField operator&(const IINField& aIIN) const + { + return IINField(LSB & aIIN.LSB, MSB & aIIN.MSB); + } + + IINField& operator&=(const IINField& aIIN) + { + MSB &= aIIN.MSB; + LSB &= aIIN.LSB; + return *this; + } + + IINField operator~() const + { + return IINField(~LSB, ~MSB); + } + + uint8_t LSB; + uint8_t MSB; + +private: + + static const uint8_t REQUEST_ERROR_MASK; + + inline bool Get(LSBMask bit) const + { + return (LSB & static_cast(bit)) != 0; + } + + inline bool Get(MSBMask bit) const + { + return (MSB & static_cast(bit)) != 0; + } + + inline void Set(LSBMask bit) + { + LSB |= static_cast(bit); + } + inline void Set(MSBMask bit) + { + MSB |= static_cast(bit); + } + + inline void Clear(LSBMask bit) + { + LSB &= ~static_cast(bit); + } + inline void Clear(MSBMask bit) + { + MSB &= ~static_cast(bit); + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/ITransactable.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/ITransactable.h new file mode 100644 index 0000000..4323d68 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/ITransactable.h @@ -0,0 +1,102 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ITRANSACTABLE_H +#define OPENDNP3_ITRANSACTABLE_H + +#include + +namespace opendnp3 +{ + +/** + Something that can be performed atomically or needing Start()/End() signals +*/ +class ITransactable +{ +public: + + friend class Transaction; + virtual ~ITransactable() {} + +protected: + + virtual void Start() = 0; + virtual void End() = 0; +}; + +/** + Uses RAII to safely perform a transaction +*/ +class Transaction : private openpal::Uncopyable +{ +public: + + Transaction(ITransactable& transactable) : pTransactable(&transactable) + { + pTransactable->Start(); + } + + Transaction(ITransactable* pTransactable_) : pTransactable(pTransactable_) + { + if (pTransactable) + { + pTransactable->Start(); + } + } + + ~Transaction() + { + if (pTransactable) + { + pTransactable->End(); + } + } + + static void Start(ITransactable* t) + { + if (t) + { + t->Start(); + } + } + static void End(ITransactable* t) + { + if (t) + { + t->End(); + } + } + + template + static ReturnType Apply(TransactionType& transactable, const Fun& fun) + { + Transaction t(transactable); + return fun(transactable); + } + +private: + ITransactable* pTransactable; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/Indexed.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/Indexed.h new file mode 100644 index 0000000..62a9667 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/Indexed.h @@ -0,0 +1,56 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_INDEXED_H +#define OPENDNP3_INDEXED_H + +#include + +namespace opendnp3 +{ + +/** +* A simple tuple for pairing Values with an index +*/ +template +class Indexed +{ +public: + Indexed(const T& value_, uint16_t index_) : + value(value_), + index(index_) + {} + + Indexed(): value(), index(0) + {} + + T value; + uint16_t index; +}; + +template +Indexed WithIndex(const T& value, uint16_t index) +{ + return Indexed(value, index); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementInfo.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementInfo.h new file mode 100644 index 0000000..80abf9a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementInfo.h @@ -0,0 +1,175 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MEASUREMENTINFO_H +#define OPENDNP3_MEASUREMENTINFO_H + +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/app/SecurityStat.h" + +#include "opendnp3/app/EventType.h" + +#include "opendnp3/gen/StaticBinaryVariation.h" +#include "opendnp3/gen/StaticDoubleBinaryVariation.h" +#include "opendnp3/gen/StaticBinaryOutputStatusVariation.h" +#include "opendnp3/gen/StaticCounterVariation.h" +#include "opendnp3/gen/StaticFrozenCounterVariation.h" +#include "opendnp3/gen/StaticAnalogVariation.h" +#include "opendnp3/gen/StaticAnalogOutputStatusVariation.h" +#include "opendnp3/gen/StaticTimeAndIntervalVariation.h" +#include "opendnp3/gen/StaticSecurityStatVariation.h" + +#include "opendnp3/gen/EventBinaryVariation.h" +#include "opendnp3/gen/EventDoubleBinaryVariation.h" +#include "opendnp3/gen/EventBinaryOutputStatusVariation.h" +#include "opendnp3/gen/EventCounterVariation.h" +#include "opendnp3/gen/EventFrozenCounterVariation.h" +#include "opendnp3/gen/EventAnalogVariation.h" +#include "opendnp3/gen/EventAnalogOutputStatusVariation.h" +#include "opendnp3/gen/EventSecurityStatVariation.h" + +#include "opendnp3/gen/StaticTypeBitmask.h" +#include "opendnp3/gen/BinaryQuality.h" +#include "openpal/util/Uncopyable.h" + +namespace opendnp3 +{ + + +struct BinaryInfo : private openpal::StaticOnly +{ + typedef Binary meas_t; + typedef bool value_t; + typedef EventBinaryVariation event_variation_t; + typedef StaticBinaryVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::Binary; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::BinaryInput; + static const event_variation_t DefaultEventVariation = EventBinaryVariation::Group2Var1; + static const static_variation_t DefaultStaticVariation = StaticBinaryVariation::Group1Var2; +}; + +struct DoubleBitBinaryInfo : private openpal::StaticOnly +{ + typedef DoubleBitBinary meas_t; + typedef DoubleBit value_t; + typedef EventDoubleBinaryVariation event_variation_t; + typedef StaticDoubleBinaryVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::DoubleBitBinary; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::DoubleBinaryInput; + static const event_variation_t DefaultEventVariation = EventDoubleBinaryVariation::Group4Var1; + static const static_variation_t DefaultStaticVariation = StaticDoubleBinaryVariation::Group3Var2; +}; + +class BinaryOutputStatusInfo : private openpal::StaticOnly +{ +public: + + typedef BinaryOutputStatus meas_t; + typedef bool value_t; + typedef EventBinaryOutputStatusVariation event_variation_t; + typedef StaticBinaryOutputStatusVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::BinaryOutputStatus; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::BinaryOutputStatus; + static const event_variation_t DefaultEventVariation = EventBinaryOutputStatusVariation::Group11Var1; + static const static_variation_t DefaultStaticVariation = StaticBinaryOutputStatusVariation::Group10Var2; + + +}; + + +struct AnalogInfo : private openpal::StaticOnly +{ + typedef Analog meas_t; + typedef double value_t; + typedef EventAnalogVariation event_variation_t; + typedef StaticAnalogVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::Analog; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::AnalogInput; + static const event_variation_t DefaultEventVariation = EventAnalogVariation::Group32Var1; + static const static_variation_t DefaultStaticVariation = StaticAnalogVariation::Group30Var1; +}; + +struct CounterInfo : private openpal::StaticOnly +{ + typedef Counter meas_t; + typedef uint32_t value_t; + typedef EventCounterVariation event_variation_t; + typedef StaticCounterVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::Counter; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::Counter; + static const event_variation_t DefaultEventVariation = EventCounterVariation::Group22Var1; + static const static_variation_t DefaultStaticVariation = StaticCounterVariation::Group20Var1; +}; + +struct FrozenCounterInfo : private openpal::StaticOnly +{ + typedef FrozenCounter meas_t; + typedef uint32_t value_t; + typedef EventFrozenCounterVariation event_variation_t; + typedef StaticFrozenCounterVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::FrozenCounter; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::FrozenCounter; + static const event_variation_t DefaultEventVariation = EventFrozenCounterVariation::Group23Var1; + static const static_variation_t DefaultStaticVariation = StaticFrozenCounterVariation::Group21Var1; +}; + +struct AnalogOutputStatusInfo : private openpal::StaticOnly +{ + typedef AnalogOutputStatus meas_t; + typedef double value_t; + typedef EventAnalogOutputStatusVariation event_variation_t; + typedef StaticAnalogOutputStatusVariation static_variation_t; + + static const EventType EventTypeEnum = EventType::AnalogOutputStatus; + static const StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::AnalogOutputStatus; + static const event_variation_t DefaultEventVariation = EventAnalogOutputStatusVariation::Group42Var1; + static const static_variation_t DefaultStaticVariation = StaticAnalogOutputStatusVariation::Group40Var1; +}; + +struct TimeAndIntervalInfo : private openpal::StaticOnly +{ + typedef TimeAndInterval meas_t; + typedef StaticTimeAndIntervalVariation static_variation_t; + + const static StaticTypeBitmask StaticTypeEnum = StaticTypeBitmask::TimeAndInterval; + const static StaticTimeAndIntervalVariation DefaultStaticVariation = StaticTimeAndIntervalVariation::Group50Var4; +}; + +struct SecurityStatInfo : private openpal::StaticOnly +{ + typedef SecurityStat meas_t; + typedef SecurityStat::Value value_t; + typedef EventSecurityStatVariation event_variation_t; + typedef StaticSecurityStatVariation static_variation_t; + + const static EventType EventTypeEnum = EventType::SecurityStat; + const static event_variation_t DefaultEventVariation = EventSecurityStatVariation::Group122Var1; + const static static_variation_t DefaultStaticVariation = StaticSecurityStatVariation::Group121Var1; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypeSpecs.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypeSpecs.h new file mode 100644 index 0000000..ff3ee33 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypeSpecs.h @@ -0,0 +1,155 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MEASUREMENTTYPESPECS_H +#define OPENDNP3_MEASUREMENTTYPESPECS_H + +#include "opendnp3/outstation/MeasurementConfig.h" +#include "opendnp3/app/EventCells.h" +#include "opendnp3/app/EventTriggers.h" + +namespace opendnp3 +{ + + +struct BinarySpec : public BinaryInfo +{ + typedef BinaryConfig config_t; + typedef SimpleEventCell event_cell_t; + + inline static bool IsQualityOnlineOnly(const Binary& binary) + { + return (binary.flags.value & 0b01111111) == static_cast(BinaryQuality::ONLINE); + } + + inline static bool IsEvent(const Binary& oldValue, const Binary& newValue) + { + return oldValue.flags.value != newValue.flags.value; + } +}; + +struct DoubleBitBinarySpec : public DoubleBitBinaryInfo +{ + typedef DoubleBitBinaryConfig config_t; + typedef SimpleEventCell event_cell_t; + + inline static bool IsEvent(const DoubleBitBinary& oldValue, const DoubleBitBinary& newValue) + { + return oldValue.flags.value != newValue.flags.value; + } +}; + +struct BinaryOutputStatusSpec : public BinaryOutputStatusInfo +{ + typedef BOStatusConfig config_t; + typedef SimpleEventCell event_cell_t; + + inline static bool IsEvent(const BinaryOutputStatus& oldValue, const BinaryOutputStatus& newValue) + { + return oldValue.flags.value != newValue.flags.value; + } +}; + + +struct AnalogSpec : public AnalogInfo +{ + typedef AnalogConfig config_t; + typedef DeadbandEventCell event_cell_t; + + inline static bool IsEvent(const Analog& oldValue, const Analog& newValue, double deadband) + { + return measurements::IsEvent(newValue, oldValue, deadband); + } +}; + +struct CounterSpec : public CounterInfo +{ + typedef CounterConfig config_t; + typedef DeadbandEventCell event_cell_t; + + inline static bool IsEvent(const Counter& oldValue, const Counter& newValue, uint32_t deadband) + { + if (oldValue.flags.value != newValue.flags.value) + { + return true; + } + else + { + return measurements::IsEvent(oldValue.value, newValue.value, deadband); + } + } +}; + +struct FrozenCounterSpec : public FrozenCounterInfo +{ + typedef FrozenCounterConfig config_t; + typedef DeadbandEventCell event_cell_t; + + inline static bool IsEvent(const FrozenCounter& oldValue, const FrozenCounter& newValue, uint32_t deadband) + { + if (oldValue.flags.value != newValue.flags.value) + { + return true; + } + else + { + return measurements::IsEvent(oldValue.value, newValue.value, deadband); + } + } +}; + +struct AnalogOutputStatusSpec : public AnalogOutputStatusInfo +{ + typedef AOStatusConfig config_t; + typedef DeadbandEventCell event_cell_t; + + inline static bool IsEvent(const AnalogOutputStatus& oldValue, const AnalogOutputStatus& newValue, double deadband) + { + return measurements::IsEvent(newValue, oldValue, deadband); + } +}; + +struct TimeAndIntervalSpec : public TimeAndIntervalInfo +{ + typedef TimeAndIntervalConfig config_t; + typedef EmptyEventCell event_cell_t; +}; + +struct SecurityStatSpec : public SecurityStatInfo +{ + typedef SecurityStatConfig config_t; + typedef EmptyEventCell event_cell_t; + + inline static bool IsEvent(const SecurityStat& oldValue, const SecurityStat& newValue, uint32_t deadband) + { + if (oldValue.quality != newValue.quality) + { + return true; + } + else + { + return measurements::IsEvent(oldValue.value.count, newValue.value.count, deadband); + } + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypes.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypes.h new file mode 100644 index 0000000..0433e56 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/MeasurementTypes.h @@ -0,0 +1,200 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MEASUREMENTTYPES_H +#define OPENDNP3_MEASUREMENTTYPES_H + +#include "opendnp3/app/BaseMeasurementTypes.h" + +#include "opendnp3/gen/DoubleBit.h" +#include "opendnp3/gen/IntervalUnits.h" + +namespace opendnp3 +{ + +/** + The Binary data type is for describing on-off (boolean) type values. Good examples of + binaries are alarms, mode settings, enabled/disabled flags etc. Think of it as a status + LED on a piece of equipment. +*/ +class Binary : public TypedMeasurement +{ +public: + + Binary(); + + Binary(bool value); + + Binary(Flags flags); + + Binary(Flags flags, DNPTime time); + + Binary(bool value, Flags flags); + + Binary(bool value, Flags flags, DNPTime time); +}; + +/** +The Double-bit Binary data type has two stable states, on and off, and an in transit state. Motor operated switches +or binary valves are good examples. +*/ +class DoubleBitBinary : public TypedMeasurement +{ +public: + + + DoubleBitBinary(); + + DoubleBitBinary(DoubleBit value); + + DoubleBitBinary(Flags flags); + + DoubleBitBinary(Flags flags, DNPTime time); + + DoubleBitBinary(DoubleBit value, Flags flags); + + DoubleBitBinary(DoubleBit value, Flags flags, DNPTime time); + +private: + + static const uint8_t ValueMask = 0xC0; + static const uint8_t QualityMask = 0x3F; + + static DoubleBit GetValue(Flags flags); + + static Flags GetFlags(Flags flags, DoubleBit state); +}; + + +/** + BinaryOutputStatus is used for describing the current state of a control. It is very infrequently + used and many masters don't provide any mechanisms for reading these values so their use is + strongly discouraged, a Binary should be used instead. +*/ +class BinaryOutputStatus : public TypedMeasurement +{ +public: + + BinaryOutputStatus(); + + BinaryOutputStatus(bool value); + + BinaryOutputStatus(Flags flags); + + BinaryOutputStatus(Flags flags, DNPTime time); + + BinaryOutputStatus(bool value, Flags flags); + + BinaryOutputStatus(bool value, Flags flags, DNPTime time); + +}; + +/** + Analogs are used for variable data points that usually reflect a real world value. + Good examples are current, voltage, sensor readouts, etc. Think of a speedometer guage. +*/ + +class Analog : public TypedMeasurement +{ +public: + + Analog(); + + Analog(double value); + + Analog(double value, Flags flags); + + Analog(double value, Flags flags, DNPTime time); +}; + +/** + Counters are used for describing generally increasing values (non-negative!). Good examples are + total power consumed, max voltage. Think odometer on a car. +*/ +class Counter : public TypedMeasurement +{ +public: + + Counter(); + + Counter(uint32_t value); + + Counter(uint32_t value, Flags flags); + + Counter(uint32_t value, Flags flags, DNPTime time); +}; + +/** + Frozen counters are used to report the value of a counter point captured at the instant when the count is frozen. +*/ +class FrozenCounter : public TypedMeasurement +{ +public: + + FrozenCounter(); + + FrozenCounter(uint32_t value); + + FrozenCounter(uint32_t value, Flags flags); + + FrozenCounter(uint32_t value, Flags flags, DNPTime time); +}; + +/** + Describes the last set value of the set-point. Like the BinaryOutputStatus data type it is not + well supported and its generally better practice to use an explicit analog. +*/ +class AnalogOutputStatus : public TypedMeasurement +{ +public: + + AnalogOutputStatus(); + + AnalogOutputStatus(double value); + + AnalogOutputStatus(double value, Flags flags); + + AnalogOutputStatus(double value, Flags flags, DNPTime time); +}; + +/** + Maps to Group50Var4 + This class is a bit of an outlier as an indexed type and is really only used in the DNP3 PV profile +*/ +class TimeAndInterval +{ +public: + + TimeAndInterval(); + + TimeAndInterval(DNPTime time, uint32_t interval, uint8_t units); + + TimeAndInterval(DNPTime time, uint32_t interval, IntervalUnits units); + + IntervalUnits GetUnitsEnum() const; + + DNPTime time; + uint32_t interval; + uint8_t units; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetData.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetData.h new file mode 100644 index 0000000..b823a06 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetData.h @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OCTETDATA_H +#define OPENDNP3_OCTETDATA_H + +#include + +#include +#include + +namespace opendnp3 +{ + +/** +* A base-class for bitstrings containing up to 255 bytes +*/ +class OctetData +{ +public: + + const static uint8_t MAX_SIZE = 255; + + OctetData(); + OctetData(const openpal::RSlice& input); + + openpal::RSlice ToRSlice() const; + +private: + + void Initialize(const openpal::RSlice& buffer); + + openpal::StaticBuffer buffer; + uint8_t size; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetString.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetString.h new file mode 100644 index 0000000..cfd3aac --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/OctetString.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OCTETSTRING_H +#define OPENDNP3_OCTETSTRING_H + +#include "OctetData.h" + +namespace opendnp3 +{ + +/** +* Respresents group 110/111 objects +*/ +class OctetString : public OctetData +{ +public: + + OctetString() : OctetData() + {} + + OctetString(const OctetString& data) : OctetData(data) + {} + + OctetString(const openpal::RSlice& buffer) : OctetData(buffer) + {} + +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/QualityMasks.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/QualityMasks.h new file mode 100644 index 0000000..492ad80 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/QualityMasks.h @@ -0,0 +1,44 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_QUALITYMASKS_H +#define OPENDNP3_QUALITYMASKS_H + +#include "opendnp3/gen/BinaryQuality.h" +#include "opendnp3/gen/DoubleBitBinaryQuality.h" +#include "opendnp3/gen/CounterQuality.h" +#include "opendnp3/gen/FrozenCounterQuality.h" +#include "opendnp3/gen/AnalogQuality.h" + +#include "opendnp3/gen/AnalogOutputStatusQuality.h" +#include "opendnp3/gen/BinaryOutputStatusQuality.h" + +namespace opendnp3 +{ + +template +inline uint8_t ToUnderlying(T flag) +{ + return static_cast(flag); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/SecurityStat.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/SecurityStat.h new file mode 100644 index 0000000..0e231cb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/SecurityStat.h @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SECURITYSTATISTIC_H +#define OPENDNP3_SECURITYSTATISTIC_H + +#include "opendnp3/app/DNPTime.h" + +namespace opendnp3 +{ + + + +/** + SA security statistic object as used by the API. +*/ +class SecurityStat +{ +public: + + // this is the easiest way to make the SecurityStats look like other types + struct Value + { + uint16_t assocId; + uint32_t count; + }; + + SecurityStat(); + + SecurityStat(Value value, uint8_t quality, DNPTime time); + + SecurityStat(uint8_t quality, uint16_t assocId, uint32_t count); + + SecurityStat(uint8_t quality, uint16_t assocId, uint32_t count, DNPTime time); + + uint8_t quality; // bitfield that stores type specific quality flags + Value value; // assocId and count + DNPTime time; // timestamp associated with the measurement (may not be set) +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/app/parsing/ICollection.h b/utils/dnp3_src/cpp/libs/include/opendnp3/app/parsing/ICollection.h new file mode 100644 index 0000000..12b0d8e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/app/parsing/ICollection.h @@ -0,0 +1,115 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICOLLECTION_H +#define OPENDNP3_ICOLLECTION_H + +#include + +namespace opendnp3 +{ + +/** +* Abstract way of visiting elements of a collection +* +*/ +template +class IVisitor +{ +public: + + virtual void OnValue(const T& value) = 0; +}; + +/** +* A visitor implemented as an abstract functor +* +*/ +template +class FunctorVisitor : public IVisitor +{ + +public: + + FunctorVisitor(const Fun& fun_) : fun(fun_) {} + + virtual void OnValue(const T& value) override final + { + fun(value); + } + +private: + Fun fun; +}; + +/** +* An interface representing an abstract immutable collection of things of type T. +* +* The user can only read these values via callback to receive each element. +*/ +template +class ICollection +{ +public: + + /** + * The number of elements in the collection + */ + virtual size_t Count() const = 0; + + /** + * Visit all the elements of a collection + */ + virtual void Foreach(IVisitor& visitor) const = 0; + + /** + visit all of the elements of a collection + */ + template + void ForeachItem(const Fun& fun) const + { + FunctorVisitor visitor(fun); + this->Foreach(visitor); + } + + /** + Retrieve the only value from the collection. + */ + bool ReadOnlyValue(T& value) const + { + if (this->Count() == 1) + { + auto assignValue = [&value](const T & item) + { + value = item; + }; + this->ForeachItem(assignValue); + return true; + } + else + { + return false; + } + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogOutputStatusQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogOutputStatusQuality.h new file mode 100644 index 0000000..da62ede --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogOutputStatusQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_ANALOGOUTPUTSTATUSQUALITY_H +#define OPENDNP3_ANALOGOUTPUTSTATUSQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for analog output status values +*/ +enum class AnalogOutputStatusQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// set if a hardware input etc. is out of range and we are using a place holder value + OVERRANGE = 0x20, + /// set if calibration or reference voltage has been lost meaning readings are questionable + REFERENCE_ERR = 0x40, + /// reserved bit + RESERVED = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogQuality.h new file mode 100644 index 0000000..b7c13b0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AnalogQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_ANALOGQUALITY_H +#define OPENDNP3_ANALOGQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for analog values +*/ +enum class AnalogQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// set if a hardware input etc. is out of range and we are using a place holder value + OVERRANGE = 0x20, + /// set if calibration or reference voltage has been lost meaning readings are questionable + REFERENCE_ERR = 0x40, + /// reserved bit + RESERVED = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AssignClassType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AssignClassType.h new file mode 100644 index 0000000..81e7f4c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AssignClassType.h @@ -0,0 +1,45 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_ASSIGNCLASSTYPE_H +#define OPENDNP3_ASSIGNCLASSTYPE_H + +#include + +namespace opendnp3 { + +/** + groups that can be used inconjunction with the ASSIGN_CLASS function code +*/ +enum class AssignClassType : uint8_t +{ + BinaryInput = 0x0, + DoubleBinaryInput = 0x1, + Counter = 0x2, + FrozenCounter = 0x3, + AnalogInput = 0x4, + BinaryOutputStatus = 0x5, + AnalogOutputStatus = 0x6 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/Attributes.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/Attributes.h new file mode 100644 index 0000000..d02ba59 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/Attributes.h @@ -0,0 +1,35 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_ATTRIBUTES_H +#define OPENDNP3_ATTRIBUTES_H + +#include "opendnp3/gen/GroupVariation.h" + +namespace opendnp3 { + +bool HasAbsoluteTime(GroupVariation gv); +bool HasRelativeTime(GroupVariation gv); +bool HasFlags(GroupVariation gv); +bool IsEvent(GroupVariation gv); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AuthErrorCode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AuthErrorCode.h new file mode 100644 index 0000000..60abcde --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/AuthErrorCode.h @@ -0,0 +1,63 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_AUTHERRORCODE_H +#define OPENDNP3_AUTHERRORCODE_H + +#include + +namespace opendnp3 { + +/** + Specifies the reason that an auth error message was transmitted +*/ +enum class AuthErrorCode : uint8_t +{ + /// Supplied auth information + AUTHENTICATION_FAILED = 0x1, + /// Aggressive mode not supported on this link + AGGRESSIVE_MODE_UNSUPPORTED = 0x4, + /// The specified MAC algorithm is not supported + MAC_NOT_SUPPORTED = 0x5, + /// The key-wrap algorithm is not supported + KEY_WRAP_NOT_SUPPORTED = 0x6, + /// Authentication passed, but that user not authorized for requested operation + AUTHORIZATION_FAILED = 0x7, + /// The outstation does not support specified key change method on this link + UPDATE_KEY_METHOD_NOT_PERMITTED = 0x8, + /// The digital signature supplied in a user status change object was invalid + INVALID_SIGNATURE = 0x9, + /// The certification data supplied in a user status change object was invalid + INVALID_CERTIFICATION_DATA = 0xA, + /// The master attempted to change the Update Key of a user without a valid prior user status change + UNKNOWN_USER = 0xB, + /// The master on a different association has requred session key status too often + MAX_SESSION_KEY_STATUS_REQUESTS_EXCEEDED = 0xC, + /// Unknown error code + UNKNOWN = 0x0 +}; + +uint8_t AuthErrorCodeToType(AuthErrorCode arg); +AuthErrorCode AuthErrorCodeFromType(uint8_t arg); +char const* AuthErrorCodeToString(AuthErrorCode arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryOutputStatusQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryOutputStatusQuality.h new file mode 100644 index 0000000..ae8e39b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryOutputStatusQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_BINARYOUTPUTSTATUSQUALITY_H +#define OPENDNP3_BINARYOUTPUTSTATUSQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for binary output status values +*/ +enum class BinaryOutputStatusQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// reserved bit 1 + RESERVED1 = 0x20, + /// reserved bit 2 + RESERVED2 = 0x40, + /// state bit + STATE = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryQuality.h new file mode 100644 index 0000000..e26a0c8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/BinaryQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_BINARYQUALITY_H +#define OPENDNP3_BINARYQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for binary values +*/ +enum class BinaryQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// set if the value is oscillating very quickly and some events are being suppressed + CHATTER_FILTER = 0x20, + /// reserved bit + RESERVED = 0x40, + /// state bit + STATE = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CertificateType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CertificateType.h new file mode 100644 index 0000000..405e81d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CertificateType.h @@ -0,0 +1,47 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_CERTIFICATETYPE_H +#define OPENDNP3_CERTIFICATETYPE_H + +#include + +namespace opendnp3 { + +/** + Specifies the reason that an auth error message was transmitted +*/ +enum class CertificateType : uint8_t +{ + /// ID certificate + ID_CERTIFICATE = 0x1, + /// Attribute certificate + ATTRIBUTE_CERTIFICATE = 0x2, + /// Unknown certificate type + UNKNOWN = 0x0 +}; + +uint8_t CertificateTypeToType(CertificateType arg); +CertificateType CertificateTypeFromType(uint8_t arg); +char const* CertificateTypeToString(CertificateType arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChallengeReason.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChallengeReason.h new file mode 100644 index 0000000..173ace2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChallengeReason.h @@ -0,0 +1,45 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_CHALLENGEREASON_H +#define OPENDNP3_CHALLENGEREASON_H + +#include + +namespace opendnp3 { + +/** + Enumerates reasons for a sec-auth challenge +*/ +enum class ChallengeReason : uint8_t +{ + /// Challenging a critical function + CRITICAL = 0x1, + /// Unknown reason + UNKNOWN = 0xFF +}; + +uint8_t ChallengeReasonToType(ChallengeReason arg); +ChallengeReason ChallengeReasonFromType(uint8_t arg); +char const* ChallengeReasonToString(ChallengeReason arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChannelState.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChannelState.h new file mode 100644 index 0000000..689d05f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ChannelState.h @@ -0,0 +1,47 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_CHANNELSTATE_H +#define OPENDNP3_CHANNELSTATE_H + +#include + +namespace opendnp3 { + +/** + Enumeration for possible states of a channel +*/ +enum class ChannelState : uint8_t +{ + /// offline and idle + CLOSED = 0, + /// trying to open + OPENING = 1, + /// open + OPEN = 2, + /// stopped and will never do anything again + SHUTDOWN = 3 +}; + +char const* ChannelStateToString(ChannelState arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandPointState.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandPointState.h new file mode 100644 index 0000000..c7d0e04 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandPointState.h @@ -0,0 +1,51 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_COMMANDPOINTSTATE_H +#define OPENDNP3_COMMANDPOINTSTATE_H + +#include + +namespace opendnp3 { + +/** + List the various states that an individual command object can be in after an SBO or direct operate request +*/ +enum class CommandPointState : uint8_t +{ + /// No corresponding response was ever received for this command point + INIT = 0, + /// A response to a select request was received and matched, but the operate did not complete + SELECT_SUCCESS = 1, + /// A response to a select operation did not contain the same value that was sent + SELECT_MISMATCH = 2, + /// A response to a select operation contained a command status other than success + SELECT_FAIL = 3, + /// A response to an operate or direct operate did not match the request + OPERATE_FAIL = 4, + /// A matching response was received to the operate + SUCCESS = 5 +}; + +char const* CommandPointStateToString(CommandPointState arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandStatus.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandStatus.h new file mode 100644 index 0000000..badc810 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CommandStatus.h @@ -0,0 +1,84 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_COMMANDSTATUS_H +#define OPENDNP3_COMMANDSTATUS_H + +#include + +namespace opendnp3 { + +/** + An enumeration of result codes received from an outstation in response to command request. + These correspond to those defined in the DNP3 standard +*/ +enum class CommandStatus : uint8_t +{ + /// command was accepted, initiated, or queued + SUCCESS = 0, + /// command timed out before completing + TIMEOUT = 1, + /// command requires being selected before operate, configuration issue + NO_SELECT = 2, + /// bad control code or timing values + FORMAT_ERROR = 3, + /// command is not implemented + NOT_SUPPORTED = 4, + /// command is all ready in progress or its all ready in that mode + ALREADY_ACTIVE = 5, + /// something is stopping the command, often a local/remote interlock + HARDWARE_ERROR = 6, + /// the function governed by the control is in local only control + LOCAL = 7, + /// the command has been done too often and has been throttled + TOO_MANY_OPS = 8, + /// the command was rejected because the device denied it or an RTU intercepted it + NOT_AUTHORIZED = 9, + /// command not accepted because it was prevented or inhibited by a local automation process, such as interlocking logic or synchrocheck + AUTOMATION_INHIBIT = 10, + /// command not accepted because the device cannot process any more activities than are presently in progress + PROCESSING_LIMITED = 11, + /// command not accepted because the value is outside the acceptable range permitted for this point + OUT_OF_RANGE = 12, + /// command not accepted because the outstation is forwarding the request to another downstream device which reported LOCAL + DOWNSTREAM_LOCAL = 13, + /// command not accepted because the outstation has already completed the requested operation + ALREADY_COMPLETE = 14, + /// command not accepted because the requested function is specifically blocked at the outstation + BLOCKED = 15, + /// command not accepted because the operation was cancelled + CANCELLED = 16, + /// command not accepted because another master is communicating with the outstation and has exclusive rights to operate this control point + BLOCKED_OTHER_MASTER = 17, + /// command not accepted because the outstation is forwarding the request to another downstream device which cannot be reached or is otherwise incapable of performing the request + DOWNSTREAM_FAIL = 18, + /// (deprecated) indicates the outstation shall not issue or perform the control operation + NON_PARTICIPATING = 126, + /// 10 to 126 are currently reserved + UNDEFINED = 127 +}; + +uint8_t CommandStatusToType(CommandStatus arg); +CommandStatus CommandStatusFromType(uint8_t arg); +char const* CommandStatusToString(CommandStatus arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ConfigAuthMode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ConfigAuthMode.h new file mode 100644 index 0000000..8621edf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ConfigAuthMode.h @@ -0,0 +1,42 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_CONFIGAUTHMODE_H +#define OPENDNP3_CONFIGAUTHMODE_H + +#include + +namespace opendnp3 { + +/** + Configuration enum for the authentication mode +*/ +enum class ConfigAuthMode : uint8_t +{ + /// No authentication + NONE = 0x0, + /// Secure authentication version 5 + SAV5 = 0x1 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ControlCode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ControlCode.h new file mode 100644 index 0000000..56687b1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/ControlCode.h @@ -0,0 +1,72 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_CONTROLCODE_H +#define OPENDNP3_CONTROLCODE_H + +#include + +namespace opendnp3 { + +/** + Defines the interoperable values of the Control Code + Refer to pages 506-510 of 1815 for a full description +*/ +enum class ControlCode : uint8_t +{ + /// Does not initiate an action or change an in-progress or pending command. + NUL = 0x0, + /// Cancel in-progress and pending commands. Take no additional action. + NUL_CANCEL = 0x20, + /// For activation model, set output to active for the duration of the On-time. For both complementary models, return NOT_SUPPORTED status. + PULSE_ON = 0x1, + /// Cancel in-progress and pending commands, process the remainder of the fields as if the control code were PULSE_ON + PULSE_ON_CANCEL = 0x21, + /// Non-interoperable code. Do not use for new applications. return NOT_SUPPORTED + PULSE_OFF = 0x2, + /// Non-interoperable code. Do not use for new applications. Cancel in-progress and pending commands, process remainder of fields as if the control code were PULSE_OFF + PULSE_OFF_CANCEL = 0x22, + /// For activation model, set output to active for the duration of the On-time. For complementary latch model, set the output to active. For complementary two-output model, set the close output to active for the duration of the On-time. + LATCH_ON = 0x3, + /// Cancel in-progress and pending commands, process the remainder of the fields as if the control code were LATCH_ON. + LATCH_ON_CANCEL = 0x23, + /// For activation model, set output to active for the duration of the On-time. For complementary latch model, set the output to inactive. For complementary two-output model, set the trip output to active for the duration of the On-time. + LATCH_OFF = 0x4, + /// Cancel in-progress and pending commands, process the remainder of the fields as if the control code were LATCH_OFF. + LATCH_OFF_CANCEL = 0x24, + /// For activation model, set output to active for the duration of the On-time. For complementary latch model, set the output to active. For complementary two-output model, set the close output to active for the duration of the On-time. + CLOSE_PULSE_ON = 0x41, + /// Cancel in-progress and pending commands, process the remainder of the fields as if the control code were CLOSE_PULSE_ON. + CLOSE_PULSE_ON_CANCEL = 0x61, + /// For activation model, set output to active for the duration of the On-time. For complementary latch model, set the output to inactive. For complementary two-output model, set the trip output to active for the duration of the On-time. + TRIP_PULSE_ON = 0x81, + /// Cancel in-progress and pending commands, process the remainder of the fields as if the control code were TRIP_PULSE_ON. + TRIP_PULSE_ON_CANCEL = 0xA1, + /// undefined command (used by DNP standard) + UNDEFINED = 0xFF +}; + +uint8_t ControlCodeToType(ControlCode arg); +ControlCode ControlCodeFromType(uint8_t arg); +char const* ControlCodeToString(ControlCode arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CounterQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CounterQuality.h new file mode 100644 index 0000000..4275f05 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/CounterQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_COUNTERQUALITY_H +#define OPENDNP3_COUNTERQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for counter values +*/ +enum class CounterQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// Deprecated flag that indicates value has rolled over + ROLLOVER = 0x20, + /// indicates an unusual change in value + DISCONTINUITY = 0x40, + /// reserved bit + RESERVED = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBit.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBit.h new file mode 100644 index 0000000..5c1b6bc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBit.h @@ -0,0 +1,49 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_DOUBLEBIT_H +#define OPENDNP3_DOUBLEBIT_H + +#include + +namespace opendnp3 { + +/** + Enumeration for possible states of a double bit value +*/ +enum class DoubleBit : uint8_t +{ + /// Transitioning between end conditions + INTERMEDIATE = 0x0, + /// End condition, determined to be OFF + DETERMINED_OFF = 0x1, + /// End condition, determined to be ON + DETERMINED_ON = 0x2, + /// Abnormal or custom condition + INDETERMINATE = 0x3 +}; + +uint8_t DoubleBitToType(DoubleBit arg); +DoubleBit DoubleBitFromType(uint8_t arg); +char const* DoubleBitToString(DoubleBit arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBitBinaryQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBitBinaryQuality.h new file mode 100644 index 0000000..8d670df --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/DoubleBitBinaryQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_DOUBLEBITBINARYQUALITY_H +#define OPENDNP3_DOUBLEBITBINARYQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for double bit binary values +*/ +enum class DoubleBitBinaryQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// set if the value is oscillating very quickly and some events are being suppressed + CHATTER_FILTER = 0x20, + /// state bit 1 + STATE1 = 0x40, + /// state bit 2 + STATE2 = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogOutputStatusVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogOutputStatusVariation.h new file mode 100644 index 0000000..021a182 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogOutputStatusVariation.h @@ -0,0 +1,43 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTANALOGOUTPUTSTATUSVARIATION_H +#define OPENDNP3_EVENTANALOGOUTPUTSTATUSVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventAnalogOutputStatusVariation : uint8_t +{ + Group42Var1 = 0, + Group42Var2 = 1, + Group42Var3 = 2, + Group42Var4 = 3, + Group42Var5 = 4, + Group42Var6 = 5, + Group42Var7 = 6, + Group42Var8 = 7 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogVariation.h new file mode 100644 index 0000000..11ad437 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventAnalogVariation.h @@ -0,0 +1,43 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTANALOGVARIATION_H +#define OPENDNP3_EVENTANALOGVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventAnalogVariation : uint8_t +{ + Group32Var1 = 0, + Group32Var2 = 1, + Group32Var3 = 2, + Group32Var4 = 3, + Group32Var5 = 4, + Group32Var6 = 5, + Group32Var7 = 6, + Group32Var8 = 7 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryOutputStatusVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryOutputStatusVariation.h new file mode 100644 index 0000000..50ffefb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryOutputStatusVariation.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTBINARYOUTPUTSTATUSVARIATION_H +#define OPENDNP3_EVENTBINARYOUTPUTSTATUSVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventBinaryOutputStatusVariation : uint8_t +{ + Group11Var1 = 0, + Group11Var2 = 1 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryVariation.h new file mode 100644 index 0000000..9fa84a6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventBinaryVariation.h @@ -0,0 +1,38 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTBINARYVARIATION_H +#define OPENDNP3_EVENTBINARYVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventBinaryVariation : uint8_t +{ + Group2Var1 = 0, + Group2Var2 = 1, + Group2Var3 = 2 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventCounterVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventCounterVariation.h new file mode 100644 index 0000000..613f2d1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventCounterVariation.h @@ -0,0 +1,39 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTCOUNTERVARIATION_H +#define OPENDNP3_EVENTCOUNTERVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventCounterVariation : uint8_t +{ + Group22Var1 = 0, + Group22Var2 = 1, + Group22Var5 = 2, + Group22Var6 = 3 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventDoubleBinaryVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventDoubleBinaryVariation.h new file mode 100644 index 0000000..ffe6a0b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventDoubleBinaryVariation.h @@ -0,0 +1,38 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTDOUBLEBINARYVARIATION_H +#define OPENDNP3_EVENTDOUBLEBINARYVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventDoubleBinaryVariation : uint8_t +{ + Group4Var1 = 0, + Group4Var2 = 1, + Group4Var3 = 2 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventFrozenCounterVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventFrozenCounterVariation.h new file mode 100644 index 0000000..7f29962 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventFrozenCounterVariation.h @@ -0,0 +1,39 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTFROZENCOUNTERVARIATION_H +#define OPENDNP3_EVENTFROZENCOUNTERVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventFrozenCounterVariation : uint8_t +{ + Group23Var1 = 0, + Group23Var2 = 1, + Group23Var5 = 2, + Group23Var6 = 3 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventMode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventMode.h new file mode 100644 index 0000000..abfa4b4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventMode.h @@ -0,0 +1,44 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTMODE_H +#define OPENDNP3_EVENTMODE_H + +#include + +namespace opendnp3 { + +/** + Describes how a transaction behaves with respect to event generation +*/ +enum class EventMode : uint8_t +{ + /// Detect events using the specific mechanism for that type + Detect = 0x0, + /// Force the creation of an event bypassing detection mechanism + Force = 0x1, + /// Never produce an event regardless of changes + Suppress = 0x2 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventSecurityStatVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventSecurityStatVariation.h new file mode 100644 index 0000000..5e8fabd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/EventSecurityStatVariation.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_EVENTSECURITYSTATVARIATION_H +#define OPENDNP3_EVENTSECURITYSTATVARIATION_H + +#include + +namespace opendnp3 { + +enum class EventSecurityStatVariation : uint8_t +{ + Group122Var1 = 0, + Group122Var2 = 1 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlagsType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlagsType.h new file mode 100644 index 0000000..8a132f2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlagsType.h @@ -0,0 +1,48 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_FLAGSTYPE_H +#define OPENDNP3_FLAGSTYPE_H + +#include + +namespace opendnp3 { + +/** + enumerates all types that have flags +*/ +enum class FlagsType : uint8_t +{ + DoubleBinaryInput = 0x1, + Counter = 0x2, + FrozenCounter = 0x3, + AnalogInput = 0x4, + BinaryOutputStatus = 0x5, + AnalogOutputStatus = 0x6, + BinaryInput = 0x0 +}; + +uint8_t FlagsTypeToType(FlagsType arg); +FlagsType FlagsTypeFromType(uint8_t arg); +char const* FlagsTypeToString(FlagsType arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlowControl.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlowControl.h new file mode 100644 index 0000000..e5595fc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FlowControl.h @@ -0,0 +1,44 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_FLOWCONTROL_H +#define OPENDNP3_FLOWCONTROL_H + +#include + +namespace opendnp3 { + +/** + Enumeration for setting serial port flow control +*/ +enum class FlowControl : uint8_t +{ + Hardware = 1, + XONXOFF = 2, + None = 0 +}; + +uint8_t FlowControlToType(FlowControl arg); +FlowControl FlowControlFromType(uint8_t arg); +char const* FlowControlToString(FlowControl arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FrozenCounterQuality.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FrozenCounterQuality.h new file mode 100644 index 0000000..041483e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FrozenCounterQuality.h @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_FROZENCOUNTERQUALITY_H +#define OPENDNP3_FROZENCOUNTERQUALITY_H + +#include + +namespace opendnp3 { + +/** + Quality field bitmask for frozen counter values +*/ +enum class FrozenCounterQuality : uint8_t +{ + /// set when the data is "good", meaning that rest of the system can trust the value + ONLINE = 0x1, + /// the quality all points get before we have established communication (or populated) the point + RESTART = 0x2, + /// set if communication has been lost with the source of the data (after establishing contact) + COMM_LOST = 0x4, + /// set if the value is being forced to a "fake" value somewhere in the system + REMOTE_FORCED = 0x8, + /// set if the value is being forced to a "fake" value on the original device + LOCAL_FORCED = 0x10, + /// Deprecated flag that indicates value has rolled over + ROLLOVER = 0x20, + /// indicates an unusual change in value + DISCONTINUITY = 0x40, + /// reserved bit + RESERVED = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FunctionCode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FunctionCode.h new file mode 100644 index 0000000..8eab187 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/FunctionCode.h @@ -0,0 +1,115 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_FUNCTIONCODE_H +#define OPENDNP3_FUNCTIONCODE_H + +#include + +namespace opendnp3 { + +/** + Application layer function code enumeration +*/ +enum class FunctionCode : uint8_t +{ + /// Master sends this to an outstation to confirm the receipt of an Application Layer fragment + CONFIRM = 0x0, + /// Outstation shall return the data specified by the objects in the request + READ = 0x1, + /// Outstation shall store the data specified by the objects in the request + WRITE = 0x2, + /// Outstation shall select (or arm) the output points specified by the objects in the request in preparation for a subsequent operate command + SELECT = 0x3, + /// Outstation shall activate the output points selected (or armed) by a previous select function code command + OPERATE = 0x4, + /// Outstation shall immediately actuate the output points specified by the objects in the request + DIRECT_OPERATE = 0x5, + /// Same as DIRECT_OPERATE but outstation shall not send a response + DIRECT_OPERATE_NR = 0x6, + /// Outstation shall copy the point data values specified by the objects in the request to a separate freeze buffer + IMMED_FREEZE = 0x7, + /// Same as IMMED_FREEZE but outstation shall not send a response + IMMED_FREEZE_NR = 0x8, + /// Outstation shall copy the point data values specified by the objects in the request into a separate freeze buffer and then clear the values + FREEZE_CLEAR = 0x9, + /// Same as FREEZE_CLEAR but outstation shall not send a response + FREEZE_CLEAR_NR = 0xA, + /// Outstation shall copy the point data values specified by the objects in the request to a separate freeze buffer at the time and/or time intervals specified in a special time data information object + FREEZE_AT_TIME = 0xB, + /// Same as FREEZE_AT_TIME but outstation shall not send a response + FREEZE_AT_TIME_NR = 0xC, + /// Outstation shall perform a complete reset of all hardware and software in the device + COLD_RESTART = 0xD, + /// Outstation shall reset only portions of the device + WARM_RESTART = 0xE, + /// Obsolete-Do not use for new designs + INITIALIZE_DATA = 0xF, + /// Outstation shall place the applications specified by the objects in the request into the ready to run state + INITIALIZE_APPLICATION = 0x10, + /// Outstation shall start running the applications specified by the objects in the request + START_APPLICATION = 0x11, + /// Outstation shall stop running the applications specified by the objects in the request + STOP_APPLICATION = 0x12, + /// This code is deprecated-Do not use for new designs + SAVE_CONFIGURATION = 0x13, + /// Enables outstation to initiate unsolicited responses from points specified by the objects in the request + ENABLE_UNSOLICITED = 0x14, + /// Prevents outstation from initiating unsolicited responses from points specified by the objects in the request + DISABLE_UNSOLICITED = 0x15, + /// Outstation shall assign the events generated by the points specified by the objects in the request to one of the classes + ASSIGN_CLASS = 0x16, + /// Outstation shall report the time it takes to process and initiate the transmission of its response + DELAY_MEASURE = 0x17, + /// Outstation shall save the time when the last octet of this message is received + RECORD_CURRENT_TIME = 0x18, + /// Outstation shall open a file + OPEN_FILE = 0x19, + /// Outstation shall close a file + CLOSE_FILE = 0x1A, + /// Outstation shall delete a file + DELETE_FILE = 0x1B, + /// Outstation shall retrieve information about a file + GET_FILE_INFO = 0x1C, + /// Outstation shall return a file authentication key + AUTHENTICATE_FILE = 0x1D, + /// Outstation shall abort a file transfer operation + ABORT_FILE = 0x1E, + /// The master uses this function code when sending authentication requests to the outstation + AUTH_REQUEST = 0x20, + /// The master uses this function code when sending authentication requests to the outstation that do no require acknowledgement + AUTH_REQUEST_NO_ACK = 0x21, + /// Master shall interpret this fragment as an Application Layer response to an ApplicationLayer request + RESPONSE = 0x81, + /// Master shall interpret this fragment as an unsolicited response that was not prompted by an explicit request + UNSOLICITED_RESPONSE = 0x82, + /// The outstation uses this function code to issue authentication messages to the master + AUTH_RESPONSE = 0x83, + /// Unknown function code. Used internally in opendnp3 to indicate the code didn't match anything known + UNKNOWN = 0xFF +}; + +uint8_t FunctionCodeToType(FunctionCode arg); +FunctionCode FunctionCodeFromType(uint8_t arg); +char const* FunctionCodeToString(FunctionCode arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/GroupVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/GroupVariation.h new file mode 100644 index 0000000..0e62812 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/GroupVariation.h @@ -0,0 +1,174 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUPVARIATION_H +#define OPENDNP3_GROUPVARIATION_H + +#include + +namespace opendnp3 { + +/** + Comprehensive list of supported groups and variations +*/ +enum class GroupVariation : uint16_t +{ + Group1Var0 = 0x100, + Group1Var1 = 0x101, + Group1Var2 = 0x102, + Group2Var0 = 0x200, + Group2Var1 = 0x201, + Group2Var2 = 0x202, + Group2Var3 = 0x203, + Group3Var0 = 0x300, + Group3Var1 = 0x301, + Group3Var2 = 0x302, + Group4Var0 = 0x400, + Group4Var1 = 0x401, + Group4Var2 = 0x402, + Group4Var3 = 0x403, + Group10Var0 = 0xA00, + Group10Var1 = 0xA01, + Group10Var2 = 0xA02, + Group11Var0 = 0xB00, + Group11Var1 = 0xB01, + Group11Var2 = 0xB02, + Group12Var0 = 0xC00, + Group12Var1 = 0xC01, + Group13Var1 = 0xD01, + Group13Var2 = 0xD02, + Group20Var0 = 0x1400, + Group20Var1 = 0x1401, + Group20Var2 = 0x1402, + Group20Var5 = 0x1405, + Group20Var6 = 0x1406, + Group21Var0 = 0x1500, + Group21Var1 = 0x1501, + Group21Var2 = 0x1502, + Group21Var5 = 0x1505, + Group21Var6 = 0x1506, + Group21Var9 = 0x1509, + Group21Var10 = 0x150A, + Group22Var0 = 0x1600, + Group22Var1 = 0x1601, + Group22Var2 = 0x1602, + Group22Var5 = 0x1605, + Group22Var6 = 0x1606, + Group23Var0 = 0x1700, + Group23Var1 = 0x1701, + Group23Var2 = 0x1702, + Group23Var5 = 0x1705, + Group23Var6 = 0x1706, + Group30Var0 = 0x1E00, + Group30Var1 = 0x1E01, + Group30Var2 = 0x1E02, + Group30Var3 = 0x1E03, + Group30Var4 = 0x1E04, + Group30Var5 = 0x1E05, + Group30Var6 = 0x1E06, + Group32Var0 = 0x2000, + Group32Var1 = 0x2001, + Group32Var2 = 0x2002, + Group32Var3 = 0x2003, + Group32Var4 = 0x2004, + Group32Var5 = 0x2005, + Group32Var6 = 0x2006, + Group32Var7 = 0x2007, + Group32Var8 = 0x2008, + Group40Var0 = 0x2800, + Group40Var1 = 0x2801, + Group40Var2 = 0x2802, + Group40Var3 = 0x2803, + Group40Var4 = 0x2804, + Group41Var0 = 0x2900, + Group41Var1 = 0x2901, + Group41Var2 = 0x2902, + Group41Var3 = 0x2903, + Group41Var4 = 0x2904, + Group42Var0 = 0x2A00, + Group42Var1 = 0x2A01, + Group42Var2 = 0x2A02, + Group42Var3 = 0x2A03, + Group42Var4 = 0x2A04, + Group42Var5 = 0x2A05, + Group42Var6 = 0x2A06, + Group42Var7 = 0x2A07, + Group42Var8 = 0x2A08, + Group43Var1 = 0x2B01, + Group43Var2 = 0x2B02, + Group43Var3 = 0x2B03, + Group43Var4 = 0x2B04, + Group43Var5 = 0x2B05, + Group43Var6 = 0x2B06, + Group43Var7 = 0x2B07, + Group43Var8 = 0x2B08, + Group50Var1 = 0x3201, + Group50Var4 = 0x3204, + Group51Var1 = 0x3301, + Group51Var2 = 0x3302, + Group52Var1 = 0x3401, + Group52Var2 = 0x3402, + Group60Var1 = 0x3C01, + Group60Var2 = 0x3C02, + Group60Var3 = 0x3C03, + Group60Var4 = 0x3C04, + Group70Var1 = 0x4601, + Group70Var2 = 0x4602, + Group70Var3 = 0x4603, + Group70Var4 = 0x4604, + Group70Var5 = 0x4605, + Group70Var6 = 0x4606, + Group70Var7 = 0x4607, + Group70Var8 = 0x4608, + Group80Var1 = 0x5001, + Group110Var0 = 0x6E00, + Group111Var0 = 0x6F00, + Group112Var0 = 0x7000, + Group113Var0 = 0x7100, + Group120Var1 = 0x7801, + Group120Var2 = 0x7802, + Group120Var3 = 0x7803, + Group120Var4 = 0x7804, + Group120Var5 = 0x7805, + Group120Var6 = 0x7806, + Group120Var7 = 0x7807, + Group120Var8 = 0x7808, + Group120Var9 = 0x7809, + Group120Var10 = 0x780A, + Group120Var11 = 0x780B, + Group120Var12 = 0x780C, + Group120Var13 = 0x780D, + Group120Var14 = 0x780E, + Group120Var15 = 0x780F, + Group121Var0 = 0x7900, + Group121Var1 = 0x7901, + Group122Var0 = 0x7A00, + Group122Var1 = 0x7A01, + Group122Var2 = 0x7A02, + UNKNOWN = 0xFFFF +}; + +uint16_t GroupVariationToType(GroupVariation arg); +GroupVariation GroupVariationFromType(uint16_t arg); +char const* GroupVariationToString(GroupVariation arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/HMACType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/HMACType.h new file mode 100644 index 0000000..e98acfb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/HMACType.h @@ -0,0 +1,55 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_HMACTYPE_H +#define OPENDNP3_HMACTYPE_H + +#include + +namespace opendnp3 { + +/** + Enumerates possible algorithms used to calculate the HMAC +*/ +enum class HMACType : uint8_t +{ + /// No HMAC value in this message + NO_MAC_VALUE = 0x0, + /// Networked version of SHA1 + HMAC_SHA1_TRUNC_10 = 0x2, + /// Serial version of SHA256 + HMAC_SHA256_TRUNC_8 = 0x3, + /// Networked version of SHA256 + HMAC_SHA256_TRUNC_16 = 0x4, + /// Serial version of SHA1 + HMAC_SHA1_TRUNC_8 = 0x5, + /// 12 octet output for serial or network + AES_GMAC = 0x6, + /// Unknown HMAC algorithm + UNKNOWN = 0xFF +}; + +uint8_t HMACTypeToType(HMACType arg); +HMACType HMACTypeFromType(uint8_t arg); +char const* HMACTypeToString(HMACType arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/IndexMode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/IndexMode.h new file mode 100644 index 0000000..75d3cb0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/IndexMode.h @@ -0,0 +1,42 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_INDEXMODE_H +#define OPENDNP3_INDEXMODE_H + +#include + +namespace opendnp3 { + +/** + Select contiguous or dis-contiguous index mode +*/ +enum class IndexMode : uint8_t +{ + /// Indices are contiguous. Most efficient as direct indexing is used. + Contiguous = 0x0, + /// Indices are dis-contiguous. Resorts to binary search to find raw index. + Discontiguous = 0x1 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/IntervalUnits.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/IntervalUnits.h new file mode 100644 index 0000000..004c65b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/IntervalUnits.h @@ -0,0 +1,65 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_INTERVALUNITS_H +#define OPENDNP3_INTERVALUNITS_H + +#include + +namespace opendnp3 { + +/** + Time internal units +*/ +enum class IntervalUnits : uint8_t +{ + /// The outstation does not repeat the action regardless of the value in the interval count + NoRepeat = 0x0, + /// the interval is always counted relative to the start time and is constant regardless of the clock time set at the outstation + Milliseconds = 0x1, + /// At the same millisecond within the second that is specified in the start time + Seconds = 0x2, + /// At the same second and millisecond within the minute that is specified in the start time + Minutes = 0x3, + /// At the same minute, second and millisecond within the hour that is specified in the start time + Hours = 0x4, + /// At the same time of day that is specified in the start time + Days = 0x5, + /// On the same day of the week at the same time of day that is specified in the start time + Weeks = 0x6, + /// On the same day of each month at the same time of day that is specified in the start time + Months7 = 0x7, + /// At the same time of day on the same day of the week after the beginning of the month as the day specified in the start time + Months8 = 0x8, + /// Months on Same Day of Week from End of Month - The outstation shall interpret this setting as in Months8, but the day of the week shall be measured from the end of the month, + Months9 = 0x9, + /// The definition of a season is specific to the outstation + Seasons = 0xA, + /// 11-127 are reserved for future use + Undefined = 0x7F +}; + +uint8_t IntervalUnitsToType(IntervalUnits arg); +IntervalUnits IntervalUnitsFromType(uint8_t arg); +char const* IntervalUnitsToString(IntervalUnits arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyChangeMethod.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyChangeMethod.h new file mode 100644 index 0000000..0a8d979 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyChangeMethod.h @@ -0,0 +1,50 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_KEYCHANGEMETHOD_H +#define OPENDNP3_KEYCHANGEMETHOD_H + +#include + +namespace opendnp3 { + +/** + Enumerates possible algorithms for changing the update key +*/ +enum class KeyChangeMethod : uint8_t +{ + AES_128_SHA1_HMAC = 0x3, + AES_256_SHA256_HMAC = 0x4, + AES_256_AES_GMAC = 0x5, + RSA_1024_DSA_SHA1_HMAC_SHA1 = 0x43, + RSA_2048_DSA_SHA256_HMAC_SHA256 = 0x44, + RSA_3072_DSA_SHA256_HMAC_SHA256 = 0x45, + RSA_2048_DSA_SHA256_AES_GMAC = 0x46, + RSA_3072_DSA_SHA256_AES_GMAC = 0x47, + UNDEFINED = 0x0 +}; + +uint8_t KeyChangeMethodToType(KeyChangeMethod arg); +KeyChangeMethod KeyChangeMethodFromType(uint8_t arg); +char const* KeyChangeMethodToString(KeyChangeMethod arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyStatus.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyStatus.h new file mode 100644 index 0000000..cda7caf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyStatus.h @@ -0,0 +1,50 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_KEYSTATUS_H +#define OPENDNP3_KEYSTATUS_H + +#include + +namespace opendnp3 { + +/** + Describes the status of the two session keys as known by the outstation +*/ +enum class KeyStatus : uint8_t +{ + /// Session keys are valid + OK = 0x1, + /// Sessions keys are not valid due to no init or interval expiration + NOT_INIT = 0x2, + /// Session keys are not valid due to communications failure + COMM_FAIL = 0x3, + /// Session keys are not valid due to an authentication failure + AUTH_FAIL = 0x4, + UNDEFINED = 0x0 +}; + +uint8_t KeyStatusToType(KeyStatus arg); +KeyStatus KeyStatusFromType(uint8_t arg); +char const* KeyStatusToString(KeyStatus arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyWrapAlgorithm.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyWrapAlgorithm.h new file mode 100644 index 0000000..e089d0a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/KeyWrapAlgorithm.h @@ -0,0 +1,46 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_KEYWRAPALGORITHM_H +#define OPENDNP3_KEYWRAPALGORITHM_H + +#include + +namespace opendnp3 { + +/** + Enumerates possible key-wrap algorithms +*/ +enum class KeyWrapAlgorithm : uint8_t +{ + /// AES 128 Key Wrap Algorithm + AES_128 = 0x1, + /// AES 256 Key Wrap Algorithm + AES_256 = 0x2, + UNDEFINED = 0x0 +}; + +uint8_t KeyWrapAlgorithmToType(KeyWrapAlgorithm arg); +KeyWrapAlgorithm KeyWrapAlgorithmFromType(uint8_t arg); +char const* KeyWrapAlgorithmToString(KeyWrapAlgorithm arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkFunction.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkFunction.h new file mode 100644 index 0000000..4ca8d54 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkFunction.h @@ -0,0 +1,51 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_LINKFUNCTION_H +#define OPENDNP3_LINKFUNCTION_H + +#include + +namespace opendnp3 { + +/** + Link layer function code enumeration +*/ +enum class LinkFunction : uint8_t +{ + PRI_RESET_LINK_STATES = 0x40, + PRI_TEST_LINK_STATES = 0x42, + PRI_CONFIRMED_USER_DATA = 0x43, + PRI_UNCONFIRMED_USER_DATA = 0x44, + PRI_REQUEST_LINK_STATUS = 0x49, + SEC_ACK = 0x0, + SEC_NACK = 0x1, + SEC_LINK_STATUS = 0xB, + SEC_NOT_SUPPORTED = 0xF, + INVALID = 0xFF +}; + +uint8_t LinkFunctionToType(LinkFunction arg); +LinkFunction LinkFunctionFromType(uint8_t arg); +char const* LinkFunctionToString(LinkFunction arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkStatus.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkStatus.h new file mode 100644 index 0000000..1bb43c5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/LinkStatus.h @@ -0,0 +1,43 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_LINKSTATUS_H +#define OPENDNP3_LINKSTATUS_H + +#include + +namespace opendnp3 { + +/** + Enumeration for reset/unreset states of a link layer +*/ +enum class LinkStatus : uint8_t +{ + /// DOWN + UNRESET = 0, + /// UP + RESET = 1 +}; + +char const* LinkStatusToString(LinkStatus arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/MasterTaskType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/MasterTaskType.h new file mode 100644 index 0000000..529b77d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/MasterTaskType.h @@ -0,0 +1,48 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_MASTERTASKTYPE_H +#define OPENDNP3_MASTERTASKTYPE_H + +#include + +namespace opendnp3 { + +/** + Enumeration of internal tasks +*/ +enum class MasterTaskType : uint8_t +{ + CLEAR_RESTART = 0, + DISABLE_UNSOLICITED = 1, + ASSIGN_CLASS = 2, + STARTUP_INTEGRITY_POLL = 3, + SERIAL_TIME_SYNC = 4, + ENABLE_UNSOLICITED = 5, + AUTO_EVENT_SCAN = 6, + USER_TASK = 7, + SET_SESSION_KEYS = 8 +}; + +char const* MasterTaskTypeToString(MasterTaskType arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/OperateType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/OperateType.h new file mode 100644 index 0000000..980a538 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/OperateType.h @@ -0,0 +1,44 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_OPERATETYPE_H +#define OPENDNP3_OPERATETYPE_H + +#include + +namespace opendnp3 { + +/** + Various ways that an outstation can receive a request to operate a BO or AO point +*/ +enum class OperateType : uint8_t +{ + /// The outstation received a valid prior SELECT followed by OPERATE + SelectBeforeOperate = 0x0, + /// The outstation received a direct operate request + DirectOperate = 0x1, + /// The outstation received a direct operate no ack request + DirectOperateNoAck = 0x2 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/Parity.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/Parity.h new file mode 100644 index 0000000..6fb9d78 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/Parity.h @@ -0,0 +1,44 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_PARITY_H +#define OPENDNP3_PARITY_H + +#include + +namespace opendnp3 { + +/** + Enumeration for setting serial port parity +*/ +enum class Parity : uint8_t +{ + Even = 1, + Odd = 2, + None = 0 +}; + +uint8_t ParityToType(Parity arg); +Parity ParityFromType(uint8_t arg); +char const* ParityToString(Parity arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/PointClass.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/PointClass.h new file mode 100644 index 0000000..7086110 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/PointClass.h @@ -0,0 +1,46 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_POINTCLASS_H +#define OPENDNP3_POINTCLASS_H + +#include + +namespace opendnp3 { + +/** + Class assignment for a measurement point +*/ +enum class PointClass : uint8_t +{ + /// No event class assignment + Class0 = 0x1, + /// Assigned to event class 1 + Class1 = 0x2, + /// Assigned to event class 2 + Class2 = 0x4, + /// Assigned to event class 3 + Class3 = 0x8 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/QualifierCode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/QualifierCode.h new file mode 100644 index 0000000..279bd9d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/QualifierCode.h @@ -0,0 +1,50 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_QUALIFIERCODE_H +#define OPENDNP3_QUALIFIERCODE_H + +#include + +namespace opendnp3 { + +/** + Object header range/prefix as a single enumeration +*/ +enum class QualifierCode : uint8_t +{ + UINT8_START_STOP = 0x0, + UINT16_START_STOP = 0x1, + ALL_OBJECTS = 0x6, + UINT8_CNT = 0x7, + UINT16_CNT = 0x8, + UINT8_CNT_UINT8_INDEX = 0x17, + UINT16_CNT_UINT16_INDEX = 0x28, + UINT16_FREE_FORMAT = 0x5B, + UNDEFINED = 0xFF +}; + +uint8_t QualifierCodeToType(QualifierCode arg); +QualifierCode QualifierCodeFromType(uint8_t arg); +char const* QualifierCodeToString(QualifierCode arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartMode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartMode.h new file mode 100644 index 0000000..89167bb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartMode.h @@ -0,0 +1,44 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_RESTARTMODE_H +#define OPENDNP3_RESTARTMODE_H + +#include + +namespace opendnp3 { + +/** + Enumeration describing restart mode support of an outstation +*/ +enum class RestartMode : uint8_t +{ + /// Device does not support restart + UNSUPPORTED = 0, + /// Supports restart, and time returned is a fine time delay + SUPPORTED_DELAY_FINE = 1, + /// Supports restart, and time returned is a coarse time delay + SUPPORTED_DELAY_COARSE = 2 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartType.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartType.h new file mode 100644 index 0000000..fd88a58 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/RestartType.h @@ -0,0 +1,42 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_RESTARTTYPE_H +#define OPENDNP3_RESTARTTYPE_H + +#include + +namespace opendnp3 { + +/** + Enumeration describing restart operation to perform on an outstation +*/ +enum class RestartType : uint8_t +{ + /// Full reboot + COLD = 0, + /// Warm reboot of process only + WARM = 1 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/SecurityStatIndex.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/SecurityStatIndex.h new file mode 100644 index 0000000..9c0507e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/SecurityStatIndex.h @@ -0,0 +1,74 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_SECURITYSTATINDEX_H +#define OPENDNP3_SECURITYSTATINDEX_H + +#include + +namespace opendnp3 { + +/** + Indices of the SA security statistics +*/ +enum class SecurityStatIndex : uint8_t +{ + /// The other device has responded with a message that was not the expected next step in the state machine. + UNEXPECTED_MESSAGES = 0, + /// The other device has replied with the correct authentication information, so the user is authentic, but the user is not authorized to perform the requested operation. + AUTHORIZATION_FAILURES = 1, + /// The other device has provided invalid authentication information such as an incorrect MAC + AUTHENTICATION_FAILURES = 2, + /// The other device has not replied within the configured time required + REPLY_TIMEOUTS = 3, + /// An Authentication Failure has occurred that causes the master station to change the session keys + REKEYS_DUE_TO_AUTH_FAILUE = 4, + /// The device sends an Application Layer fragment + TOTAL_MESSAGES_TX = 5, + /// The device receives an Application Layer fragment + TOTAL_MESSAGES_RX = 6, + /// The device receives a Challenge message or transmits an Aggressive Mode Request message + CRITICAL_MESSAGES_TX = 7, + /// The device transmits a Challenge message or receives an Aggressive Mode Request message + CRITICAL_MESSAGES_RX = 8, + /// The device discards a received message + DISCARED_MESSAGES = 9, + /// The device has sent a fragment containing an Error object indicating an authentication failure or potential configuration error + ERROR_MESSAGES_TX = 10, + /// The device has received an Error object + ERROR_MESSAGES_RX = 11, + /// The device successfully authenticates a message + SUCCESSFUL_AUTHS = 12, + /// A users session key is successfully changed + SESSION_KEY_CHANGES = 13, + /// A failure occurs while changing a session key + FAILED_SESSION_KEY_CHANGES = 14, + /// The master and authority change the Update Key for a user + UPDATE_KEY_CHANGES = 15, + /// The master and authority fail to change the Update Key for a user + FAILED_UPDATE_KEY_CHANGES = 16, + /// Only used by a master. Set to zero in outstations. The master rekeyed the session keys because the outstation restarted + REKEYS_DUE_TO_RESTART = 17 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogOutputStatusVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogOutputStatusVariation.h new file mode 100644 index 0000000..eec70b2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogOutputStatusVariation.h @@ -0,0 +1,39 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICANALOGOUTPUTSTATUSVARIATION_H +#define OPENDNP3_STATICANALOGOUTPUTSTATUSVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticAnalogOutputStatusVariation : uint8_t +{ + Group40Var1 = 0, + Group40Var2 = 1, + Group40Var3 = 2, + Group40Var4 = 3 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogVariation.h new file mode 100644 index 0000000..bc92902 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticAnalogVariation.h @@ -0,0 +1,41 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICANALOGVARIATION_H +#define OPENDNP3_STATICANALOGVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticAnalogVariation : uint8_t +{ + Group30Var1 = 0, + Group30Var2 = 1, + Group30Var3 = 2, + Group30Var4 = 3, + Group30Var5 = 4, + Group30Var6 = 5 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryOutputStatusVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryOutputStatusVariation.h new file mode 100644 index 0000000..c6b0c54 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryOutputStatusVariation.h @@ -0,0 +1,36 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICBINARYOUTPUTSTATUSVARIATION_H +#define OPENDNP3_STATICBINARYOUTPUTSTATUSVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticBinaryOutputStatusVariation : uint8_t +{ + Group10Var2 = 0 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryVariation.h new file mode 100644 index 0000000..93301f5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticBinaryVariation.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICBINARYVARIATION_H +#define OPENDNP3_STATICBINARYVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticBinaryVariation : uint8_t +{ + Group1Var1 = 0, + Group1Var2 = 1 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticCounterVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticCounterVariation.h new file mode 100644 index 0000000..47a1635 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticCounterVariation.h @@ -0,0 +1,39 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICCOUNTERVARIATION_H +#define OPENDNP3_STATICCOUNTERVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticCounterVariation : uint8_t +{ + Group20Var1 = 0, + Group20Var2 = 1, + Group20Var5 = 2, + Group20Var6 = 3 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticDoubleBinaryVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticDoubleBinaryVariation.h new file mode 100644 index 0000000..1129f3a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticDoubleBinaryVariation.h @@ -0,0 +1,36 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICDOUBLEBINARYVARIATION_H +#define OPENDNP3_STATICDOUBLEBINARYVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticDoubleBinaryVariation : uint8_t +{ + Group3Var2 = 0 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticFrozenCounterVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticFrozenCounterVariation.h new file mode 100644 index 0000000..90c95dd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticFrozenCounterVariation.h @@ -0,0 +1,41 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICFROZENCOUNTERVARIATION_H +#define OPENDNP3_STATICFROZENCOUNTERVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticFrozenCounterVariation : uint8_t +{ + Group21Var1 = 0, + Group21Var2 = 1, + Group21Var5 = 2, + Group21Var6 = 3, + Group21Var9 = 4, + Group21Var10 = 5 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticSecurityStatVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticSecurityStatVariation.h new file mode 100644 index 0000000..b97d5d4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticSecurityStatVariation.h @@ -0,0 +1,36 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICSECURITYSTATVARIATION_H +#define OPENDNP3_STATICSECURITYSTATVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticSecurityStatVariation : uint8_t +{ + Group121Var1 = 0 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTimeAndIntervalVariation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTimeAndIntervalVariation.h new file mode 100644 index 0000000..95fc707 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTimeAndIntervalVariation.h @@ -0,0 +1,36 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICTIMEANDINTERVALVARIATION_H +#define OPENDNP3_STATICTIMEANDINTERVALVARIATION_H + +#include + +namespace opendnp3 { + +enum class StaticTimeAndIntervalVariation : uint8_t +{ + Group50Var4 = 0 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTypeBitmask.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTypeBitmask.h new file mode 100644 index 0000000..493f781 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StaticTypeBitmask.h @@ -0,0 +1,46 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STATICTYPEBITMASK_H +#define OPENDNP3_STATICTYPEBITMASK_H + +#include + +namespace opendnp3 { + +/** + Bitmask values for all the static types +*/ +enum class StaticTypeBitmask : uint16_t +{ + BinaryInput = 0x1, + DoubleBinaryInput = 0x2, + Counter = 0x4, + FrozenCounter = 0x8, + AnalogInput = 0x10, + BinaryOutputStatus = 0x20, + AnalogOutputStatus = 0x40, + TimeAndInterval = 0x80 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StopBits.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StopBits.h new file mode 100644 index 0000000..2c05f53 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/StopBits.h @@ -0,0 +1,45 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_STOPBITS_H +#define OPENDNP3_STOPBITS_H + +#include + +namespace opendnp3 { + +/** + Enumeration for setting serial port stop bits +*/ +enum class StopBits : uint8_t +{ + One = 1, + OnePointFive = 2, + Two = 3, + None = 0 +}; + +uint8_t StopBitsToType(StopBits arg); +StopBits StopBitsFromType(uint8_t arg); +char const* StopBitsToString(StopBits arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TaskCompletion.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TaskCompletion.h new file mode 100644 index 0000000..31d85cd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TaskCompletion.h @@ -0,0 +1,57 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_TASKCOMPLETION_H +#define OPENDNP3_TASKCOMPLETION_H + +#include + +namespace opendnp3 { + +/** + Enum that describes if a master task succeeded or failed +*/ +enum class TaskCompletion : uint8_t +{ + /// A valid response was received from the outstation + SUCCESS = 0, + /// A response was received from the outstation, but it was not valid + FAILURE_BAD_RESPONSE = 1, + /// The task request did not receive a response within the timeout + FAILURE_RESPONSE_TIMEOUT = 2, + /// The start timeout expired before the task could begin running + FAILURE_START_TIMEOUT = 3, + /// The task could not run because the specified user was not defined on the master (SA only) + FAILURE_NO_USER = 4, + /// The task failed because of some unexpected internal issue like bad configuration data + FAILURE_INTERNAL_ERROR = 5, + /// The outstation rejected the operation do to a lack of valid session keys or the user not existing on the outstation (SA only) + FAILURE_BAD_AUTHENTICATION = 6, + /// The outstation rejected the operation because the specified user is not authorized for the request that was made (SA only) + FAILURE_NOT_AUTHORIZED = 7, + /// There is no communication with the outstation, so the task was not attempted + FAILURE_NO_COMMS = 255 +}; + +char const* TaskCompletionToString(TaskCompletion arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimeSyncMode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimeSyncMode.h new file mode 100644 index 0000000..b6b7436 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimeSyncMode.h @@ -0,0 +1,42 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_TIMESYNCMODE_H +#define OPENDNP3_TIMESYNCMODE_H + +#include + +namespace opendnp3 { + +/** + Determines what the master station does when it sees the NEED_TIME iin bit +*/ +enum class TimeSyncMode : uint8_t +{ + /// synchronize the outstation's time using the serial time sync procedure + SerialTimeSync = 1, + /// don't perform a time-sync + None = 0 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimestampMode.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimestampMode.h new file mode 100644 index 0000000..b59f667 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/TimestampMode.h @@ -0,0 +1,44 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_TIMESTAMPMODE_H +#define OPENDNP3_TIMESTAMPMODE_H + +#include + +namespace opendnp3 { + +/** + Indicates the validity of timestamp values for an entire object header +*/ +enum class TimestampMode : uint8_t +{ + /// The timestamp is UTC synchronized at the remote device + SYNCHRONIZED = 1, + /// The device indicate the timestamp may be unsynchronized + UNSYNCHRONIZED = 2, + /// Timestamp is not valid, ignore the value and use a local timestamp + INVALID = 0 +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserOperation.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserOperation.h new file mode 100644 index 0000000..a3cc7de --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserOperation.h @@ -0,0 +1,45 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_USEROPERATION_H +#define OPENDNP3_USEROPERATION_H + +#include + +namespace opendnp3 { + +/** + Enumerates possible remote operations on users +*/ +enum class UserOperation : uint8_t +{ + OP_ADD = 0x1, + OP_DELETE = 0x2, + OP_CHANGE = 0x3, + OP_UNDEFINED = 0xFF +}; + +uint8_t UserOperationToType(UserOperation arg); +UserOperation UserOperationFromType(uint8_t arg); +char const* UserOperationToString(UserOperation arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserRole.h b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserRole.h new file mode 100644 index 0000000..79df149 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/gen/UserRole.h @@ -0,0 +1,50 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_USERROLE_H +#define OPENDNP3_USERROLE_H + +#include + +namespace opendnp3 { + +/** + Enumerates pre-defined rules in secure authentication +*/ +enum class UserRole : uint16_t +{ + VIEWER = 0, + OPERATOR = 1, + ENGINEER = 2, + INSTALLER = 3, + SECADM = 4, + SECAUD = 5, + RBACMNT = 6, + SINGLE_USER = 32768, + UNDEFINED = 32767 +}; + +uint16_t UserRoleToType(UserRole arg); +UserRole UserRoleFromType(uint16_t arg); +char const* UserRoleToString(UserRole arg); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/link/ILinkListener.h b/utils/dnp3_src/cpp/libs/include/opendnp3/link/ILinkListener.h new file mode 100644 index 0000000..1d4cbfe --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/link/ILinkListener.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_ILINK_LISTENER_H +#define OPENDNP3_ILINK_LISTENER_H + +#include + +namespace opendnp3 +{ + +/** +* Various optional callbacks that can be received for the link layer +*/ +class ILinkListener +{ +public: + + /// Called when a the reset/unreset status of the link layer changes + virtual void OnStateChange(LinkStatus value) {} + + /// Called when the keep alive timer elapses. This doesn't denote a keep-alive failure, it's just a notification + virtual void OnKeepAliveInitiated() {} + + /// Called when a keep alive message (request link status) receives no response + virtual void OnKeepAliveFailure() {} + + /// Called when a keep alive message receives a valid response + virtual void OnKeepAliveSuccess() {} +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkConfig.h b/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkConfig.h new file mode 100644 index 0000000..f225dc2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkConfig.h @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKCONFIG_H +#define OPENDNP3_LINKCONFIG_H + +#include + +namespace opendnp3 +{ + +/** + Configuration for the dnp3 link layer +*/ +struct LinkConfig +{ + LinkConfig( + bool isMaster, + bool useConfirms, + uint32_t numRetry, + uint16_t localAddr, + uint16_t remoteAddr, + openpal::TimeDuration timeout, + openpal::TimeDuration keepAliveTimeout) : + + IsMaster(isMaster), + UseConfirms(useConfirms), + NumRetry(numRetry), + LocalAddr(localAddr), + RemoteAddr(remoteAddr), + Timeout(timeout), + KeepAliveTimeout(keepAliveTimeout) + {} + + LinkConfig( + bool isMaster, + bool useConfirms) : + + IsMaster(isMaster), + UseConfirms(useConfirms), + NumRetry(0), + LocalAddr(isMaster ? 1 : 1024), + RemoteAddr(isMaster ? 1024 : 1), + Timeout(openpal::TimeDuration::Seconds(1)), + KeepAliveTimeout(openpal::TimeDuration::Minutes(1)) + {} + + /// The master/outstation bit set on all messages + bool IsMaster; + + /// If true, the link layer will send data requesting confirmation + bool UseConfirms; + + /// The number of retry attempts the link will attempt after the initial try + uint32_t NumRetry; + + /// dnp3 address of the local device + uint16_t LocalAddr; + + /// dnp3 address of the remote device + uint16_t RemoteAddr; + + /// the response timeout in milliseconds for confirmed requests + openpal::TimeDuration Timeout; + + /// the interval for keep-alive messages (link status requests) + openpal::TimeDuration KeepAliveTimeout; + +private: + + LinkConfig() {} +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkHeaderFields.h b/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkHeaderFields.h new file mode 100644 index 0000000..bc6ee25 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkHeaderFields.h @@ -0,0 +1,46 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINK_HEADER_FIELDS_H +#define OPENDNP3_LINK_HEADER_FIELDS_H + +#include "opendnp3/gen/LinkFunction.h" + +namespace opendnp3 +{ + +struct LinkHeaderFields +{ + LinkHeaderFields(); + + LinkHeaderFields(LinkFunction func, bool isMaster, bool fcb, bool fcvdfc, uint16_t dest, uint16_t source); + + LinkFunction func; + bool isFromMaster; + bool fcb; + bool fcvdfc; + uint16_t dest; + uint16_t src; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkStatistics.h b/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkStatistics.h new file mode 100644 index 0000000..e6c3ff8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/link/LinkStatistics.h @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKSTATISTICS_H +#define OPENDNP3_LINKSTATISTICS_H + +#include + +namespace opendnp3 +{ + +/** +* Counters for the channel and the DNP3 link layer +*/ +struct LinkStatistics +{ + struct Parser + { + /// Number of frames discarded due to header CRC errors + uint32_t numHeaderCrcError = 0; + + /// Number of frames discarded due to body CRC errors + uint32_t numBodyCrcError = 0; + + /// Number of frames received + uint32_t numLinkFrameRx = 0; + + /// number of bad LEN fields received (malformed frame) + uint32_t numBadLength = 0; + + /// number of bad function codes (malformed frame) + uint32_t numBadFunctionCode = 0; + + /// number of FCV / function code mismatches (malformed frame) + uint32_t numBadFCV = 0; + + /// number of frames w/ unexpected FCB bit set (malformed frame) + uint32_t numBadFCB = 0; + }; + + struct Channel + { + /// The number of times the channel has successfully opened + uint32_t numOpen = 0; + + /// The number of times the channel has failed to open + uint32_t numOpenFail = 0; + + /// The number of times the channel has closed either due to user intervention or an error + uint32_t numClose = 0; + + /// The number of bytes received + uint32_t numBytesRx = 0; + + /// The number of bytes transmitted + uint32_t numBytesTx = 0; + + /// Number of frames transmitted + uint32_t numLinkFrameTx = 0; + }; + + LinkStatistics() = default; + + LinkStatistics(const Channel& channel, const Parser& parser) : channel(channel), parser(parser) + {} + + /// statistics for the communicaiton channel + Channel channel; + + /// statistics for the link parser + Parser parser; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandCallbackT.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandCallbackT.h new file mode 100644 index 0000000..bc4264c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandCallbackT.h @@ -0,0 +1,35 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COMMAND_CALLBACK_T_H +#define OPENDNP3_COMMAND_CALLBACK_T_H + +#include "ICommandTaskResult.h" + +#include + +namespace opendnp3 +{ + +typedef std::function CommandCallbackT; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandPointResult.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandPointResult.h new file mode 100644 index 0000000..636249a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandPointResult.h @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_COMMAND_POINT_RESULT_H +#define OPENDNP3_COMMAND_POINT_RESULT_H + +#include "opendnp3/gen/CommandStatus.h" +#include "opendnp3/gen/CommandPointState.h" + +namespace opendnp3 +{ + +/// Represents the result of a command operation on a particular point +class CommandPointResult +{ + +public: + + /// Fully construct based on all members + CommandPointResult(uint32_t headerIndex_, uint16_t index_, CommandPointState state_, CommandStatus status_) : + headerIndex(headerIndex_), + index(index_), + state(state_), + status(status_) + {} + + /// Check the result for equality against another value + bool Equals(const CommandPointResult& other) const + { + return (headerIndex == other.headerIndex) && + (index == other.index) && + (state == other.state) && + (status == other.status); + } + + /// The index of the header when request was made (0-based) + uint32_t headerIndex; + + /// The index of the command that was requested + uint16_t index; + + /// The final state of the command operation on this point + CommandPointState state; + + /// The response value. This is only valid if state == SUCCESS or state == SELECT_FAIL + CommandStatus status; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandSet.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandSet.h new file mode 100644 index 0000000..d7c0554 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/CommandSet.h @@ -0,0 +1,156 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COMMAND_SET_H +#define OPENDNP3_COMMAND_SET_H + +#include "opendnp3/master/ICommandCollection.h" + +#include "opendnp3/app/ControlRelayOutputBlock.h" +#include "opendnp3/app/AnalogOutput.h" +#include "opendnp3/app/Indexed.h" + +#include +#include + +namespace opendnp3 +{ + +class ICommandHeader; + +/** +* Provides a mechanism for building a set of one or more command headers +*/ +class CommandSet final +{ + // friend class used to hide some implementation details while keeping the headers private + friend class CommandSetOps; + +public: + + typedef std::vector HeaderVector; + + /// Contrsuct an empty command set + CommandSet() {} + + /// Construct a new command set and take ownership of the headers in argument + CommandSet(CommandSet&& other); + + /// Destruct the command set and free any referenced headers + ~CommandSet(); + + /// Construct a command set from a list of CROB + CommandSet(std::initializer_list> items); + + /// Construct a command set from a list of AOInt16 + CommandSet(std::initializer_list> items); + + /// Construct a command set from a list of AOInt32 + CommandSet(std::initializer_list> items); + + /// Construct a command set from a list of AOFloat32 + CommandSet(std::initializer_list> items); + + /// Construct a command set from a list of AODouble64 + CommandSet(std::initializer_list> items); + + /// Convenience functions that can build an entire header in one call + template + void Add(std::initializer_list> items) + { + if (!items.size() == 0) + { + auto& header = this->StartHeader(); + for (auto& command : items) + { + header.Add(command.value, command.index); + } + } + } + + /// Convenience functions that can build an entire header in one call + template + void Add(std::vector> items) + { + if (!items.empty()) + { + auto& header = this->StartHeader(); + for (auto& command : items) + { + header.Add(command.value, command.index); + } + } + } + + /// Begin a header of the parameterized type + template + ICommandCollection& StartHeader(); + + +private: + + template + void AddAny(std::initializer_list> items); + + ICommandCollection& StartHeaderCROB(); + ICommandCollection& StartHeaderAOInt32(); + ICommandCollection& StartHeaderAOInt16(); + ICommandCollection& StartHeaderAOFloat32(); + ICommandCollection& StartHeaderAODouble64(); + + CommandSet(const CommandSet&) = delete; + CommandSet& operator= (const CommandSet& other) = delete; + + HeaderVector m_headers; +}; + +template <> +inline ICommandCollection& CommandSet::StartHeader() +{ + return this->StartHeaderCROB(); +} + +template <> +inline ICommandCollection& CommandSet::StartHeader() +{ + return this->StartHeaderAOInt16(); +} + +template <> +inline ICommandCollection& CommandSet::StartHeader() +{ + return this->StartHeaderAOInt32(); +} + +template <> +inline ICommandCollection& CommandSet::StartHeader() +{ + return this->StartHeaderAOFloat32(); +} + +template <> +inline ICommandCollection& CommandSet::StartHeader() +{ + return this->StartHeaderAODouble64(); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderInfo.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderInfo.h new file mode 100644 index 0000000..fcbd22f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderInfo.h @@ -0,0 +1,80 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_HEADERINFO_H +#define OPENDNP3_HEADERINFO_H + +#include "opendnp3/gen/QualifierCode.h" +#include "opendnp3/gen/TimestampMode.h" +#include "opendnp3/gen/GroupVariation.h" + +#include "opendnp3/gen/Attributes.h" + +namespace opendnp3 +{ + +/** +* Simple structure used in the ISOEHandler callbacks to return information +* about the associated header. +*/ +class HeaderInfo +{ +public: + + HeaderInfo() : + gv(GroupVariation::UNKNOWN), + qualifier(QualifierCode::UNDEFINED), + tsmode(TimestampMode::INVALID), + isEventVariation(false), + flagsValid(false), + headerIndex(0) + {} + + HeaderInfo( + GroupVariation gv_, + QualifierCode qualifier_, + TimestampMode tsmode_, + uint32_t headerIndex_ + ) : + gv(gv_), + qualifier(qualifier_), + tsmode(tsmode_), + isEventVariation(IsEvent(gv_)), + flagsValid(HasFlags(gv_)), + headerIndex(headerIndex_) + {} + + /// The group/variation enumeration for the header + GroupVariation gv; + /// The qualifier code enumeration for the header + QualifierCode qualifier; + /// Enumeration that provides information about the validity of timestamps on the associated objects + TimestampMode tsmode; + /// True if the specfied variation is an event variation + bool isEventVariation; + /// True if the flags on the value were present on underlying type, false if online is just assumed + bool flagsValid; + /// The 0-based index of the header within the ASDU + uint32_t headerIndex; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderTypes.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderTypes.h new file mode 100644 index 0000000..f41c024 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/HeaderTypes.h @@ -0,0 +1,139 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_HEADERTYPES_H +#define OPENDNP3_HEADERTYPES_H + +#include + +#include "opendnp3/gen/QualifierCode.h" +#include "opendnp3/app/GroupVariationID.h" +#include "opendnp3/gen/PointClass.h" + +namespace opendnp3 +{ + +class HeaderWriter; + +/** +* An enumeration that defines the type of object header +*/ +enum class HeaderType : uint8_t +{ + AllObjects, + Ranged8, + Ranged16, + LimitedCount8, + LimitedCount16 +}; + +/** +* A template for a integer range +*/ +template +struct StartStopRange +{ + T start; + T stop; +}; + +/** +* A template for an integer count +*/ +template +struct Count +{ + T value; +}; + +/** +* Union type that holds information for a single header type +*/ +union HeaderUnion +{ + StartStopRange range8; + StartStopRange range16; + Count count8; + Count count16; +}; + +/** +* Class used to specify a header type +*/ +class Header +{ +public: + + bool WriteTo(opendnp3::HeaderWriter& writer) const; + + /** + * Create an all objects (0x06) header + */ + static Header AllObjects(uint8_t group, uint8_t variation); + + /** + * Create an all objects (0x06) header + */ + static Header From(PointClass pc); + + /** + * Create a 8-bit start stop header (0x00) + */ + static Header Range8(uint8_t group, uint8_t variation, uint8_t start, uint8_t stop); + + /** + * Create a 16-bit start stop header (0x01) + */ + static Header Range16(uint8_t group, uint8_t variation, uint16_t start, uint16_t stop); + + /** + * Create a 8-bit count header (0x07) + */ + static Header Count8(uint8_t group, uint8_t variation, uint8_t count); + + /** + * Create a 16-bit count header (0x08) + */ + static Header Count16(uint8_t group, uint8_t variation, uint16_t count); + + Header() {} + +private: + + opendnp3::GroupVariationID id; + HeaderType type = HeaderType::AllObjects; + HeaderUnion value; + + Header(uint8_t group, uint8_t var); + + Header(uint8_t group, uint8_t var, uint8_t start, uint8_t stop); + + Header(uint8_t group, uint8_t var, uint16_t start, uint16_t stop); + + Header(uint8_t group, uint8_t var, uint8_t count); + + Header(uint8_t group, uint8_t var, uint16_t count); +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandCollection.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandCollection.h new file mode 100644 index 0000000..0c5e620 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandCollection.h @@ -0,0 +1,40 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICOMMAND_COLLECTION_H +#define OPENDNP3_ICOMMAND_COLLECTION_H + +#include + +namespace opendnp3 +{ + +/// A collection type for command to which the user can add by type and index +template +class ICommandCollection +{ +public: + + virtual ICommandCollection& Add(const T& command, uint16_t index) = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandProcessor.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandProcessor.h new file mode 100644 index 0000000..53839fc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandProcessor.h @@ -0,0 +1,96 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICOMMANDPROCESSOR_H +#define OPENDNP3_ICOMMANDPROCESSOR_H + +#include "opendnp3/master/CommandSet.h" +#include "opendnp3/master/CommandCallbackT.h" +#include "opendnp3/master/TaskConfig.h" + +namespace opendnp3 +{ + +/** +* Interface used to dispatch SELECT / OPERATE / DIRECT OPERATE from application code to a master +*/ +class ICommandProcessor +{ +public: + + /** + * Select and operate a set of commands + * + * @param commands Set of command headers + * @param callback callback that will be invoked upon completion or failure + * @param config optional configuration that controls normal callbacks and allows the user to be specified for SA + */ + virtual void SelectAndOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config = TaskConfig::Default()) = 0; + + /** + * Direct operate a set of commands + * + * @param commands Set of command headers + * @param callback callback that will be invoked upon completion or failure + * @param config optional configuration that controls normal callbacks and allows the user to be specified for SA + */ + virtual void DirectOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config = TaskConfig::Default()) = 0; + + + /** + * Select/operate a single command + * + * @param command Command to operate + * @param index of the command + * @param callback callback that will be invoked upon completion or failure + * @param config optional configuration that controls normal callbacks and allows the user to be specified for SA + */ + template + void SelectAndOperate(const T& command, uint16_t index, const CommandCallbackT& callback, const TaskConfig& config = TaskConfig::Default()); + + /** + * Direct operate a single command + * + * @param command Command to operate + * @param index of the command + * @param callback callback that will be invoked upon completion or failure + * @param config optional configuration that controls normal callbacks and allows the user to be specified for SA + */ + template + void DirectOperate(const T& command, uint16_t index, const CommandCallbackT& callback, const TaskConfig& config = TaskConfig::Default()); +}; + +template +void ICommandProcessor::SelectAndOperate(const T& command, uint16_t index, const CommandCallbackT& callback, const TaskConfig& config) +{ + CommandSet commands({ WithIndex(command, index) }); + this->SelectAndOperate(std::move(commands), callback, config); +} + +template +void ICommandProcessor::DirectOperate(const T& command, uint16_t index, const CommandCallbackT& callback, const TaskConfig& config) +{ + CommandSet commands({ WithIndex(command, index) }); + this->DirectOperate(std::move(commands), callback, config); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandTaskResult.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandTaskResult.h new file mode 100644 index 0000000..fd7a7c1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ICommandTaskResult.h @@ -0,0 +1,55 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_ICOMMAND_TASK_RESULT_H +#define OPENDNP3_ICOMMAND_TASK_RESULT_H + +#include "opendnp3/master/CommandPointResult.h" +#include "opendnp3/gen/TaskCompletion.h" +#include "opendnp3/app/parsing/ICollection.h" + +namespace opendnp3 +{ + +/** +* Abstract result type returned via callback to a command operation. +* +* Provides the TaskCompleton summary value and access to a collection +* of flatten results. +* +* A result value is provided for every object in every header specified +* in the CommandSet used to start the operation. +* +*/ +class ICommandTaskResult : public ICollection +{ +public: + + ICommandTaskResult(TaskCompletion result_) : summary(result_) + {} + + /// A summary result for the entire task + TaskCompletion summary; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/IMasterApplication.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/IMasterApplication.h new file mode 100644 index 0000000..dd869de --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/IMasterApplication.h @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IMASTERAPPLICATION_H +#define OPENDNP3_IMASTERAPPLICATION_H + +#include + +#include "opendnp3/master/TaskInfo.h" +#include "opendnp3/master/HeaderTypes.h" + +#include "opendnp3/app/IINField.h" +#include "opendnp3/link/ILinkListener.h" + +#include "opendnp3/gen/MasterTaskType.h" +#include "opendnp3/gen/TaskCompletion.h" + +#include + +namespace opendnp3 +{ + +typedef std::function WriteHeaderFunT; + +/** +* Interface for all master application callback info except for measurement values. +*/ +class IMasterApplication : public ILinkListener, public openpal::IUTCTimeSource +{ +public: + + virtual ~IMasterApplication() {} + + /// Called when a response or unsolicited response is receive from the outstation + virtual void OnReceiveIIN(const IINField& iin) {} + + /// Task start notification + virtual void OnTaskStart(MasterTaskType type, TaskId id) {} + + /// Task completion notification + virtual void OnTaskComplete(const TaskInfo& info) {} + + /// Called when the application layer is opened + virtual void OnOpen() {} + + /// Called when the application layer is closed + virtual void OnClose() {} + + /// @return true if the master should do an assign class task during startup handshaking + virtual bool AssignClassDuringStartup() + { + return false; + } + + /// Configure the request headers for assign class. Only called if + /// "AssignClassDuringStartup" returns true + /// The user only needs to call the function for each header type to be written + virtual void ConfigureAssignClassRequest(const WriteHeaderFunT& fun) {} + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/ISOEHandler.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ISOEHandler.h new file mode 100644 index 0000000..a1f3ab0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ISOEHandler.h @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ISOEHANDLER_H +#define OPENDNP3_ISOEHANDLER_H + +#include "opendnp3/app/ITransactable.h" + +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/app/BinaryCommandEvent.h" +#include "opendnp3/app/AnalogCommandEvent.h" +#include "opendnp3/app/OctetString.h" +#include "opendnp3/app/SecurityStat.h" + +#include "opendnp3/app/Indexed.h" +#include "opendnp3/app/parsing/ICollection.h" + +#include "opendnp3/master/HeaderInfo.h" +#include "openpal/executor/UTCTimestamp.h" + +namespace opendnp3 +{ + +/** +* An interface for Sequence-Of-Events (SOE) callbacks from a master stack to +* the application layer. +* +* A call is made to the appropriate member method for every measurement value in an ASDU. +* The HeaderInfo class provides information about the object header associated with the value. +* +*/ +class ISOEHandler : public ITransactable +{ +public: + + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection>& values) = 0; + virtual void Process(const HeaderInfo& info, const ICollection& values) = 0; + + virtual ~ISOEHandler() {} +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/ITaskCallback.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ITaskCallback.h new file mode 100644 index 0000000..16a441e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/ITaskCallback.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ITASKCALLBACK_H +#define OPENDNP3_ITASKCALLBACK_H + +#include "opendnp3/gen/TaskCompletion.h" + +namespace opendnp3 +{ + +/** +* Callbacks for when a task starts and completes +*/ +class ITaskCallback +{ +public: + + // Called when the task starts running + virtual void OnStart() = 0; + + // Called when the task succeeds or fails + virtual void OnComplete(TaskCompletion result) = 0; + + // Called when the task no longer exists and no more calls will be made to OnStart/OnComplete + virtual void OnDestroyed() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/MasterParams.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/MasterParams.h new file mode 100644 index 0000000..06ca8ba --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/MasterParams.h @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MASTERPARAMS_H +#define OPENDNP3_MASTERPARAMS_H + +#include + +#include "opendnp3/gen/TimeSyncMode.h" +#include "opendnp3/app/ClassField.h" +#include "opendnp3/app/AppConstants.h" + +namespace opendnp3 +{ + +/** +Configuration information for the dnp3 master +*/ +struct MasterParams +{ + /// Default constructor + MasterParams() {} + + /// Application layer response timeout + openpal::TimeDuration responseTimeout = openpal::TimeDuration::Seconds(5); + + /// If true, the master will do time syncs when it sees the time IIN bit from the outstation + TimeSyncMode timeSyncMode = TimeSyncMode::None; + + /// If true, the master will disable unsol on startup for all 3 classes + bool disableUnsolOnStartup = true; + + /// If true, the master will not clear the restart IIN bit in response to detecting it set + bool ignoreRestartIIN = false; + + /// Bitwise mask used determine which classes are enabled for unsol, if 0 unsol is not enabled + ClassField unsolClassMask = ClassField::AllEventClasses(); + + /// Which classes should be requested in a startup integrity scan, defaults to 3/2/1/0 + /// A mask equal to 0 means no startup integrity scan will be performed + ClassField startupIntegrityClassMask = ClassField::AllClasses(); + + /// Defines whether an integrity scan will be performed when the EventBufferOverflow IIN is detected + bool integrityOnEventOverflowIIN = true; + + /// Which classes should be requested in an event scan when detecting corresponding events available IIN + ClassField eventScanOnEventsAvailableClassMask = ClassField::None(); + + /// Time delay before retrying a failed task + openpal::TimeDuration taskRetryPeriod = openpal::TimeDuration::Seconds(5); + + /// Time delay before failing a non-recurring task (e.g. commands) that cannot start + openpal::TimeDuration taskStartTimeout = openpal::TimeDuration::Seconds(10); + + /// maximum APDU tx size in bytes + uint32_t maxTxFragSize = DEFAULT_MAX_APDU_SIZE; + + /// maximum APDU rx size in bytes + uint32_t maxRxFragSize = DEFAULT_MAX_APDU_SIZE; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/RestartOperationResult.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/RestartOperationResult.h new file mode 100644 index 0000000..91d5e25 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/RestartOperationResult.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_RESTART_OPERATION_RESULT_H +#define OPENDNP3_RESTART_OPERATION_RESULT_H + +#include "opendnp3/gen/TaskCompletion.h" + +#include + +#include +#include + +namespace opendnp3 +{ + +class RestartOperationResult +{ +public: + + RestartOperationResult() : summary(TaskCompletion::FAILURE_NO_COMMS) + {} + + RestartOperationResult(TaskCompletion summary_, openpal::TimeDuration restartTime_) : + summary(summary_), restartTime(restartTime_) + {} + + /// The result of the task as a whole. + TaskCompletion summary; + + /// Time delay until restart + openpal::TimeDuration restartTime; +}; + +typedef std::function RestartOperationCallbackT; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskConfig.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskConfig.h new file mode 100644 index 0000000..f5ba65f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskConfig.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TASKCONFIG_H +#define OPENDNP3_TASKCONFIG_H + +#include "TaskId.h" +#include "ITaskCallback.h" + +#include + +namespace opendnp3 +{ + +/** +* Object containing multiple fields for configuring tasks +*/ +class TaskConfig +{ +public: + + TaskConfig(TaskId taskId, ITaskCallback* pCallback) : + taskId(taskId), + pCallback(pCallback) + {} + + static TaskConfig Default() + { + return TaskConfig(TaskId::Undefined(), nullptr); + } + + /// --- syntax sugar for building configs ----- + + static TaskConfig With(ITaskCallback& callback) + { + return TaskConfig(TaskId::Undefined(), &callback); + } + + TaskConfig() = delete; + +public: + + TaskId taskId; + ITaskCallback* pCallback; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskId.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskId.h new file mode 100644 index 0000000..9f67dd9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskId.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TASKID_H +#define OPENDNP3_TASKID_H + +namespace opendnp3 +{ + +/** +* Interface that represents a running master. +*/ +class TaskId +{ +public: + + static TaskId Defined(int id) + { + return TaskId(id, true); + } + static TaskId Undefined() + { + return TaskId(-1, false); + } + + int GetId() const + { + return id; + } + bool IsDefined() const + { + return isDefined; + } + +private: + + TaskId() = delete; + + TaskId(int id_, bool isDefined_) : id(id_), isDefined(isDefined_) {} + + int id; + bool isDefined; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskInfo.h b/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskInfo.h new file mode 100644 index 0000000..b85d463 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/master/TaskInfo.h @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TASK_INFO_H +#define OPENDNP3_TASK_INFO_H + +#include "opendnp3/master/TaskId.h" + +#include "opendnp3/gen/MasterTaskType.h" +#include "opendnp3/gen/TaskCompletion.h" + + +namespace opendnp3 +{ + +/** +* Struct that provides information about a completed or failed task. +*/ +class TaskInfo +{ + +public: + + TaskInfo( + MasterTaskType type_, + TaskCompletion result_, + TaskId id_ + ) : + type(type_), + result(result_), + id(id_) + {} + + MasterTaskType type; + TaskCompletion result; + TaskId id; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ApplicationIIN.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ApplicationIIN.h new file mode 100644 index 0000000..51ee2b5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ApplicationIIN.h @@ -0,0 +1,55 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APPLICATIONIIN_H +#define OPENDNP3_APPLICATIONIIN_H + +#include + +#include + +namespace opendnp3 +{ + +/** + Some IIN bits are necessarily controlled by the outstation application, + not the underlying protocol stack. This structure describes the state of + the bits controllable by the application. +*/ +class ApplicationIIN +{ + +public: + + ApplicationIIN(); + + bool needTime; + bool localControl; + bool deviceTrouble; + bool configCorrupt; + + IINField ToIIN() const; + +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/Cell.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/Cell.h new file mode 100644 index 0000000..5396e63 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/Cell.h @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CELL_H +#define OPENDNP3_CELL_H + +namespace opendnp3 +{ + +/** +* Type used to record whether a value is requested in a response +*/ +template +struct SelectedValue +{ + SelectedValue() : selected(false), value(), variation(Spec::DefaultStaticVariation) + {} + + bool selected; + typename Spec::meas_t value; + typename Spec::static_variation_t variation; +}; + +/** +* Holds particular measurement type in the database. +*/ +template +struct Cell +{ + typename Spec::meas_t value; // current value + typename Spec::config_t config; // configuration + typename Spec::event_cell_t event; // event cell + SelectedValue selection; // selected value + +}; + + + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/DatabaseSizes.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/DatabaseSizes.h new file mode 100644 index 0000000..0e50216 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/DatabaseSizes.h @@ -0,0 +1,116 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DATABASESIZES_H +#define OPENDNP3_DATABASESIZES_H + +#include + +namespace opendnp3 +{ + +/** +* Specifies the number and type of measurements in an outstation database. +*/ +struct DatabaseSizes +{ + static DatabaseSizes BinaryOnly(uint16_t count) + { + return DatabaseSizes(count, 0, 0, 0, 0, 0, 0, 0); + } + + static DatabaseSizes DoubleBinaryOnly(uint16_t count) + { + return DatabaseSizes(0, count, 0, 0, 0, 0, 0, 0); + } + + static DatabaseSizes AnalogOnly(uint16_t count) + { + return DatabaseSizes(0, 0, count, 0, 0, 0, 0, 0); + } + + static DatabaseSizes CounterOnly(uint16_t count) + { + return DatabaseSizes(0, 0, 0, count, 0, 0, 0, 0); + } + + static DatabaseSizes FrozenCounterOnly(uint16_t count) + { + return DatabaseSizes(0, 0, 0, 0, count, 0, 0, 0); + } + + static DatabaseSizes BinaryOutputStatusOnly(uint16_t count) + { + return DatabaseSizes(0, 0, 0, 0, 0, count, 0, 0); + } + + static DatabaseSizes AnalogOutputStatusOnly(uint16_t count) + { + return DatabaseSizes(0, 0, 0, 0, 0, 0, count, 0); + } + + static DatabaseSizes TimeAndIntervalOnly(uint16_t count) + { + return DatabaseSizes(0, 0, 0, 0, 0, 0, 0, count); + } + + static DatabaseSizes AllTypes(uint16_t count) + { + return DatabaseSizes(count, count, count, count, count, count, count, count); + } + + static DatabaseSizes Empty() + { + return DatabaseSizes(0, 0, 0, 0, 0, 0, 0, 0); + } + + DatabaseSizes(uint16_t numBinary, + uint16_t numDoubleBinary, + uint16_t numAnalog, + uint16_t numCounter, + uint16_t numFrozenCounter, + uint16_t numBinaryOutputStatus, + uint16_t numAnalogOutputStatus, + uint16_t numTimeAndInterval) : + + numBinary(numBinary), + numDoubleBinary(numDoubleBinary), + numAnalog(numAnalog), + numCounter(numCounter), + numFrozenCounter(numFrozenCounter), + numBinaryOutputStatus(numBinaryOutputStatus), + numAnalogOutputStatus(numAnalogOutputStatus), + numTimeAndInterval(numTimeAndInterval) + {} + + uint16_t numBinary; + uint16_t numDoubleBinary; + uint16_t numAnalog; + uint16_t numCounter; + uint16_t numFrozenCounter; + uint16_t numBinaryOutputStatus; + uint16_t numAnalogOutputStatus; + uint16_t numTimeAndInterval; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/EventBufferConfig.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/EventBufferConfig.h new file mode 100644 index 0000000..9e47752 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/EventBufferConfig.h @@ -0,0 +1,98 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTBUFFERCONFIG_H +#define OPENDNP3_EVENTBUFFERCONFIG_H + +#include + +#include "opendnp3/app/EventType.h" + +namespace opendnp3 +{ + +/** + + Configuration of maximum event counts per event type. + + The underlying implementation uses a *preallocated* heap buffer to store events + until they are transmitted to the master. The size of this buffer is proportional + to the TotalEvents() method, i.e. the sum of the maximum events for each type. + + Implementations should configure the buffers to store a reasonable number events + given the polling frequency and memory restrictions of the target platform. + +*/ +struct EventBufferConfig +{ + /** + Construct the class using the same maximum for all types. This is mainly used for demo purposes. + You probably don't want to use this method unless your implementation actually reports every type. + */ + static EventBufferConfig AllTypes(uint16_t sizes); + + /// Retrieve the number of events using a type enumeration + uint16_t GetMaxEventsForType(EventType type) const; + + /** + Construct the class specifying the maximum number of events for each type individually. + */ + EventBufferConfig( + uint16_t maxBinaryEvents = 0, + uint16_t maxDoubleBinaryEvents = 0, + uint16_t maxAnalogEvents = 0, + uint16_t maxCounterEvents = 0, + uint16_t maxFrozenCounterEvents = 0, + uint16_t maxBinaryOutputStatusEvents = 0, + uint16_t maxAnalogOutputStatusEvents = 0, + uint16_t maxSecurityStatisticEvents = 0 + ); + + /// Returns the sum of all event count maximums (number of elements in preallocated buffer) + uint32_t TotalEvents() const; + + /// The number of binary events the outstation will buffer before overflowing + uint16_t maxBinaryEvents; + + /// The number of double bit binary events the outstation will buffer before overflowing + uint16_t maxDoubleBinaryEvents; + + /// The number of analog events the outstation will buffer before overflowing + uint16_t maxAnalogEvents; + + /// The number of counter events the outstation will buffer before overflowing + uint16_t maxCounterEvents; + + /// The number of frozen counter events the outstation will buffer before overflowing + uint16_t maxFrozenCounterEvents; + + /// The number of binary output status events the outstation will buffer before overflowing + uint16_t maxBinaryOutputStatusEvents; + + /// The number of analog output status events the outstation will buffer before overflowing + uint16_t maxAnalogOutputStatusEvents; + + /// The number of security statistic events the outstation will buffer before overflowing + uint16_t maxSecurityStatisticEvents; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ICommandHandler.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ICommandHandler.h new file mode 100644 index 0000000..2b42b9f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/ICommandHandler.h @@ -0,0 +1,144 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICOMMANDHANDLER_H +#define OPENDNP3_ICOMMANDHANDLER_H + +#include "opendnp3/app/ControlRelayOutputBlock.h" +#include "opendnp3/app/AnalogOutput.h" +#include "opendnp3/app/ITransactable.h" +#include "opendnp3/gen/OperateType.h" + +namespace opendnp3 +{ + +/** +* Interface used to dispatch SELECT / OPERATE / DIRECT OPERATE (Binary/Analog output) from the outstation to application code. +* +* The ITransactable sub-interface is used to determine the start and end of an ASDU containing commands. +*/ +class ICommandHandler : public ITransactable +{ +public: + virtual ~ICommandHandler() {} + + /** + * Ask if the application supports a ControlRelayOutputBlock - group 12 variation 1 + * + * @param command command to operate + * @param index index of the command + * @return result of request + */ + virtual CommandStatus Select(const ControlRelayOutputBlock& command, uint16_t index) = 0; + + /** + * Operate a ControlRelayOutputBlock - group 12 variation 1 + * + * @param command command to operate + * @param index index of the command + * @param opType the operation type the outstation received. + * @return result of request + */ + virtual CommandStatus Operate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) = 0; + + + /** + * Ask if the application supports a 16 bit analog output - group 41 variation 2 + * + * @param command command to operate + * @param index index of the command + * @return result of request + */ + virtual CommandStatus Select(const AnalogOutputInt16& command, uint16_t index) = 0; + + /** + * Ask if the application supports a 16 bit analog output - group 41 variation 2 + * + * @param command command to operate + * @param index index of the command + * @param opType the operation type the outstation received. + * @return result of request + */ + virtual CommandStatus Operate(const AnalogOutputInt16& command, uint16_t index, OperateType opType) = 0; + + + /** + * Ask if the application supports a 32 bit analog output - group 41 variation 1 + * + * @param command command to operate + * @param index index of the command + * @return result of request + */ + virtual CommandStatus Select(const AnalogOutputInt32& command, uint16_t index) = 0; + + /** + * Operate a 32 bit analog output - group 41 variation 1 + * + * @param command command to operate + * @param index index of the command + * @param opType the operation type the outstation received. + * @return result of request + */ + virtual CommandStatus Operate(const AnalogOutputInt32& command, uint16_t index, OperateType opType) = 0; + + /** + * Ask if the application supports a single precision, floating point analog output - group 41 variation 3 + * + * @param command command to operate + * @param index index of the command + * @return result of request + */ + virtual CommandStatus Select(const AnalogOutputFloat32& command, uint16_t index) = 0; + + /** + * Operate a single precision, floating point analog output - group 41 variation 3 + * + * @param command command to operate + * @param index index of the command + * @param opType the operation type the outstation received. + * @return result of request + */ + virtual CommandStatus Operate(const AnalogOutputFloat32& command, uint16_t index, OperateType opType) = 0; + + /** + * Ask if the application supports a double precision, floating point analog output - group 41 variation 4 + * + * @param command command to operate + * @param index index of the command + * @return result of request + */ + virtual CommandStatus Select(const AnalogOutputDouble64& command, uint16_t index) = 0; + + /** + * Operate a double precision, floating point analog output - group 41 variation 4 + * + * @param command command to operate + * @param index index of the command + * @param opType the operation type the outstation received. + * @return result of request + */ + virtual CommandStatus Operate(const AnalogOutputDouble64& command, uint16_t index, OperateType opType) = 0; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IOutstationApplication.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IOutstationApplication.h new file mode 100644 index 0000000..841113f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IOutstationApplication.h @@ -0,0 +1,158 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IOUTSTATIONAPPLICATION_H +#define OPENDNP3_IOUTSTATIONAPPLICATION_H + +#include + +#include "opendnp3/gen/PointClass.h" +#include "opendnp3/gen/RestartMode.h" +#include "opendnp3/gen/AssignClassType.h" + +#include "opendnp3/link/ILinkListener.h" + +#include "opendnp3/app/Indexed.h" +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/app/parsing/ICollection.h" + +#include "opendnp3/outstation/ApplicationIIN.h" + +#include + +namespace opendnp3 +{ + +/** +* Interface for all outstation application callback info except for control requests +*/ +class IOutstationApplication : public ILinkListener +{ +public: + + + /// Queries whether the the outstation supports absolute time writes + /// If this function returns false, WriteAbsoluteTime will never be called + /// and the outstation will return IIN 2.1 (FUNC_NOT_SUPPORTED) + virtual bool SupportsWriteAbsoluteTime() + { + return false; + } + + /// Write the time to outstation, only called if SupportsWriteAbsoluteTime return true + /// @return boolean value indicating if the time value supplied was accepted. Returning + /// false will cause the outstation to set IIN 2.3 (PARAM_ERROR) in its response. + /// The outstation should clear its NEED_TIME field when handling this response + virtual bool WriteAbsoluteTime(const openpal::UTCTimestamp& timestamp) + { + return false; + } + + /// Queries whether the outstation supports the writing of TimeAndInterval + /// If this function returns false, WriteTimeAndInterval will never be called + /// and the outstation will return IIN 2.1 (FUNC_NOT_SUPPORTED) when it receives this request + virtual bool SupportsWriteTimeAndInterval() + { + return false; + } + + /// Write one or more TimeAndInterval values. Only called if SupportsWriteTimeAndInterval returns true. + /// The outstation application code is reponsible for updating TimeAndInterval values in the database if this behavior + /// is desired + /// @return boolean value indicating if the values supplied were accepted. Returning + /// false will cause the outstation to set IIN 2.3 (PARAM_ERROR) in its response. + virtual bool WriteTimeAndInterval(const ICollection>& values) + { + return false; + } + + /// True if the outstation supports the assign class function code + /// If this function returns false, the assign class callbacks will never be called + /// and the outstation will return IIN 2.1 (FUNC_NOT_SUPPORTED) when it receives this function code + virtual bool SupportsAssignClass() + { + return false; + } + + /// Called if SupportsAssignClass returns true + /// The type and range are pre-validated against the outstation's database + /// and class assignments are automatically applied internally. + /// This callback allows user code to persist the changes to non-volatile memory + virtual void RecordClassAssignment(AssignClassType type, PointClass clazz, uint16_t start, uint16_t stop) {} + + /// Returns the application-controlled IIN field + virtual ApplicationIIN GetApplicationIIN() const + { + return ApplicationIIN(); + } + + /// Query the outstation for the cold restart mode it supports + virtual RestartMode ColdRestartSupport() const + { + return RestartMode::UNSUPPORTED; + } + + /// Query the outstation for the warm restart mode it supports + virtual RestartMode WarmRestartSupport() const + { + return RestartMode::UNSUPPORTED; + } + + /// The outstation should perform a complete restart. + /// See the DNP3 specification for a complete descripton of normal behavior + /// @return number of seconds or milliseconds until restart is complete. The value + /// is interpreted based on the Restart Mode returned from ColdRestartSupport() + virtual uint16_t ColdRestart() + { + return 65535; + } + + /// The outstation should perform a partial restart of only the DNP3 application. + /// See the DNP3 specification for a complete descripton of normal behavior + /// @return number of seconds or milliseconds until restart is complete. The value + /// is interpreted based on the Restart Mode returned from WarmRestartSupport() + virtual uint16_t WarmRestart() + { + return 65535; + } + + + virtual ~IOutstationApplication() {} +}; + +/** +* A singleton with default setting useful for examples +*/ +class DefaultOutstationApplication : public IOutstationApplication +{ +public: + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + DefaultOutstationApplication() = default; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IUpdateHandler.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IUpdateHandler.h new file mode 100644 index 0000000..d635c7a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/IUpdateHandler.h @@ -0,0 +1,124 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IUPDATEHANDLER_H +#define OPENDNP3_IUPDATEHANDLER_H + +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/gen/EventMode.h" +#include "opendnp3/gen/FlagsType.h" + +namespace opendnp3 +{ + +/** +* An interface used to update measurement values. +*/ +class IUpdateHandler +{ +public: + + virtual ~IUpdateHandler() {} + + /** + * Update a Binary measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const Binary& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update a DoubleBitBinary measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const DoubleBitBinary& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update an Analog measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const Analog& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update a Counter measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const Counter& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update a FrozenCounter measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const FrozenCounter& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update a BinaryOutputStatus measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const BinaryOutputStatus& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update a AnalogOutputStatus measurement + * @param meas measurement to be processed + * @param index index of the measurement + * @param mode Describes how event generation is handled for this method + * @return true if the value exists and it was updated + */ + virtual bool Update(const AnalogOutputStatus& meas, uint16_t index, EventMode mode = EventMode::Detect) = 0; + + /** + * Update a TimeAndInterval valueindex + * @param meas measurement to be processed + * @param index index of the measurement + * @return true if the value exists and it was updated + */ + virtual bool Update(const TimeAndInterval& meas, uint16_t index) = 0; + + /** + * Update the flags of a measurement without changing it's value + * @param type enumeration specifiy the type to change + * @param start the start index at which to begin changing flags + * @param stop the stop index at which to end changing flags + * @param flags the new value of the flags + */ + virtual bool Modify(FlagsType type, uint16_t start, uint16_t stop, uint8_t flags) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/MeasurementConfig.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/MeasurementConfig.h new file mode 100644 index 0000000..bd0cf96 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/MeasurementConfig.h @@ -0,0 +1,70 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the Infoific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_MEASUREMENTCONFIG_H +#define OPENDNP3_MEASUREMENTCONFIG_H + +#include "opendnp3/app/MeasurementInfo.h" +#include "opendnp3/gen/PointClass.h" + +namespace opendnp3 +{ + +// All entries have this information +struct IndexConfig +{ + // virtual index for discontiguous data, as opposed to the raw array index + uint16_t vIndex = 0; +}; + +// All entries have this information +template +struct StaticConfig : IndexConfig +{ + typename Info::static_variation_t svariation = Info::DefaultStaticVariation; +}; + +template +struct EventConfig : StaticConfig +{ + PointClass clazz = PointClass::Class1; + typename Info::event_variation_t evariation = Info::DefaultEventVariation; +}; + +template +struct DeadbandConfig : EventConfig +{ + typename Info::value_t deadband = 0; +}; + +class BinaryConfig : public EventConfig {}; +class DoubleBitBinaryConfig : public EventConfig {}; +class AnalogConfig : public DeadbandConfig {}; +class CounterConfig : public DeadbandConfig {}; +class FrozenCounterConfig : public DeadbandConfig {}; +class BOStatusConfig : public EventConfig {}; +class AOStatusConfig : public DeadbandConfig {}; +class TimeAndIntervalConfig : public StaticConfig {}; +class SecurityStatConfig : public IndexConfig {}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationConfig.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationConfig.h new file mode 100644 index 0000000..7c7c37d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationConfig.h @@ -0,0 +1,55 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONCONFIG_H +#define OPENDNP3_OUTSTATIONCONFIG_H + +#include + +#include "opendnp3/outstation/OutstationParams.h" +#include "opendnp3/outstation/EventBufferConfig.h" + + +namespace opendnp3 +{ + +/** Configuration information for a dnp3 outstation (outstation) + +Used as both input describing the startup configuration of the outstation, and as configuration state of mutable properties (i.e. unsolicited responses). + +Major feature areas are unsolicited responses, time synchronization requests, event buffer limits, and the DNP3 object/variations to use by default +when the master requests class data or variation 0. + +*/ +struct OutstationConfig +{ + /// Various parameters that govern outstation behavior + OutstationParams params; + + /// Describes the sizes in the event buffer + EventBufferConfig eventBufferConfig; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationParams.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationParams.h new file mode 100644 index 0000000..7bb7abf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/OutstationParams.h @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONPARAMS_H +#define OPENDNP3_OUTSTATIONPARAMS_H + +#include + +#include "opendnp3/gen/IndexMode.h" + +#include "opendnp3/app/ClassField.h" +#include "opendnp3/app/AppConstants.h" + +#include "opendnp3/outstation/StaticTypeBitfield.h" + +namespace opendnp3 +{ + +/** +* Static configuration parameters for an outstation session +*/ +struct OutstationParams +{ + /// Controls the index mode (defaults to contiguous) + IndexMode indexMode = IndexMode::Contiguous; + + /// The maximum number of controls the outstation will attempt to process from a single APDU + uint8_t maxControlsPerRequest = 16; + + /// How long the outstation will allow an operate to proceed after a prior select + openpal::TimeDuration selectTimeout = openpal::TimeDuration::Seconds(10); + + /// Timeout for solicited confirms + openpal::TimeDuration solConfirmTimeout = DEFAULT_APP_TIMEOUT; + + /// Timeout for unsolicited confirms + openpal::TimeDuration unsolConfirmTimeout = DEFAULT_APP_TIMEOUT; + + /// Timeout for unsolicited retries + openpal::TimeDuration unsolRetryTimeout = DEFAULT_APP_TIMEOUT; + + /// The maximum fragment size the outstation will use for fragments it sends + uint32_t maxTxFragSize = DEFAULT_MAX_APDU_SIZE; + + /// The maximum fragment size the outstation will be able to receive + uint32_t maxRxFragSize = DEFAULT_MAX_APDU_SIZE; + + /// Global enabled / disable for unsolicited messages. If false, the NULL unsolicited message is not even sent + bool allowUnsolicited = false; + + /// A bitmask type that specifies the types allowed in a class 0 reponse + StaticTypeBitField typesAllowedInClass0 = StaticTypeBitField::AllTypes(); + + /// Class mask for unsolicted, default to 0 as unsolicited has to be enabled + ClassField unsolClassMask = ClassField::None(); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/SimpleCommandHandler.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/SimpleCommandHandler.h new file mode 100644 index 0000000..7e33c67 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/SimpleCommandHandler.h @@ -0,0 +1,112 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SIMPLECOMMANDHANDLER_H +#define OPENDNP3_SIMPLECOMMANDHANDLER_H + +#include "ICommandHandler.h" + +#include + +namespace opendnp3 +{ + +/** +* Mock ICommandHandler used for examples and demos +*/ +class SimpleCommandHandler : public ICommandHandler +{ +public: + + /** + * @param status The status value to return in response to all commands + */ + SimpleCommandHandler(CommandStatus status); + + CommandStatus Select(const ControlRelayOutputBlock& command, uint16_t index) override final; + CommandStatus Operate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) override final; + + + CommandStatus Select(const AnalogOutputInt16& command, uint16_t index) override final; + CommandStatus Operate(const AnalogOutputInt16& command, uint16_t index, OperateType opType) override final; + + + CommandStatus Select(const AnalogOutputInt32& command, uint16_t index) override final; + CommandStatus Operate(const AnalogOutputInt32& command, uint16_t index, OperateType opType) override final; + + + CommandStatus Select(const AnalogOutputFloat32& command, uint16_t index) override final; + CommandStatus Operate(const AnalogOutputFloat32& command, uint16_t index, OperateType opType) override final; + + + CommandStatus Select(const AnalogOutputDouble64& command, uint16_t index) override final; + CommandStatus Operate(const AnalogOutputDouble64& command, uint16_t index, OperateType opType) override final; + + +protected: + + virtual void DoSelect(const ControlRelayOutputBlock& command, uint16_t index) {} + virtual void DoOperate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) {} + + virtual void DoSelect(const AnalogOutputInt16& command, uint16_t index) {} + virtual void DoOperate(const AnalogOutputInt16& command, uint16_t index, OperateType opType) {} + + virtual void DoSelect(const AnalogOutputInt32& command, uint16_t index) {} + virtual void DoOperate(const AnalogOutputInt32& command, uint16_t index, OperateType opType) {} + + virtual void DoSelect(const AnalogOutputFloat32& command, uint16_t index) {} + virtual void DoOperate(const AnalogOutputFloat32& command, uint16_t index, OperateType opType) {} + + virtual void DoSelect(const AnalogOutputDouble64& command, uint16_t index) {} + virtual void DoOperate(const AnalogOutputDouble64& command, uint16_t index, OperateType opType) {} + + virtual void Start() override; + virtual void End() override; + + CommandStatus status; + +public: + + uint32_t numOperate; + uint32_t numSelect; + uint32_t numStart; + uint32_t numEnd; + +}; + +/** +* A singleton command handler that always returns success +*/ +class SuccessCommandHandler : public SimpleCommandHandler +{ +public: + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + SuccessCommandHandler() : SimpleCommandHandler(CommandStatus::SUCCESS) {} +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/StaticTypeBitfield.h b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/StaticTypeBitfield.h new file mode 100644 index 0000000..1c0f519 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/opendnp3/outstation/StaticTypeBitfield.h @@ -0,0 +1,64 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_STATICTYPEBITFIELD_H +#define OPENDNP3_STATICTYPEBITFIELD_H + +#include "opendnp3/gen/StaticTypeBitmask.h" + +#include + +namespace opendnp3 +{ + +/** +* A bitfield that describes a subset of all static types, e.g. { Binary, Analog } or {Analog, Counter, FrozenCounter } +*/ +struct StaticTypeBitField +{ + StaticTypeBitField() : mask(0) + {} + + StaticTypeBitField(uint16_t mask_) : mask(mask_) + {} + + static StaticTypeBitField AllTypes() + { + return StaticTypeBitField(~0); + } + + bool IsSet(StaticTypeBitmask type) const + { + return (mask & static_cast(type)) != 0; + } + + StaticTypeBitField Except(StaticTypeBitmask type) const + { + return StaticTypeBitField(mask & ~static_cast(type)); + } + +private: + + uint16_t mask; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/Configure.h b/utils/dnp3_src/cpp/libs/include/openpal/Configure.h new file mode 100644 index 0000000..b0f94da --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/Configure.h @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_CONFIGURE_H +#define OPENPAL_CONFIGURE_H + +#include + +// Default configurations for the static erasure size. +// They are liberally set by default for x64 +// but can be reduced for embedded systems. + +#ifndef OPENPAL_ERASURE_MULTIPLE +#define OPENPAL_ERASURE_MULTIPLE 12 +#endif + +namespace openpal +{ +namespace sizes +{ + +static const uint16_t MAX_ERASURE_SIZE = OPENPAL_ERASURE_MULTIPLE * sizeof(void*); + +} +} + +#ifdef AVR + +#include +#include + +inline void* operator new(size_t, void* p) +{ + return p; +} + +inline void* operator new(size_t size) +{ + return malloc(size); +} + +inline void operator delete(void* ptr) +{ + free(ptr); +} + +inline void* operator new[](size_t size) +{ + return malloc(size); +} + +inline void operator delete[](void* ptr) +{ + free(ptr); +} + +extern "C" void abort(); + +#else + +#include + +#endif + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayer.h b/utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayer.h new file mode 100644 index 0000000..f8f5254 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayer.h @@ -0,0 +1,150 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_IPHYSICALLAYER_H +#define OPENPAL_IPHYSICALLAYER_H + +#include "ChannelStatistics.h" + +#include "openpal/container/RSlice.h" +#include "openpal/container/WSlice.h" + +namespace openpal +{ + +class IPhysicalLayerCallbacks; + +class IChannelState +{ + +public: + + virtual bool CanOpen() const = 0; + + virtual bool CanClose() const = 0; + + virtual bool CanRead() const = 0; + + virtual bool CanWrite() const = 0; + + /** @return True if the layer is performing an async read */ + virtual bool IsReading() const = 0; + + /** @return True if the layer is performing an async write */ + virtual bool IsWriting() const = 0; + + /** @return True if the layer is performing an asynchronously closing */ + virtual bool IsClosing() const = 0; + + /** @return True if the layer is in the closed with no other activity */ + virtual bool IsClosed() const = 0; + + /** @return True if the layer is performing an asynchronously opening */ + virtual bool IsOpening() const = 0; + + /** @return True if the layer is open for read/write */ + virtual bool IsOpen() const = 0; +}; + + +/** + * Defines an asynchronous interface for serial/tcp/? + */ +class IPhysicalLayer : public IChannelState +{ +public: + + IPhysicalLayer() : pChannelStatistics(nullptr) + {} + + virtual ~IPhysicalLayer() {} + + /** + * Tell the layer where to update its channel statistics + */ + void SetChannelStatistics(ChannelStatistics* pChannelStatistics_) + { + pChannelStatistics = pChannelStatistics_; + } + + /** + * Starts an open operation. + * + * Callback is either IHandler::OnLowerLayerUp or + * IHandler::OnOpenFailure. + */ + virtual void BeginOpen() = 0; + + /** + * Starts a close operation. + * + * Callback is IHandler::OnLowerLayerDown. Callback occurs + * after all hronous operations have occured. If the user + * code has an outstanding read or write, those handlers will not + * be called. + */ + virtual void BeginClose() = 0; + + /** + * Starts a send operation. + * + * Callback is IHandler::OnSendSuccess or a failure will + * result in the layer closing. + * + * @param arBuffer The buffer from which the write operation + * will write data. The underlying buffer must + * remain available until the write callback or + * close occurs. + */ + virtual void BeginWrite(const RSlice& arBuffer) = 0; + + /** + * Starts a read operation. + * + * Use SetHandler to provide a callback that is called by + * OnReceive(const RSlice&) or a failure will + * result in the layer closing. + * + * @param arBuffer Read into the underlying buffer + * defined by the wrapper. The underlying buffer + * must remain available until the read callback + */ + virtual void BeginRead(WSlice& arBuffer) = 0; + + /** + * Set the handler interface for callbacks. A read interface has + * been added so the max size is no longer required. + * + * @param apHandler Class that will process asynchronous + * callbacks + */ + virtual void SetHandler(IPhysicalLayerCallbacks* apHandler) = 0; + +protected: + + ChannelStatistics* pChannelStatistics; + +}; + +}; + + + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayerCallbacks.h b/utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayerCallbacks.h new file mode 100644 index 0000000..155de27 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/channel/IPhysicalLayerCallbacks.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_IPHYSICALLAYERCALLBACKS_H +#define OPENPAL_IPHYSICALLAYERCALLBACKS_H + +#include "openpal/container/RSlice.h" + +namespace openpal +{ + +class IPhysicalLayerCallbacks +{ + +public: + virtual ~IPhysicalLayerCallbacks() {} + + // Called by a lower Layer when it is available to this layer + virtual void OnLowerLayerUp() = 0; + + // Called by a lower layer when it is no longer available to this layer + virtual void OnLowerLayerDown() = 0; + + // In addition to all of the IUpperLayer functions, provide a mechanism to receive open failures + // For consistency sake, use NVII pattern in case we want pre/post conditions in the future + virtual void OnOpenFailure() = 0; + + // Called by the physical layer when data arrives + virtual void OnReceive(const RSlice&) = 0; + + // Called by lower layer when a previously requested send operation succeeds or fails. + // Layers can only have 1 outstanding send operation. The callback is guaranteed + // unless the the OnLowerLayerDown() function is called beforehand + virtual void OnSendResult(bool isSucccess) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/Array.h b/utils/dnp3_src/cpp/libs/include/openpal/container/Array.h new file mode 100644 index 0000000..1e8acb0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/Array.h @@ -0,0 +1,124 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_DYNAMICARRAY_H +#define OPENPAL_DYNAMICARRAY_H + +#include "ArrayView.h" + +#include "openpal/Configure.h" +#include "openpal/util/Uncopyable.h" + +#include +#include + +namespace openpal +{ + +/** +* Template type for a dynamically allocated array +*/ +template +class Array : public HasSize//, private openpal::Uncopyable +{ + +public: + + Array(IndexType size) : + HasSize(size), + buffer(new ValueType[size]()) + {} + + Array() : + HasSize(0), + buffer(nullptr) + {} + + Array(const Array& copy) : + HasSize(copy.Size()), + buffer(new ValueType[copy.Size()]) + { + for(IndexType i = 0; i < copy.Size(); ++i) buffer[i] = copy.buffer[i]; + } + + ArrayView ToView() const + { + return ArrayView(buffer, this->size); + } + + inline bool Contains(IndexType index) const + { + return index < this->size; + } + + inline ValueType& operator[](IndexType index) + { + assert(index < this->size); + return buffer[index]; + } + + const ValueType& operator[](IndexType index) const + { + assert(index < this->size); + return buffer[index]; + } + + template + void foreach(const Action& action) const + { + for(IndexType i = 0; i < this->size; ++i) action(buffer[i]); + } + + template + void foreach(const Action& action) + { + for(IndexType i = 0; i < this->size; ++i) action(buffer[i]); + } + + template + void foreachIndex(const Action& action) + { + for(IndexType i = 0; i < this->size; ++i) action(buffer[i], i); + } + + + template + void foreachIndex(const Action& action) const + { + for(uint32_t i = 0; i < this->size; ++i) action(buffer[i], i); + } + + virtual ~Array() + { + delete[] buffer; + } + +protected: + + ValueType* buffer; + +private: + + Array& operator=(const Array&) = delete; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/ArrayView.h b/utils/dnp3_src/cpp/libs/include/openpal/container/ArrayView.h new file mode 100644 index 0000000..f24f193 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/ArrayView.h @@ -0,0 +1,96 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_ARRAYVIEW_H +#define OPENPAL_ARRAYVIEW_H + +#include "HasSize.h" + +#include + +namespace openpal +{ + +/** +* Acts as a safe facade around an underlying array +*/ +template +class ArrayView : public HasSize +{ + +public: + + static ArrayView Empty() + { + return ArrayView(nullptr, 0); + } + + ArrayView(ValueType* start, IndexType aSize) : HasSize(aSize), buffer(start) + {} + + inline bool Contains(IndexType index) const + { + return index < this->size; + } + + inline bool Contains(IndexType start, IndexType stop) const + { + return (start < stop) && Contains(stop); + } + + inline ValueType& operator[](IndexType index) + { + assert(index < this->size); + return buffer[index]; + } + + inline const ValueType& operator[](IndexType index) const + { + assert(index < this->size); + return buffer[index]; + } + + template + void foreach(const Action& action) + { + for (IndexType i = 0; i < this->size; ++i) + { + action(buffer[i]); + } + } + + template + void foreachIndex(const Action& action) + { + for (IndexType i = 0; i < this->size; ++i) + { + action(buffer[i], i); + } + } + +private: + ValueType* buffer; +}; + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/Buffer.h b/utils/dnp3_src/cpp/libs/include/openpal/container/Buffer.h new file mode 100644 index 0000000..e9706e1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/Buffer.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_BUFFER_H +#define OPENPAL_BUFFER_H + +#include "Array.h" + +#include "openpal/container/WSlice.h" +#include "openpal/container/RSlice.h" + +#include + +namespace openpal +{ + +class Buffer : public Array +{ + +public: + + Buffer(); + + Buffer(uint32_t size); + + // initialize with the exact size and contents of the view + Buffer(const RSlice& input); + + virtual ~Buffer() {} + + RSlice ToRSlice() const; + + WSlice GetWSlice(); + + WSlice GetWSlice(uint32_t maxSize); + + const uint8_t* operator()() const + { + return buffer; + } + + uint8_t* operator()() + { + return buffer; + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/HasSize.h b/utils/dnp3_src/cpp/libs/include/openpal/container/HasSize.h new file mode 100644 index 0000000..13b46eb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/HasSize.h @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_HASSIZE_H +#define OPENPAL_HASSIZE_H + +namespace openpal +{ + +template +class HasSize +{ + +public: + + HasSize(SizeType size_) : size(size_) + {} + + SizeType Size() const + { + return size; + } + + bool IsEmpty() const + { + return size == 0; + } + + bool IsNotEmpty() const + { + return size != 0; + } + +protected: + + SizeType size; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/LinkedList.h b/utils/dnp3_src/cpp/libs/include/openpal/container/LinkedList.h new file mode 100644 index 0000000..2c93521 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/LinkedList.h @@ -0,0 +1,401 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LINKEDLIST_H +#define OPENPAL_LINKEDLIST_H + +#include "ArrayView.h" + +#include "openpal/container/Array.h" + +namespace openpal +{ + +template +class ListNode +{ +public: + ListNode() : value(), prev(nullptr), next(nullptr) + {} + + ValueType value; + +private: + ListNode* prev; + ListNode* next; + + template + friend class LinkedList; + + template + friend class LinkedListIterator; +}; + + +template +class LinkedListIterator +{ +public: + static LinkedListIterator Undefined() + { + return LinkedListIterator(nullptr); + } + + static LinkedListIterator From(ListNode< ValueType>* pStart) + { + return LinkedListIterator(pStart); + } + + + + bool HasNext() const + { + return (pCurrent != nullptr); + } + + ListNode< ValueType>* Next() + { + if (pCurrent == nullptr) + { + return nullptr; + } + else + { + auto pRet = pCurrent; + pCurrent = pCurrent->next; + return pRet; + } + } + + ListNode< ValueType>* Current() + { + return pCurrent; + } + + ValueType* CurrentValue() + { + if (pCurrent) + { + return &pCurrent->value; + } + else + { + return nullptr; + } + } + +private: + + LinkedListIterator(ListNode< ValueType>* pStart) : pCurrent(pStart) + {} + + ListNode* pCurrent; +}; + + +// A container adapter for a -linked list +template +class LinkedList : public HasSize +{ +public: + + typedef LinkedListIterator Iterator; + + LinkedList(IndexType maxSize) : + HasSize(0), + pHead(nullptr), + pTail(nullptr), + pFree(nullptr), + underlying(maxSize) + { + Initialize(); + } + + IndexType Capacity() const + { + return underlying.Size(); + } + + void Clear() + { + if (this->IsNotEmpty()) + { + // link the remaining free list to the end of active list + this->Link(pTail, pFree); + // set the free pointer to the head + pFree = pHead; + pHead = pTail = nullptr; + this->size = 0; + } + } + + inline ListNode* Head() + { + return pHead; + } + + Iterator Iterate() const + { + return Iterator::From(pHead); + } + + template + ListNode* FindFirst(Selector select); + + ListNode* Add(const ValueType& value); + + template + void While(Selector select) + { + auto iter = this->Iterate(); + bool result = true; + while (result && iter.HasNext()) + { + result = select(iter.Next()->value); + } + } + + template + void Foreach(Selector select) + { + auto iter = this->Iterate(); + while (iter.HasNext()) + { + select(iter.Next()->value); + } + } + + template + ListNode* RemoveFirst(Selector select) + { + auto pNode = this->FindFirst(select); + if (pNode) + { + this->Remove(pNode); + } + return pNode; + } + + template + IndexType RemoveAll(Selector match) + { + IndexType count = 0; + + auto iter = this->Iterate(); + auto pCurrent = iter.Next(); + while (pCurrent) + { + if (match(pCurrent->value)) + { + auto pRemoved = pCurrent; + pCurrent = iter.Next(); + this->Remove(pRemoved); + ++count; + } + else + { + pCurrent = iter.Next(); + } + } + + return count; + } + + bool Remove(const ValueType& value) + { + auto iter = this->Iterate(); + while (iter.HasNext()) + { + auto pNode = iter.Next(); + if (pNode->value == value) + { + this->Remove(pNode); + return true; + } + } + return false; + } + + template + ListNode* Insert(const ValueType& value, LessThan lt); + + void Remove(ListNode* apNode); + + inline bool IsFull() const; + +private: + + ListNode* pHead; + ListNode* pTail; + ListNode* pFree; + + Array, IndexType> underlying; + + ListNode* Insert(const ValueType& value, ListNode* left, ListNode* right); + + inline static void Link(ListNode* prev, ListNode* next); + + void Initialize(); +}; + +template +ListNode* LinkedList::Add(const ValueType& value) +{ + return this->Insert(value, pTail, nullptr); +} + + +template +template +ListNode* LinkedList::Insert(const ValueType& value, LessThan lt) +{ + if (pFree == nullptr) + { + return nullptr; + } + else + { + auto query = [lt, value](const ValueType & v) + { + return lt(value, v); + }; + auto pResult = this->FindFirst(query); + if (pResult) + { + return Insert(value, pResult->prev, pResult); + } + else + { + return Insert(value, pTail, nullptr); + } + } +} + +template +ListNode* LinkedList::Insert(const ValueType& value, ListNode* pLeft, ListNode* pRight) +{ + if (pFree == nullptr) + { + return nullptr; + } + else + { + // initialize the new node, and increment the size + auto pNode = pFree; + pFree = pFree->next; + pNode->value = value; + ++(this->size); + + this->Link(pLeft, pNode); + this->Link(pNode, pRight); + + // change of head + if (pLeft == nullptr) + { + pHead = pNode; + } + + // change of tail + if (pRight == nullptr) + { + pTail = pNode; + } + + return pNode; + } +} + +template +template +ListNode* LinkedList::FindFirst(Selector select) +{ + auto iter = this->Iterate(); + while (iter.HasNext()) + { + auto pNode = iter.Next(); + if (select(pNode->value)) + { + return pNode; + } + } + return nullptr; +} + +template +void LinkedList::Remove(ListNode* apNode) +{ + if(apNode->prev == nullptr) // it's the head + { + if (apNode->next == nullptr) + { + pHead = pTail = nullptr; // list is now empty + } + else + { + pHead = apNode->next; // head but not tail + } + } + else + { + if(apNode->next == nullptr) pTail = apNode->prev; // was only the tail + } + + // attach the adjacent nodes to eachother if they exist + Link(apNode->prev, apNode->next); + + // Now that the data list is complete, attach the freed node to the front of the free list + apNode->next = pFree; + if(pFree != nullptr) pFree->prev = apNode; + apNode->prev = nullptr; // it's the head now + pFree = apNode; + --(this->size); +} + +template +bool LinkedList::IsFull() const +{ + return (pFree == nullptr); +} + + + +template +void LinkedList::Link(ListNode* first, ListNode* second) +{ + if(first) first->next = second; + if(second) second->prev = first; +} + +template +void LinkedList::Initialize() +{ + if(underlying.IsNotEmpty()) + { + pFree = &underlying[0]; + for(IndexType i = 1; i < underlying.Size(); ++i) + { + Link(&underlying[i - 1], &underlying[i]); + } + } +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/Pair.h b/utils/dnp3_src/cpp/libs/include/openpal/container/Pair.h new file mode 100644 index 0000000..b7f17ba --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/Pair.h @@ -0,0 +1,42 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_PAIR_H +#define OPENPAL_PAIR_H + +namespace openpal +{ + +template +class Pair +{ + +public: + + Pair(const A& first_, const B& second_) : first(first_), second(second_) + {} + + A first; + B second; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/Queue.h b/utils/dnp3_src/cpp/libs/include/openpal/container/Queue.h new file mode 100644 index 0000000..94667ae --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/Queue.h @@ -0,0 +1,123 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_QUEUE_H +#define OPENPAL_QUEUE_H + +#include + +#include "openpal/container/Array.h" + +namespace openpal +{ + +template +class Queue +{ + +public: + + Queue(IndexType size) : count(0), first(0), nextInsert(0), buffer(size) + {} + + IndexType Size() const + { + return count; + } + + IndexType Capacity() const + { + return buffer.Size(); + } + + bool IsEmpty() const + { + return count == 0; + } + + bool IsNotEmpty() const + { + return count > 0; + } + + bool IsFull() const + { + return count == buffer.Size(); + } + + void Clear() + { + count = first = nextInsert = 0; + } + + ValueType* Peek() + { + if (IsEmpty()) + { + return nullptr; + } + else + { + return &buffer[first]; + } + } + + ValueType* Pop() + { + if (IsEmpty()) + { + return nullptr; + } + else + { + IndexType ret = first; + first = (first + 1) % buffer.Size(); + --count; + return &buffer[ret]; + } + } + + bool Enqueue(const ValueType& value) + { + if (IsFull()) + { + return false; + } + else + { + buffer[nextInsert] = value; + nextInsert = (nextInsert + 1) % buffer.Size(); + ++count; + return true; + } + } + +private: + + IndexType count; + IndexType first; + IndexType nextInsert; + + openpal::Array buffer; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/RSlice.h b/utils/dnp3_src/cpp/libs/include/openpal/container/RSlice.h new file mode 100644 index 0000000..0da2b1c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/RSlice.h @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_RSLICE_H +#define OPENPAL_RSLICE_H + +#include "HasSize.h" + +#include + +namespace openpal +{ + +class WSlice; + +/** +* Represents a readonly slice of a buffer located elsewhere. Mediates reading from the buffer +* to prevent overreads and other errors. +*/ +class RSlice : public HasSize +{ + +public: + + static RSlice Empty(); + + RSlice(); + + RSlice(uint8_t const* pBuffer, uint32_t size); + + void Clear(); + + RSlice CopyTo(WSlice&) const; + + RSlice Take(uint32_t count) const; + + RSlice Skip(uint32_t count) const; + + bool Equals(const RSlice& rhs) const; + + void Advance(uint32_t count); + + operator uint8_t const* () const + { + return pBuffer; + }; + +private: + uint8_t const* pBuffer; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/RingBuffer.h b/utils/dnp3_src/cpp/libs/include/openpal/container/RingBuffer.h new file mode 100644 index 0000000..719f8d7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/RingBuffer.h @@ -0,0 +1,127 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_RINGBUFFER_H +#define OPENPAL_RINGBUFFER_H + +#include + +#include "openpal/container/WSlice.h" +#include "openpal/container/RSlice.h" +#include "openpal/util/Comparisons.h" + +namespace openpal +{ + +/** + A byte-oriented ring buffer. + Interrupt-safe (w/o disabling interrupts) for a single producer + and single consumer, one reading and one writing. + + N must be a power of 2, and is enforced via static assert. +*/ +template +class RingBuffer +{ + static_assert((N > 1) & !(N & (N - 1)), "Should use a power of 2 as template parameter, e.g. 16, 32, 64, 128"); + +public: + + RingBuffer() : head(0), tail(0) {} + + volatile bool Put(uint8_t byteIn) + { + if(Full()) + { + return false; + } + else + { + buffer[(head++) & (N - 1)] = byteIn; + return true; + } + } + + volatile bool Get(uint8_t& byteOut) + { + if(Empty()) + { + return false; + } + else + { + byteOut = buffer[(tail++) & (N - 1)]; + return true; + } + } + + volatile uint8_t GetMany(WSlice& output) + { + uint8_t num = openpal::Min(Count(), output.Size()); + for(uint8_t i = 0; i < num; ++i) + { + output[i] = buffer[(tail++) & (N - 1)]; + } + output.Advance(num); + return num; + } + + volatile uint8_t PutMany(RSlice& input) + { + uint8_t num = openpal::Min(N - Count(), input.Size()); + for(uint8_t i = 0; i < num; ++i) + { + buffer[(head++) & (N - 1)] = input[i]; + } + input.Advance(num); + return num; + } + + volatile inline bool Full() + { + return Count() == N; + } + + volatile inline bool Empty() + { + return Count() == 0; + } + + +private: + + volatile inline uint8_t Count() + { + return head - tail; + } + + uint8_t buffer[N]; + + // these may be changed from another thread or interrupt + volatile uint8_t head; + volatile uint8_t tail; + + RingBuffer(const RingBuffer&) = delete; + RingBuffer& operator= (const RingBuffer&) = delete; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/SecureBuffer.h b/utils/dnp3_src/cpp/libs/include/openpal/container/SecureBuffer.h new file mode 100644 index 0000000..c4c81f6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/SecureBuffer.h @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SECURE_BUFFER_H +#define OPENPAL_SECURE_BUFFER_H + +#include "openpal/container/Buffer.h" + +namespace openpal +{ + +class SecureBuffer final : public Buffer +{ + +public: + + SecureBuffer() : Buffer() {} + + SecureBuffer(uint32_t size) : Buffer(size) {} + + // initialize with the exact size and contents of the view + SecureBuffer(const RSlice& input) : Buffer(input) {} + + ~SecureBuffer() + { + this->GetWSlice().SetAllTo(0x00); + } + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/Settable.h b/utils/dnp3_src/cpp/libs/include/openpal/container/Settable.h new file mode 100644 index 0000000..4bab8db --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/Settable.h @@ -0,0 +1,117 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SETTABLE_H +#define OPENPAL_SETTABLE_H + +namespace openpal +{ + +// utility class for representing a value that may or may not be set +template +class Settable +{ +public: + + Settable() : valueIsSet(false) + {} + + bool IsSet() const + { + return valueIsSet; + } + + bool IsEmpty() const + { + return !valueIsSet; + } + + T Get() const + { + return value; + } + + bool Pop(T& output) + { + if (valueIsSet) + { + valueIsSet = false; + output = value; + return true; + } + else + { + return false; + } + } + + void Clear() + { + valueIsSet = false; + } + + void Set(const T& value_) + { + value = value_; + valueIsSet = true; + } + + template + bool IsSetAnd(Action action); + + template + void Foreach(Action action); + + +private: + + bool valueIsSet; + T value; +}; + +template +template +bool Settable::IsSetAnd(Action action) +{ + if (valueIsSet) + { + return action(value); + } + else + { + return false; + } +} + +template +template +void Settable::Foreach(Action action) +{ + if (valueIsSet) + { + action(value); + } +} + +} + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/StaticBuffer.h b/utils/dnp3_src/cpp/libs/include/openpal/container/StaticBuffer.h new file mode 100644 index 0000000..edac29f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/StaticBuffer.h @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_STATICBUFFER_H +#define OPENPAL_STATICBUFFER_H + +#include "openpal/container/WSlice.h" +#include "openpal/container/RSlice.h" +#include "openpal/util/Comparisons.h" + +#include + +namespace openpal +{ + +template +class StaticBuffer +{ + +public: + + StaticBuffer() + {} + + virtual ~StaticBuffer() {} + + RSlice ToRSlice() const + { + return RSlice(buffer, SIZE); + } + + RSlice ToRSlice(uint32_t maxSize) const + { + return RSlice(buffer, openpal::Min(SIZE, maxSize)); + } + + WSlice GetWSlice() + { + return WSlice(buffer, SIZE); + } + + WSlice GetWSlice(uint32_t maxSize) + { + return WSlice(buffer, openpal::Min(SIZE, maxSize)); + } + + const uint8_t* operator()() const + { + return buffer; + } + + uint8_t* operator()() + { + return buffer; + } + + uint32_t Size() const + { + return SIZE; + } + +private: + uint8_t buffer[SIZE]; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/container/WSlice.h b/utils/dnp3_src/cpp/libs/include/openpal/container/WSlice.h new file mode 100644 index 0000000..84f3253 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/container/WSlice.h @@ -0,0 +1,74 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_WSLICE_H +#define OPENPAL_WSLICE_H + +#include "HasSize.h" + +#include + +namespace openpal +{ + +class RSlice; + +/** +* Represents a write-able slice of a buffer located elsewhere. Mediates writing to the buffer +* to prevent overruns and other errors. +*/ +class WSlice : public HasSize +{ +public: + + static WSlice Empty(); + + void SetAllTo(uint8_t value); + + WSlice(); + WSlice(uint8_t* pBuffer, uint32_t size); + + void Clear(); + + uint32_t Advance(uint32_t count); + + WSlice Skip(uint32_t count) const; + + RSlice ToRSlice() const; + + operator uint8_t* () + { + return pBuffer; + }; + + operator uint8_t const* () const + { + return pBuffer; + }; + +private: + + uint8_t* pBuffer; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/IExecutor.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/IExecutor.h new file mode 100644 index 0000000..1bf3169 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/IExecutor.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_IEXECUTOR_H +#define OPENPAL_IEXECUTOR_H + +#include "ITimer.h" +#include "TimeDuration.h" +#include "IMonotonicTimeSource.h" + +#include + + +namespace openpal +{ + +typedef std::function action_t; + +/** + * Interface for posting events to a queue. Events can be posted for + * immediate consumption or some time in the future. Events are processed + * in the order they are received. + * + */ +class IExecutor : public IMonotonicTimeSource +{ + +public: + + virtual ~IExecutor() {} + + /// @return a new timer based on a relative time duration + virtual ITimer* Start(const TimeDuration& duration, const action_t& action) = 0; + + /// @return a new timer based on an absolute timestamp of the monotonic clock + virtual ITimer* Start(const MonotonicTimestamp& expiration, const action_t& action) = 0; + + /// @return Thread-safe way to post an event to be handled asynchronously + virtual void Post(const action_t& action) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/IMonotonicTimeSource.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/IMonotonicTimeSource.h new file mode 100644 index 0000000..2be0189 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/IMonotonicTimeSource.h @@ -0,0 +1,41 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_IMONOTONICTIMESOURCE_H +#define OPENPAL_IMONOTONICTIMESOURCE_H + +#include "MonotonicTimestamp.h" + +namespace openpal +{ + +class IMonotonicTimeSource +{ +public: + + virtual ~IMonotonicTimeSource() {} + + /// @return a non-absolute timestamp for the monotonic time source + virtual MonotonicTimestamp GetTime() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/ITimer.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/ITimer.h new file mode 100644 index 0000000..ad887f2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/ITimer.h @@ -0,0 +1,42 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_ITIMER_H +#define OPENPAL_ITIMER_H + +#include "MonotonicTimestamp.h" + +namespace openpal +{ + +/** + * Timer are used to defer events for a later time on an executor. + */ +class ITimer +{ +public: + virtual ~ITimer() {} + virtual void Cancel() = 0; + virtual MonotonicTimestamp ExpiresAt() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/IUTCTimeSource.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/IUTCTimeSource.h new file mode 100644 index 0000000..82b0750 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/IUTCTimeSource.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_IUTCTIMESOURCE_H +#define OPENPAL_IUTCTIMESOURCE_H + +#include "UTCTimestamp.h" + +namespace openpal +{ + +/** +* Interface that defines a method to get UTC timestamps +*/ +class IUTCTimeSource +{ + +public: + /** + * Returns a UTCTimestamp of the current time + */ + virtual UTCTimestamp Now() = 0; +}; + +/** +* Mock usable for testing +*/ +class FixedUTCTimeSource : public IUTCTimeSource +{ +public: + FixedUTCTimeSource(int64_t time_): time(time_) + {} + + UTCTimestamp Now() + { + return UTCTimestamp (time); + } + + int64_t time; +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/MonotonicTimestamp.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/MonotonicTimestamp.h new file mode 100644 index 0000000..2d937c9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/MonotonicTimestamp.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_MONOTONICTIMESTAMP_H +#define OPENPAL_MONOTONICTIMESTAMP_H + +#include + +#include "TimeDuration.h" + +namespace openpal +{ + +/** +* Strong typing for millisecond-based monotonic timestamps +*/ +class MonotonicTimestamp +{ + +public: + + static MonotonicTimestamp Max(); + static MonotonicTimestamp Min(); + + bool IsMax() const; + bool IsMin() const; + + MonotonicTimestamp(); + + explicit MonotonicTimestamp(int64_t milliseconds); + + // overflow capped to maximum value + MonotonicTimestamp Add(const TimeDuration& duration) const; + + int64_t milliseconds; +}; + +bool operator==(const MonotonicTimestamp& first, const MonotonicTimestamp& second); +bool operator<(const MonotonicTimestamp& first, const MonotonicTimestamp& second); +bool operator>(const MonotonicTimestamp& first, const MonotonicTimestamp& second); + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/TimeDuration.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/TimeDuration.h new file mode 100644 index 0000000..626ddaf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/TimeDuration.h @@ -0,0 +1,104 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_TIMEDURATION_H +#define OPENPAL_TIMEDURATION_H + +#include + +namespace openpal +{ + +template +class TimeDurationBase +{ + +public: + + TimeDurationBase() : milliseconds(0) + {} + + T GetMilliseconds() const + { + return milliseconds; + } + + bool IsNegative() const + { + return milliseconds < 0; + } + + operator T() const + { + return milliseconds; + } + + T milliseconds; + +protected: + + TimeDurationBase(T milliseconds) : milliseconds(milliseconds) + {} + +}; + + +/** +* Strong typing for millisecond based time durations +*/ +class TimeDuration : public TimeDurationBase +{ + +public: + + TimeDuration(); + + bool IsPostive() const; + + TimeDuration MultiplyBy(int factor) const + { + return TimeDuration(factor * milliseconds); + } + + static TimeDuration Min(); + + static TimeDuration Max(); + + static TimeDuration Zero(); + + static TimeDuration Milliseconds(int64_t milliseconds); + + static TimeDuration Seconds(int64_t seconds); + + static TimeDuration Minutes(int64_t minutes); + + static TimeDuration Hours(int64_t hours); + + static TimeDuration Days(int64_t days); + +private: + TimeDuration(int64_t aMilliseconds); +}; + +bool operator==(const TimeDuration& lhs, const TimeDuration& rhs); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/TimerRef.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/TimerRef.h new file mode 100644 index 0000000..4c8f7b4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/TimerRef.h @@ -0,0 +1,133 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_TIMERREF_H +#define OPENPAL_TIMERREF_H + +#include "openpal/executor/ITimer.h" +#include "openpal/executor/IExecutor.h" +#include "openpal/util/Uncopyable.h" + +namespace openpal +{ + +/** +* A management class to make dealing with timer pointers safer a little safer +* +* Holds an optional pointer to an active ITimer pointer. Acts as a safe proxy for dealing with a recurring timer instance. +*/ +class TimerRef : openpal::Uncopyable +{ + +public: + TimerRef(openpal::IExecutor& executor); + + // automatically cancels any active timers on destructive + ~TimerRef(); + + // Called to see if the timer is currently active + bool IsActive() const; + + // return the expiration time, MonotonticTimestamp::Max() if not active + MonotonicTimestamp ExpiresAt() const; + + // cancels any existing timer, returning true if the timer was active, false otherwise + bool Cancel(); + + // Attempts to start a new timer + // returns false if timer is already active, true otherwise + template + bool Start(const TimeDuration& timeout, const Lambda& action); + + template + bool Start(const MonotonicTimestamp& expiration, const Lambda& action); + + // Start a new timer, canceling any existing timer + template + void Restart(const TimeDuration& expiration, const Lambda& action); + + template + void Restart(const MonotonicTimestamp& expiration, const Lambda& action); + + +private: + + // restart the timer, return false if already active + bool StartAction(const TimeDuration& timeout, const action_t& action); + bool StartAction(const MonotonicTimestamp& expiration, const action_t& action); + + // Start a new timer, canceling any existing timer + void RestartAction(const TimeDuration& expiration, const action_t& action); + void RestartAction(const MonotonicTimestamp& expiration, const action_t& action); + + + IExecutor* pExecutor; + ITimer* pTimer; +}; + +// Attempts to start a new timer +// returns false if timer is already active, true otherwise +template +bool TimerRef::Start(const TimeDuration& timeout, const Lambda& action) +{ + auto proxy = [this, action] + { + pTimer = nullptr; + action(); + }; + return this->StartAction(timeout, proxy); +} + +template +bool TimerRef::Start(const MonotonicTimestamp& expiration, const Lambda& action) +{ + auto proxy = [this, action] + { + pTimer = nullptr; + action(); + }; + return this->StartAction(expiration, proxy); +} + +template +void TimerRef::Restart(const TimeDuration& timeout, const Lambda& action) +{ + auto proxy = [this, action] + { + pTimer = nullptr; + action(); + }; + this->RestartAction(timeout, proxy); +} + +template +void TimerRef::Restart(const MonotonicTimestamp& expiration, const Lambda& action) +{ + auto proxy = [this, action] + { + pTimer = nullptr; + action(); + }; + this->RestartAction(expiration, proxy); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/executor/UTCTimestamp.h b/utils/dnp3_src/cpp/libs/include/openpal/executor/UTCTimestamp.h new file mode 100644 index 0000000..34c4274 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/executor/UTCTimestamp.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_UTCTIMESTAMP_H +#define OPENPAL_UTCTIMESTAMP_H + +#include + +namespace openpal +{ + +/** +* Strong typing for UTCTimestamps +*/ +class UTCTimestamp +{ + +public: + + UTCTimestamp() = default; + + UTCTimestamp(uint64_t msSinceEpoch) : msSinceEpoch(msSinceEpoch) + {} + + uint64_t msSinceEpoch = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/ILogHandler.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/ILogHandler.h new file mode 100644 index 0000000..e309a6e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/ILogHandler.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_ILOGHANDLER_H +#define OPENPAL_ILOGHANDLER_H + +#include "LogEntry.h" + +namespace openpal +{ + +/** +* Callback interface for log messages +*/ +class ILogHandler +{ +public: + virtual ~ILogHandler() {} + + /** + * Callback method for log messages + * + * @param entry the log message to handle + */ + virtual void Log( const LogEntry& entry ) = 0; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/Location.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/Location.h new file mode 100644 index 0000000..c588c0b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/Location.h @@ -0,0 +1,33 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LOCATION_H +#define OPENPAL_LOCATION_H + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#ifndef OPENPAL_SUPPRESS_LOG_LOCATION +#define LOCATION __FILE__ "(" TOSTRING(__LINE__) ")" +#else +#define LOCATION "" +#endif + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/LogEntry.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogEntry.h new file mode 100644 index 0000000..12fb737 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogEntry.h @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LOGENTRY_H +#define OPENPAL_LOGENTRY_H + +#include + +#include "LogFilters.h" +#include "openpal/util/Uncopyable.h" + +namespace openpal +{ + +/** +* An event recorded by the logging framework. +*/ +class LogEntry : openpal::Uncopyable +{ + +public: + + LogEntry() = delete; + + LogEntry(const char* loggerid, const LogFilters& filters, const char* location, const char* message) : + loggerid(loggerid), + filters(filters), + location(location), + message(message) + {} + + + const char* loggerid; + LogFilters filters; + const char* location; + const char* message; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/LogFilters.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogFilters.h new file mode 100644 index 0000000..400069c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogFilters.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LOGFILTERS_H +#define OPENPAL_LOGFILTERS_H + +#include + +namespace openpal +{ + +/** +* Strongly typed wrapper for flags bitfield +*/ +class LogFilters +{ + +public: + + LogFilters() : filters(0) + {} + + LogFilters(int32_t filters_) : filters(filters_) + {} + + inline bool IsSet(int32_t levels) const + { + return (levels & filters) != 0; + } + + bool operator &(const LogFilters& rhs) const + { + return IsSet(rhs.filters); + } + + int32_t GetBitfield() const + { + return filters; + } + +private: + + int32_t filters; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/LogLevels.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogLevels.h new file mode 100644 index 0000000..1e6e4b5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogLevels.h @@ -0,0 +1,61 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef OPENPAL_LOGLEVELS_H +#define OPENPAL_LOGLEVELS_H + +#include + +namespace openpal +{ +// some common log flags +namespace logflags +{ +const int32_t EVENT = 1 << 0; +const int32_t ERR = 1 << 1; +const int32_t WARN = 1 << 2; +const int32_t INFO = 1 << 3; +const int32_t DBG = 1 << 4; +} + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/LogMacros.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogMacros.h new file mode 100644 index 0000000..1c9d958 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/LogMacros.h @@ -0,0 +1,91 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LOGMACROS_H +#define OPENPAL_LOGMACROS_H + +#include "Location.h" + +#ifndef OPENPAL_STRIP_LOGGING + +#include "StringFormatting.h" + +#include + +#ifdef WIN32 +#define SAFE_STRING_FORMAT(dest, size, format, ...) _snprintf_s(dest, size, _TRUNCATE, format, ##__VA_ARGS__) +#else +#define SAFE_STRING_FORMAT(dest, size, format, ...) snprintf(dest, size, format, ##__VA_ARGS__) +#endif + +#ifdef OPENPAL_CUSTOMIZE_LOGGING + +#include "CustomLogMacros.h" + +#else + +#define SIMPLE_LOG_BLOCK(logger, filters, message) \ + if(logger.IsEnabled(filters)){ \ + logger.Log(filters, LOCATION, message); \ + } + +#define SIMPLE_LOGGER_BLOCK(pLogger, filters, message) \ + if(pLogger && pLogger->IsEnabled(filters)){ \ + pLogger->Log(filters, LOCATION, message); \ + } + +#define FORMAT_LOG_BLOCK(logger, filters, format, ...) \ + if(logger.IsEnabled(filters)){ \ + char message[openpal::MAX_LOG_ENTRY_SIZE]; \ + SAFE_STRING_FORMAT(message, openpal::MAX_LOG_ENTRY_SIZE, format, ##__VA_ARGS__); \ + logger.Log(filters, LOCATION, message); \ + } + +#define FORMAT_LOGGER_BLOCK(pLogger, filters, format, ...) \ + if(pLogger && pLogger->IsEnabled(filters)){ \ + char message[openpal::MAX_LOG_ENTRY_SIZE]; \ + SAFE_STRING_FORMAT(message, openpal::MAX_LOG_ENTRY_SIZE, format, ##__VA_ARGS__); \ + pLogger->Log(filters, LOCATION, message); \ + } + +#define FORMAT_HEX_BLOCK(logger, filters, buffer, firstSize, otherSize) \ + if(logger.IsEnabled(filters)){ \ + LogHex(logger, filters, buffer, firstSize, otherSize); \ + } + +#endif + +#else + +#define SAFE_STRING_FORMAT(dest, size, format, ...) + +#define SIMPLE_LOG_BLOCK(logger, filters, message) + +#define SIMPLE_LOGGER_BLOCK(pLogger, filters, message) + +#define FORMAT_LOG_BLOCK(logger, filters, format, ...) + +#define FORMAT_LOGGER_BLOCK(pLogger, filters, format, ...) + +#define FORMAT_HEX_BLOCK(logger, filters, buffer, firstSize, otherSize) + +#endif // end OPENPAL_STRIP_LOGGING + +#endif // end include guards diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/Logger.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/Logger.h new file mode 100644 index 0000000..66c6bc9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/Logger.h @@ -0,0 +1,108 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LOGGER_H +#define OPENPAL_LOGGER_H + +#include "openpal/logging/ILogHandler.h" + +#include +#include + +namespace openpal +{ + + +/** +* A copyable facade over a LogRoot class +*/ +class Logger +{ + +public: + + struct Settings + { + Settings(const std::string& id, openpal::LogFilters levels) : id(id), levels(levels) + {} + + std::string id; + openpal::LogFilters levels; + }; + + Logger(const std::shared_ptr& backend, const std::string& id, openpal::LogFilters levels); + + static Logger Empty() + { + return Logger(nullptr, "", 0); + } + + void Log(const LogFilters& filters, const char* location, const char* message); + + Logger Detach(const std::string& id) const + { + return Logger(this->backend, std::make_shared(id, this->settings->levels)); + } + + Logger Detach(const std::string& id, openpal::LogFilters levels) const + { + return Logger(this->backend, std::make_shared(id, levels)); + } + + Logger Detach(openpal::LogFilters levels) const + { + return Logger(this->backend, std::make_shared(this->settings->id, levels)); + } + + bool IsEnabled(const LogFilters& filters) const; + + LogFilters GetFilters() const + { + return this->settings->levels; + } + + void SetFilters(const openpal::LogFilters& filters) + { + this->settings->levels = filters; + } + + void Rename(const std::string& id) + { + this->settings->id = id; + } + +private: + + Logger(const std::shared_ptr& backend, const std::shared_ptr& settings) : + backend(backend), + settings(settings) + {} + + Logger() = delete; + Logger& operator=(const Logger&) = delete; + + const std::shared_ptr backend; + const std::shared_ptr settings; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/logging/StringFormatting.h b/utils/dnp3_src/cpp/libs/include/openpal/logging/StringFormatting.h new file mode 100644 index 0000000..5558099 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/logging/StringFormatting.h @@ -0,0 +1,42 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_STRINGFORMATTING_H +#define OPENPAL_STRINGFORMATTING_H + +#include "Logger.h" + +namespace openpal +{ +class RSlice; + +const uint32_t MAX_LOG_ENTRY_SIZE = 120; +const uint32_t MAX_HEX_PER_LINE = 20; + +static_assert(MAX_HEX_PER_LINE < (MAX_LOG_ENTRY_SIZE / 3), "Each hex byte takes 3 characters"); + +void LogHex(Logger& logger, const openpal::LogFilters& filters, const openpal::RSlice& source, uint32_t firstRowSize, uint32_t otherRowSize); + +// Portable allocation of a copy of a cstring +char* AllocateCopy(char const* alias); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/ByteSerialization.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/ByteSerialization.h new file mode 100644 index 0000000..d0efaa5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/ByteSerialization.h @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_BYTESERIALIZATION_H +#define OPENPAL_BYTESERIALIZATION_H + +#include +#include + +#include "openpal/container/WSlice.h" +#include "openpal/container/RSlice.h" + +namespace openpal +{ + +class UInt8Simple +{ +public: + + inline static uint8_t Read(const uint8_t* pStart) + { + return (*pStart); + } + + inline static uint8_t ReadBuffer(RSlice& buffer) + { + auto ret = Read(buffer); + buffer.Advance(SIZE); + return ret; + } + + static void WriteBuffer(WSlice& buffer, uint8_t value) + { + Write(buffer, value); + buffer.Advance(SIZE); + } + + inline static void Write(uint8_t* pStart, uint8_t value) + { + *(pStart) = value; + } + + const static size_t SIZE = 1; + const static uint8_t Max; + const static uint8_t Min; + + typedef uint8_t Type; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/DoubleFloat.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/DoubleFloat.h new file mode 100644 index 0000000..1d018b7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/DoubleFloat.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_DOUBLE_FLOAT_H +#define OPENPAL_DOUBLE_FLOAT_H + +#include "openpal/util/Uncopyable.h" +#include "openpal/container/RSlice.h" +#include "openpal/container/WSlice.h" + +#include + +namespace openpal +{ + +class DoubleFloat : private StaticOnly +{ +public: + + static_assert(sizeof(double) == 8, "Unexpected size of double float"); + + typedef double Type; + + static double ReadBuffer(RSlice& buffer); + static void WriteBuffer(WSlice& buffer, double value); + + static double Read(const uint8_t* data); + static void Write(uint8_t* data, double value); + + const static std::size_t SIZE = sizeof(double); + const static double Max; + const static double Min; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/FloatByteOrder.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/FloatByteOrder.h new file mode 100644 index 0000000..44a1081 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/FloatByteOrder.h @@ -0,0 +1,53 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_FLOAT_BYTE_ORDER_H +#define OPENPAL_FLOAT_BYTE_ORDER_H + +#include "openpal/util/Uncopyable.h" + +#include + +namespace openpal +{ + +struct FloatByteOrder : private StaticOnly +{ + enum class Value : uint8_t + { + NORMAL, + REVERSE, + UNSUPPORTED + }; + + static const Value ORDER; + +private: + + static Value GetByteOrder(); + + static bool IsNormalByteOrder(); + static bool IsReverseByteOrder(); + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/Format.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Format.h new file mode 100644 index 0000000..1e73c1c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Format.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_FORMAT_H +#define OPENPAL_FORMAT_H + +#include "openpal/serialization/UInt48Type.h" +#include "openpal/container/WSlice.h" +#include "openpal/util/Uncopyable.h" + +namespace openpal +{ +class Format : private StaticOnly +{ +public: + + static bool Write(WSlice& dest, const uint8_t& value); + static bool Write(WSlice& dest, const uint16_t& value); + + static bool Write(WSlice& dest, const uint32_t& value); + static bool Write(WSlice& dest, const UInt48Type& value); + + static bool Write(WSlice& dest, const int16_t& value); + static bool Write(WSlice& dest, const int32_t& value); + + static bool Write(WSlice& dest, const double& value); + static bool Write(WSlice& dest, const float& value); + + template + static bool Many(WSlice& dest, const T& value, const Args& ... args) + { + return Write(dest, value) && Many(dest, args...); + } + +private: + + static bool Many(WSlice& input) + { + return true; + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/Parse.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Parse.h new file mode 100644 index 0000000..3bb314c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Parse.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_PARSE_H +#define OPENPAL_PARSE_H + +#include "openpal/serialization/UInt48Type.h" +#include "openpal/container/RSlice.h" +#include "openpal/util/Uncopyable.h" + +namespace openpal +{ +class Parse : private StaticOnly +{ +public: + + static bool Read(RSlice& input, uint8_t& output); + static bool Read(RSlice& input, uint16_t& output); + + static bool Read(RSlice& input, uint32_t& output); + static bool Read(RSlice& input, UInt48Type& output); + + static bool Read(RSlice& input, int16_t& output); + static bool Read(RSlice& input, int32_t& output); + + + static bool Read(RSlice& input, double& output); + static bool Read(RSlice& input, float& output); + + template + static bool Many(RSlice& input, T& output, Args& ... args) + { + return Read(input, output) && Many(input, args...); + } + +private: + + static bool Many(RSlice& input) + { + return true; + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/Serialization.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Serialization.h new file mode 100644 index 0000000..00cb099 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Serialization.h @@ -0,0 +1,44 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SERIALIZATION_H +#define OPENPAL_SERIALIZATION_H + +#include "UInt48LE.h" +#include "SerializationTemplatesLE.h" +#include "ByteSerialization.h" + +#include "SingleFloat.h" +#include "DoubleFloat.h" + +namespace openpal +{ + +typedef Bit16LE Int16; +typedef Bit16LE UInt16; +typedef Bit32LE Int32; +typedef Bit32LE UInt32; +typedef UInt48LE UInt48; +typedef UInt8Simple UInt8; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/SerializationTemplatesLE.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/SerializationTemplatesLE.h new file mode 100644 index 0000000..67de71c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/SerializationTemplatesLE.h @@ -0,0 +1,131 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SERIALIZATIONTEMPLATESLE_H +#define OPENPAL_SERIALIZATIONTEMPLATESLE_H + +#include +#include + +#include "openpal/container/RSlice.h" +#include "openpal/container/WSlice.h" + +#include "openpal/util/Limits.h" + +namespace openpal +{ + +template +class Bit16LE +{ +public: + + static T Read(const uint8_t* data) + { + return (static_cast(data[0]) << 0) | (static_cast(data[1]) << 8); + } + + static void Write(uint8_t* data, T value) + { + data[0] = static_cast(value & 0xFF); + data[1] = static_cast((value >> 8) & 0xFF); + } + + static void WriteBuffer(WSlice& buffer, T aValue) + { + Write(buffer, aValue); + buffer.Advance(SIZE); + } + + inline static T ReadBuffer(RSlice& arBuffer) + { + auto ret = Read(arBuffer); + arBuffer.Advance(SIZE); + return ret; + } + + typedef T Type; + + const static size_t SIZE = sizeof(T); + const static T Max; + const static T Min; +}; + +template +const T Bit16LE::Max = openpal::MaxValue(); + +template +const T Bit16LE::Min = openpal::MinValue(); + +template +class Bit32LE +{ +public: + + // Endianness doesn't apply to everything. If you do bitwise or bitshift operations on an int, you don't notice the endianness. + // The machine arranges the multiple bytes, so the least significant byte is still the least significant byte, and the most + // significant byte is still the most significant byte + + // This is endian independent of the machine order + static T Read(const uint8_t* data) + { + return (static_cast(data[0]) << 0) | + (static_cast(data[1]) << 8) | + (static_cast(data[2]) << 16) | + (static_cast(data[3]) << 24); + } + + static void Write(uint8_t* data, T value) + { + data[0] = static_cast(value & 0xFF); + data[1] = static_cast((value >> 8) & 0xFF); + data[2] = static_cast((value >> 16) & 0xFF); + data[3] = static_cast((value >> 24) & 0xFF); + } + + static void WriteBuffer(WSlice& buffer, T aValue) + { + Write(buffer, aValue); + buffer.Advance(SIZE); + } + + inline static T ReadBuffer(RSlice& buffer) + { + auto ret = Read(buffer); + buffer.Advance(SIZE); + return ret; + } + + typedef T Type; + + const static size_t SIZE = sizeof(T); + const static T Max; + const static T Min; +}; + +template +const T Bit32LE::Max = openpal::MaxValue(); + +template +const T Bit32LE::Min = openpal::MinValue(); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/Serializer.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Serializer.h new file mode 100644 index 0000000..9df3a6b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/Serializer.h @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SERIALIZER_H +#define OPENPAL_SERIALIZER_H + +#include + +#include "openpal/container/RSlice.h" +#include "openpal/container/WSlice.h" + +namespace openpal +{ + +template +class Serializer +{ +public: + + typedef bool (*ReadFunc)(RSlice& buffer, T& output); + typedef bool (*WriteFunc)(const T& value, WSlice& buffer); + + Serializer() : size(0), pReadFunc(nullptr), pWriteFunc(nullptr) + {} + + Serializer(uint32_t size_, ReadFunc pReadFunc_, WriteFunc pWriteFunc_) : + size(size_), pReadFunc(pReadFunc_), pWriteFunc(pWriteFunc_) + {} + + /** + * @return The size (in bytes) required for every call to read/write + */ + uint32_t Size() const + { + return size; + } + + /** + * reads the value and advances the read buffer + */ + bool Read(RSlice& buffer, T& output) const + { + return (*pReadFunc)(buffer, output); + } + + /** + * writes the value and advances the write buffer + */ + bool Write(const T& value, WSlice& buffer) const + { + return (*pWriteFunc)(value, buffer); + } + +private: + + uint32_t size; + ReadFunc pReadFunc; + WriteFunc pWriteFunc; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/SingleFloat.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/SingleFloat.h new file mode 100644 index 0000000..d8f9849 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/SingleFloat.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SINGLE_FLOAT_H +#define OPENPAL_SINGLE_FLOAT_H + +#include "openpal/util/Uncopyable.h" +#include "openpal/container/RSlice.h" +#include "openpal/container/WSlice.h" + +#include + +namespace openpal +{ + +class SingleFloat : private StaticOnly +{ +public: + + static_assert(sizeof(float) == 4, "Unexpected size of single float"); + + typedef float Type; + + static float ReadBuffer(RSlice& buffer); + static void WriteBuffer(WSlice& buffer, float value); + + static float Read(const uint8_t* data); + static void Write(uint8_t* data, float value); + + const static std::size_t SIZE = sizeof(float); + const static float Max; + const static float Min; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48LE.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48LE.h new file mode 100644 index 0000000..1eeb0c4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48LE.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_UINT48LE_H +#define OPENPAL_UINT48LE_H + +#include +#include + +#include "UInt48Type.h" + +#include "openpal/container/WSlice.h" +#include "openpal/container/RSlice.h" + +namespace openpal +{ + +class UInt48LE +{ +public: + + static UInt48Type Read(const uint8_t* data); + + static void Write(uint8_t* data, UInt48Type value); + + inline static UInt48Type ReadBuffer(RSlice& buffer) + { + auto ret = Read(buffer); + buffer.Advance(SIZE); + return ret; + } + + static void WriteBuffer(WSlice& buffer, UInt48Type value) + { + Write(buffer, value); + buffer.Advance(SIZE); + } + + const static int64_t MAX = 281474976710655ULL; // 2^48 -1 + const static size_t SIZE = 6; + typedef UInt48Type Type; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48Type.h b/utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48Type.h new file mode 100644 index 0000000..f5977ef --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/serialization/UInt48Type.h @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_UINT48TYPE_H +#define OPENPAL_UINT48TYPE_H + +#include + +namespace openpal +{ + +class UInt48Type +{ + +public: + + explicit UInt48Type(int64_t value) : value(value) + {} + + UInt48Type() : value(0) + {} + + operator int64_t() const + { + return value; + } + + int64_t value; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/util/Comparisons.h b/utils/dnp3_src/cpp/libs/include/openpal/util/Comparisons.h new file mode 100644 index 0000000..e12c53d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/util/Comparisons.h @@ -0,0 +1,61 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_COMPARISONS_H +#define OPENPAL_COMPARISONS_H + +namespace openpal +{ + +template +inline T Min(T a, T b) +{ + return (a < b) ? a : b; +} + +template +inline T Max(T a, T b) +{ + return (a > b) ? a : b; +} + +template +inline T Bounded(T value, T min, T max) +{ + return Min(Max(value, min), max); +} + +template +inline bool WithinLimits(T value, T min, T max) +{ + return (value >= min) && (value <= max); +} + +template +bool FloatEqual(T a, T b, T eapllon = 1e-6) +{ + T diff = a - b; + if(diff < 0) diff = -diff; + return diff <= eapllon; +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/util/Finally.h b/utils/dnp3_src/cpp/libs/include/openpal/util/Finally.h new file mode 100644 index 0000000..98c2251 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/util/Finally.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_FINALLY_H +#define OPENPAL_FINALLY_H + +#include "Uncopyable.h" + +namespace openpal +{ + +template +class RAII; + +template +RAII Finally(const Cleanup&); + +/** Finally is an RAII helper that takes a functor to run when it destructs +*/ +template +class RAII +{ +public: + friend RAII Finally(const Cleanup& fun); + + ~RAII() + { + fun(); + } + +private: + + RAII() = delete; + + RAII(const Cleanup& fun_) : fun(fun_) {} + + Cleanup fun; +}; + +template +RAII Finally(const Cleanup& fun) +{ + return RAII(fun); +} + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/include/openpal/util/Limits.h b/utils/dnp3_src/cpp/libs/include/openpal/util/Limits.h new file mode 100644 index 0000000..61d61e8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/util/Limits.h @@ -0,0 +1,35 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_LIMITS_H +#define OPENPAL_LIMITS_H + +namespace openpal +{ + +template +T MinValue(); + +template +T MaxValue(); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/util/SequenceNum.h b/utils/dnp3_src/cpp/libs/include/openpal/util/SequenceNum.h new file mode 100644 index 0000000..560d249 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/util/SequenceNum.h @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_SEQUENCENUM_H +#define OPENPAL_SEQUENCENUM_H + +namespace openpal +{ + +/** represents a sequence number +*/ +template +class SequenceNum +{ + inline static T Next(T seq) + { + return (seq + 1) % Modulus; + } + +public: + + uint8_t Get() const + { + return this->seq; + } + + operator uint8_t() const + { + return this->seq; + } + + SequenceNum() : seq(0) + {} + + SequenceNum(T value) : seq(value) + {} + + bool Equals(T other) const + { + return other == this->seq; + } + + void Increment() + { + this->seq = Next(this->seq); + } + + void Reset() + { + this->seq = 0; + } + + SequenceNum Next() const + { + return SequenceNum(Next(seq)); + } + +protected: + + T seq; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/util/ToHex.h b/utils/dnp3_src/cpp/libs/include/openpal/util/ToHex.h new file mode 100644 index 0000000..8793388 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/util/ToHex.h @@ -0,0 +1,33 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_TOHEX_H +#define OPENPAL_TOHEX_H + +#include + +namespace openpal +{ + +char ToHexChar(char c); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/include/openpal/util/Uncopyable.h b/utils/dnp3_src/cpp/libs/include/openpal/util/Uncopyable.h new file mode 100644 index 0000000..d64fe8a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/include/openpal/util/Uncopyable.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENPAL_UNCOPYABLE_H +#define OPENPAL_UNCOPYABLE_H + +namespace openpal +{ + +/** Inherited classes will not have default copy/assignment. +*/ +class Uncopyable +{ +protected: + Uncopyable() {} //allow construction/destruction + ~Uncopyable() {} + +private: + // prevent these functions + Uncopyable(const Uncopyable&) = delete; + Uncopyable& operator=(const Uncopyable&) = delete; +}; + +class StaticOnly +{ + +private: + // prevent these functions + StaticOnly() = delete; + StaticOnly(const StaticOnly&) = delete; + StaticOnly& operator=(const StaticOnly&) = delete; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/ConsoleLogger.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/ConsoleLogger.cpp new file mode 100644 index 0000000..caec321 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/ConsoleLogger.cpp @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiodnp3/ConsoleLogger.h" + +#include +#include +#include +#include + +#include + +using namespace std; +using namespace opendnp3; +using namespace std::chrono; + +namespace asiodnp3 +{ + +void ConsoleLogger::Log(const openpal::LogEntry& entry) +{ + auto time = std::chrono::high_resolution_clock::now(); + auto num = duration_cast(time.time_since_epoch()).count(); + + ostringstream oss; + + oss << "ms(" << num << ") " << LogFlagToString(entry.filters.GetBitfield()); + oss << " " << entry.loggerid; + if (printLocation) + { + oss << " - " << entry.location; + } + oss << " - " << entry.message; + + std::unique_lock lock(mutex); + std::cout << oss.str() << std::endl; +} + +} //end ns + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.cpp new file mode 100644 index 0000000..6d82632 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.cpp @@ -0,0 +1,46 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "Conversions.h" + +namespace asiodnp3 +{ + +opendnp3::HeaderBuilderT ConvertToLambda(const std::vector& headers) +{ + return[headers](opendnp3::HeaderWriter & writer) -> bool + { + + for (auto& header : headers) + { + if (!header.WriteTo(writer)) + { + return false; + } + } + + return true; + }; +} + +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.h new file mode 100644 index 0000000..c647e8c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/Conversions.h @@ -0,0 +1,38 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_CONVERSIONS_H +#define ASIODNP3_CONVERSIONS_H + +#include + +#include + +#include "opendnp3/master/HeaderTypes.h" + +namespace asiodnp3 +{ + +opendnp3::HeaderBuilderT ConvertToLambda(const std::vector& headers); + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.cpp new file mode 100644 index 0000000..85ef6d2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.cpp @@ -0,0 +1,150 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "DNP3Channel.h" + +#include +#include + +#include "MasterStack.h" +#include "OutstationStack.h" + +using namespace openpal; +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +DNP3Channel::DNP3Channel( + const Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager) : + + logger(logger), + executor(executor), + iohandler(iohandler), + manager(manager), + resources(ResourceManager::Create()) +{ + +} + +DNP3Channel::~DNP3Channel() +{ + this->ShutdownImpl(); +} + +// comes from the outside, so we need to post +void DNP3Channel::Shutdown() +{ + auto shutdown = [self = shared_from_this()]() + { + self->ShutdownImpl(); + }; + + this->executor->BlockUntilAndFlush(shutdown); +} + +void DNP3Channel::ShutdownImpl() +{ + if (!this->resources) return; + + // shutdown the IO handler + this->iohandler->Shutdown(); + this->iohandler.reset(); + + // shutdown any remaining stacks + this->resources->Shutdown(); + this->resources.reset(); + + // posting ensures that we run this after + // and callbacks created by calls above + auto detach = [self = shared_from_this()] + { + self->manager->Detach(self); + self->manager.reset(); + }; + + this->executor->strand.post(detach); +} + +LinkStatistics DNP3Channel::GetStatistics() +{ + auto get = [this]() + { + return this->iohandler->Statistics(); + }; + return this->executor->ReturnFrom(get); +} + +LogFilters DNP3Channel::GetLogFilters() const +{ + auto get = [this]() + { + return this->logger.GetFilters(); + }; + return this->executor->ReturnFrom(get); +} + +void DNP3Channel::SetLogFilters(const LogFilters& filters) +{ + auto set = [self = this->shared_from_this(), filters]() + { + self->logger.SetFilters(filters); + }; + this->executor->strand.post(set); +} + +std::shared_ptr DNP3Channel::AddMaster(const std::string& id, std::shared_ptr SOEHandler, std::shared_ptr application, const MasterStackConfig& config) +{ + auto stack = MasterStack::Create(this->logger.Detach(id), this->executor, SOEHandler, application, this->iohandler, this->resources, config, this->iohandler->TaskLock()); + + return this->AddStack(config.link, stack); + +} + +std::shared_ptr DNP3Channel::AddOutstation(const std::string& id, std::shared_ptr commandHandler, std::shared_ptr application, const OutstationStackConfig& config) +{ + auto stack = OutstationStack::Create(this->logger.Detach(id), this->executor, commandHandler, application, this->iohandler, this->resources, config); + + return this->AddStack(config.link, stack); +} + +template +std::shared_ptr DNP3Channel::AddStack(const LinkConfig& link, const std::shared_ptr& stack) +{ + + auto create = [stack, route = Route(link.RemoteAddr, link.LocalAddr), self = this->shared_from_this()]() + { + + auto add = [stack, route, self]() -> bool + { + return self->iohandler->AddContext(stack, route); + }; + + return self->executor->ReturnFrom(add) ? stack : nullptr; + }; + + return this->resources->Bind(create); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.h new file mode 100644 index 0000000..93ef4bb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Channel.h @@ -0,0 +1,97 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_DNP3CHANNEL_H +#define ASIODNP3_DNP3CHANNEL_H + + +#include "asiodnp3/IChannel.h" +#include "asiodnp3/IOHandler.h" +#include "asiopal/ResourceManager.h" +#include "opendnp3/master/MultidropTaskLock.h" + +namespace asiodnp3 +{ + +class DNP3Channel final : public IChannel, public std::enable_shared_from_this +{ + +public: + + DNP3Channel( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager + ); + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager) + { + return std::make_shared(logger, executor, iohandler, manager); + } + + ~DNP3Channel(); + + // ----------------------- Implement IChannel ----------------------- + + void Shutdown() override; + + virtual opendnp3::LinkStatistics GetStatistics() override; + + virtual openpal::LogFilters GetLogFilters() const override; + + virtual void SetLogFilters(const openpal::LogFilters& filters) override; + + virtual std::shared_ptr AddMaster(const std::string& id, + std::shared_ptr SOEHandler, + std::shared_ptr application, + const MasterStackConfig& config) override; + + + + virtual std::shared_ptr AddOutstation(const std::string& id, + std::shared_ptr commandHandler, + std::shared_ptr application, + const OutstationStackConfig& config) override; + +private: + + void ShutdownImpl(); + + // ----- generic method for adding a stack ------ + template + std::shared_ptr AddStack(const opendnp3::LinkConfig& link, const std::shared_ptr& stack); + + openpal::Logger logger; + const std::shared_ptr executor; + + std::shared_ptr iohandler; + std::shared_ptr manager; + std::shared_ptr resources; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Manager.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Manager.cpp new file mode 100644 index 0000000..e6d0a3e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3Manager.cpp @@ -0,0 +1,129 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiodnp3/DNP3Manager.h" + +#include "asiodnp3/DNP3ManagerImpl.h" + +namespace asiodnp3 +{ + +DNP3Manager::DNP3Manager( + uint32_t concurrencyHint, + std::shared_ptr handler, + std::function onThreadStart, + std::function onThreadExit) : + impl(std::make_unique(concurrencyHint, handler, onThreadStart, onThreadExit)) +{ + +} + +DNP3Manager::~DNP3Manager() +{} + +void DNP3Manager::Shutdown() +{ + impl->Shutdown(); +} + +std::shared_ptr DNP3Manager::AddTCPClient( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + std::shared_ptr listener) +{ + return this->impl->AddTCPClient(id, levels, retry, host, local, port, listener); +} + +std::shared_ptr DNP3Manager::AddTCPServer( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + std::shared_ptr listener) +{ + return this->impl->AddTCPServer(id, levels, retry, endpoint, port, listener); +} + +std::shared_ptr DNP3Manager::AddSerial( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + asiopal::SerialSettings settings, + std::shared_ptr listener) +{ + return this->impl->AddSerial(id, levels, retry, settings, listener); +} + +std::shared_ptr DNP3Manager::AddTLSClient( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + const asiopal::TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec) +{ + return this->impl->AddTLSClient(id, levels, retry, host, local, port, config, listener, ec); +} + +std::shared_ptr DNP3Manager::AddTLSServer( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + const asiopal::TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec) +{ + return this->impl->AddTLSServer(id, levels, retry, endpoint, port, config, listener, ec); +} + +std::shared_ptr DNP3Manager::CreateListener( + std::string loggerid, + openpal::LogFilters loglevel, + asiopal::IPEndpoint endpoint, + std::shared_ptr callbacks, + std::error_code& ec +) +{ + return impl->CreateListener(loggerid, loglevel, endpoint, callbacks, ec); +} + +std::shared_ptr DNP3Manager::CreateListener( + std::string loggerid, + openpal::LogFilters loglevel, + asiopal::IPEndpoint endpoint, + const asiopal::TLSConfig& config, + std::shared_ptr callbacks, + std::error_code& ec +) +{ + return impl->CreateListener(loggerid, loglevel, endpoint, config, callbacks, ec); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.cpp new file mode 100644 index 0000000..05deb23 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.cpp @@ -0,0 +1,275 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "DNP3ManagerImpl.h" + +#include + +#ifdef OPENDNP3_USE_TLS +#include "asiodnp3/tls/MasterTLSServer.h" +#include "asiodnp3/tls/TLSClientIOHandler.h" +#include "asiodnp3/tls/TLSServerIOHandler.h" +#endif + +#include "asiodnp3/ErrorCodes.h" +#include "asiodnp3/DNP3Channel.h" +#include "asiodnp3/MasterTCPServer.h" +#include "asiodnp3/TCPClientIOHandler.h" +#include "asiodnp3/TCPServerIOHandler.h" +#include "asiodnp3/SerialIOHandler.h" + +using namespace openpal; +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +DNP3ManagerImpl::DNP3ManagerImpl( + uint32_t concurrencyHint, + std::shared_ptr handler, + std::function onThreadStart, + std::function onThreadExit +) : + logger(handler, "manager", opendnp3::levels::ALL), + io(std::make_shared()), + threadpool(logger, io, concurrencyHint, onThreadStart, onThreadExit), + resources(ResourceManager::Create()) +{} + +DNP3ManagerImpl::~DNP3ManagerImpl() +{ + this->Shutdown(); +} + +void DNP3ManagerImpl::Shutdown() +{ + if (resources) + { + resources->Shutdown(); + resources.reset(); + } +} + +std::shared_ptr DNP3ManagerImpl::AddTCPClient( + const std::string& id, + uint32_t levels, + const ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + std::shared_ptr listener) +{ + auto create = [&]() -> std::shared_ptr + { + auto clogger = this->logger.Detach(id, levels); + auto executor = Executor::Create(this->io); + auto iohandler = TCPClientIOHandler::Create(clogger, listener, executor, retry, IPEndpoint(host, port), local); + return DNP3Channel::Create(clogger, executor, iohandler, this->resources); + }; + + return this->resources->Bind(create); +} + +std::shared_ptr DNP3ManagerImpl::AddTCPServer( + const std::string& id, + uint32_t levels, + const ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + std::shared_ptr listener) +{ + auto create = [&]() -> std::shared_ptr + { + std::error_code ec; + auto clogger = this->logger.Detach(id, levels); + auto executor = Executor::Create(this->io); + auto iohandler = TCPServerIOHandler::Create(clogger, listener, executor, IPEndpoint(endpoint, port), ec); + return ec ? nullptr : DNP3Channel::Create(clogger, executor, iohandler, this->resources); + }; + + return this->resources->Bind(create); +} + +std::shared_ptr DNP3ManagerImpl::AddSerial( + const std::string& id, + uint32_t levels, + const ChannelRetry& retry, + SerialSettings settings, + std::shared_ptr listener) +{ + auto create = [&]() -> std::shared_ptr + { + auto clogger = this->logger.Detach(id, levels); + auto executor = Executor::Create(this->io); + auto iohandler = SerialIOHandler::Create(clogger, listener, executor, retry, settings); + return DNP3Channel::Create(clogger, executor, iohandler, this->resources); + }; + + return this->resources->Bind(create); +} + +std::shared_ptr DNP3ManagerImpl::AddTLSClient( + const std::string& id, + uint32_t levels, + const ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + const TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec) +{ + +#ifdef OPENDNP3_USE_TLS + auto create = [&]() -> std::shared_ptr + { + auto clogger = this->logger.Detach(id, levels); + auto executor = Executor::Create(this->io); + auto iohandler = TLSClientIOHandler::Create(clogger, listener, executor, config, retry, IPEndpoint(host, port), local); + return DNP3Channel::Create(clogger, executor, iohandler, this->resources); + }; + + auto channel = this->resources->Bind(create); + + if (!channel) + { + ec = Error::SHUTTING_DOWN; + } + + return channel; +#else + ec = Error::NO_TLS_SUPPORT; + return nullptr; +#endif + +} + +std::shared_ptr DNP3ManagerImpl::AddTLSServer( + const std::string& id, + uint32_t levels, + const ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + const TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec) +{ + +#ifdef OPENDNP3_USE_TLS + auto create = [&]() -> std::shared_ptr + { + std::error_code ec; + auto clogger = this->logger.Detach(id, levels); + auto executor = Executor::Create(this->io); + auto iohandler = TLSServerIOHandler::Create(clogger, listener, executor, IPEndpoint(endpoint, port), config, ec); + return ec ? nullptr : DNP3Channel::Create(clogger, executor, iohandler, this->resources); + }; + + auto channel = this->resources->Bind(create); + + if (!channel) + { + ec = Error::SHUTTING_DOWN; + } + + return channel; + +#else + ec = Error::NO_TLS_SUPPORT; + return nullptr; +#endif + +} + +std::shared_ptr DNP3ManagerImpl::CreateListener( + std::string loggerid, + openpal::LogFilters levels, + asiopal::IPEndpoint endpoint, + const std::shared_ptr& callbacks, + std::error_code& ec) +{ + auto create = [&]() -> std::shared_ptr + { + return asiodnp3::MasterTCPServer::Create( + this->logger.Detach(loggerid, levels), + asiopal::Executor::Create(this->io), + endpoint, + callbacks, + this->resources, + ec + ); + }; + + auto listener = this->resources->Bind(create); + + if (!listener) + { + ec = Error::SHUTTING_DOWN; + } + + return listener; +} + +std::shared_ptr DNP3ManagerImpl::CreateListener( + std::string loggerid, + openpal::LogFilters levels, + asiopal::IPEndpoint endpoint, + const asiopal::TLSConfig& config, + const std::shared_ptr& callbacks, + std::error_code& ec) +{ + +#ifdef OPENDNP3_USE_TLS + + auto create = [&]() -> std::shared_ptr + { + return asiodnp3::MasterTLSServer::Create( + this->logger.Detach(loggerid, levels), + asiopal::Executor::Create(this->io), + endpoint, + config, + callbacks, + this->resources, + ec + ); + }; + + auto listener = this->resources->Bind(create); + + if (!listener) + { + ec = Error::SHUTTING_DOWN; + } + + return listener; + +#else + + ec = Error::NO_TLS_SUPPORT; + return nullptr; + +#endif + +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.h new file mode 100644 index 0000000..fff3e80 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DNP3ManagerImpl.h @@ -0,0 +1,135 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIODNP3_DNP3MANAGERIMPL_H +#define ASIODNP3_DNP3MANAGERIMPL_H + +#include "openpal/logging/Logger.h" +#include "openpal/util/Uncopyable.h" + +#include "asiopal/ThreadPool.h" +#include "asiopal/SerialTypes.h" +#include "asiopal/TLSConfig.h" +#include "asiopal/ChannelRetry.h" +#include "asiopal/ResourceManager.h" +#include "asiopal/IListener.h" +#include "asiopal/IPEndpoint.h" + +#include "opendnp3/LogLevels.h" + +#include "asiodnp3/IChannel.h" +#include "asiodnp3/IChannelListener.h" +#include "asiodnp3/IListenCallbacks.h" + + +namespace asiodnp3 +{ + +class DNP3ManagerImpl : private openpal::Uncopyable +{ + +public: + + DNP3ManagerImpl( + uint32_t concurrencyHint, + std::shared_ptr handler, + std::function onThreadStart, + std::function onThreadExit + ); + + ~DNP3ManagerImpl(); + + void Shutdown(); + + std::shared_ptr AddTCPClient( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + std::shared_ptr listener); + + std::shared_ptr AddTCPServer( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + std::shared_ptr listener); + + std::shared_ptr AddSerial( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + asiopal::SerialSettings settings, + std::shared_ptr listener); + + std::shared_ptr AddTLSClient( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& host, + const std::string& local, + uint16_t port, + const asiopal::TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec); + + std::shared_ptr AddTLSServer( + const std::string& id, + uint32_t levels, + const asiopal::ChannelRetry& retry, + const std::string& endpoint, + uint16_t port, + const asiopal::TLSConfig& config, + std::shared_ptr listener, + std::error_code& ec); + + std::shared_ptr CreateListener( + std::string loggerid, + openpal::LogFilters loglevel, + asiopal::IPEndpoint endpoint, + const std::shared_ptr& callbacks, + std::error_code& ec + ); + + std::shared_ptr CreateListener( + std::string loggerid, + openpal::LogFilters loglevel, + asiopal::IPEndpoint endpoint, + const asiopal::TLSConfig& config, + const std::shared_ptr& callbacks, + std::error_code& ec + ); + +private: + + openpal::Logger logger; + const std::shared_ptr io; + asiopal::ThreadPool threadpool; + std::shared_ptr resources; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultListenCallbacks.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultListenCallbacks.cpp new file mode 100644 index 0000000..9cdf831 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultListenCallbacks.cpp @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiodnp3/DefaultListenCallbacks.h" + +namespace asiodnp3 +{ + +DefaultListenCallbacks::DefaultListenCallbacks() +{} + + +bool DefaultListenCallbacks::AcceptConnection(uint64_t sessionid, const std::string& ipaddress) +{ + return true; +} + +bool DefaultListenCallbacks::AcceptCertificate(uint64_t sessionid, const X509Info& info) +{ + return true; +} + +openpal::TimeDuration DefaultListenCallbacks::GetFirstFrameTimeout() +{ + return openpal::TimeDuration::Seconds(30); +} + +void DefaultListenCallbacks::OnFirstFrame(uint64_t sessionid, const opendnp3::LinkHeaderFields& header, ISessionAcceptor& acceptor) +{ + MasterStackConfig config; + + // full implementations will look up config information for the SRC address + + config.link.LocalAddr = header.dest; + config.link.RemoteAddr = header.src; + + auto soe = std::make_shared(); + auto app = std::make_shared(); + + // full implementations will keep a std::shared_ptr somewhere + auto master = acceptor.AcceptSession(SessionIdToString(sessionid), soe, app, config); +} + +void DefaultListenCallbacks::OnConnectionClose(uint64_t sessionid, const std::shared_ptr& session) +{ + // full implementations would drop any references they're holding to this session + // shared_ptr can be used with == operator also +} + +void DefaultListenCallbacks::OnCertificateError(uint64_t sessionid, const X509Info& info, int error) +{ +} + +std::string DefaultListenCallbacks::SessionIdToString(uint64_t id) +{ + std::ostringstream oss; + oss << "session-" << id; + return oss.str(); +} + +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultMasterApplication.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultMasterApplication.cpp new file mode 100644 index 0000000..2e25457 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/DefaultMasterApplication.cpp @@ -0,0 +1,36 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiodnp3/DefaultMasterApplication.h" + +using namespace opendnp3; + +#include + +namespace asiodnp3 +{ + +openpal::UTCTimestamp DefaultMasterApplication::Now() +{ + auto time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + return openpal::UTCTimestamp(time); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/ErrorCodes.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/ErrorCodes.cpp new file mode 100644 index 0000000..3c6392d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/ErrorCodes.cpp @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiodnp3/ErrorCodes.h" + +namespace asiodnp3 +{ + +ErrorCategory ErrorCategory::instance; + +std::string ErrorCategory::message(int ev) const +{ + switch (ev) + { + case(static_cast(Error::SHUTTING_DOWN)) : + return "The operation was requested while the resource was shutting down"; + case(static_cast(Error::NO_TLS_SUPPORT)) : + return "Not built with TLS support"; + case(static_cast(Error::NO_SERIAL_SUPPORT)): + return "Not built with serial support"; + default: + return "unknown error"; + }; +} + +} + + + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.cpp new file mode 100644 index 0000000..9201cd9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.cpp @@ -0,0 +1,352 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiodnp3/IOHandler.h" + +#include "openpal/logging/LogMacros.h" +#include "opendnp3/LogLevels.h" + +using namespace openpal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +IOHandler::IOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener +) : + logger(logger), + listener(listener), + parser(logger) +{ + +} + +void IOHandler::Shutdown() +{ + if (!isShutdown) + { + this->isShutdown = true; + + this->Reset(); + + this->ShutdownImpl(); + + this->UpdateListener(ChannelState::SHUTDOWN); + } +} + +void IOHandler::OnReadComplete(const std::error_code& ec, size_t num) +{ + if (ec) + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, ec.message().c_str()); + + this->Reset(); + + this->UpdateListener(ChannelState::OPENING); + this->OnChannelShutdown(); + } + else + { + this->statistics.numBytesRx += static_cast(num); + + this->parser.OnRead(static_cast(num), *this); + this->BeginRead(); + } +} + +void IOHandler::OnWriteComplete(const std::error_code& ec, size_t num) +{ + + if (ec) + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, ec.message().c_str()); + this->Reset(); + + this->UpdateListener(ChannelState::OPENING); + this->OnChannelShutdown(); + } + else + { + this->statistics.numBytesTx += static_cast(num); + + if (!this->txQueue.empty()) + { + const auto session = this->txQueue.front().session; + this->txQueue.pop_front(); + session->OnTransmitResult(true); + } + + this->CheckForSend(); + } + +} + +void IOHandler::BeginTransmit(const std::shared_ptr& session, const RSlice& data) +{ + if (this->channel) + { + this->txQueue.push_back(Transmission(data, session)); + this->CheckForSend(); + } + else + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Router received transmit request while offline"); + } +} + +bool IOHandler::AddContext(const std::shared_ptr& session, const Route& route) +{ + if (this->IsRouteInUse(route)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Route already in use: %u -> %u", route.source, route.destination); + return false; + } + + if (this->IsSessionInUse(session)) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Context cannot be bound 2x"); + return false; + } + + sessions.push_back(Session(session, route)); // record is always disabled by default + + return true; +} + +bool IOHandler::Enable(const std::shared_ptr& session) +{ + auto matches = [&](const Session & rec) + { + return rec.Matches(session); + }; + + const auto iter = std::find_if(sessions.begin(), sessions.end(), matches); + + if (iter == sessions.end()) return false; + + if (iter->enabled) return true; // already enabled + + iter->enabled = true; + + if (this->channel) + { + iter->LowerLayerUp(); + } + else + { + this->UpdateListener(ChannelState::OPENING); + + this->BeginChannelAccept(); + } + + return true; +} + +bool IOHandler::Disable(const std::shared_ptr& session) +{ + auto matches = [&](const Session & rec) + { + return rec.Matches(session); + }; + + const auto iter = std::find_if(sessions.begin(), sessions.end(), matches); + + if (iter == sessions.end()) return false; + + if (!iter->enabled) return true; // already disabled + + iter->enabled = false; + + if (channel) + { + iter->LowerLayerDown(); + } + + if (!this->IsAnySessionEnabled()) + { + this->Reset(); + this->SuspendChannelAccept(); + } + + return true; +} + +bool IOHandler::Remove(const std::shared_ptr& session) +{ + auto matches = [&](const Session & rec) + { + return rec.Matches(session); + }; + + const auto iter = std::find_if(sessions.begin(), sessions.end(), matches); + + if (iter == sessions.end()) return false; + + if (channel) + { + iter->LowerLayerDown(); + } + + sessions.erase(iter); + + if (!this->IsAnySessionEnabled()) + { + this->SuspendChannelAccept(); + } + + return true; +} + +void IOHandler::OnNewChannel(const std::shared_ptr& channel) +{ + this->Reset(); + + ++this->statistics.numOpen; + + this->channel = channel; + + this->channel->SetCallbacks(shared_from_this()); + + this->UpdateListener(ChannelState::OPEN); + + this->BeginRead(); + + this->taskLock.SetOnline(); + + for (auto& session : this->sessions) + { + if (session.enabled) + { + session.LowerLayerUp(); + } + } +} + +bool IOHandler::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + if (this->SendToSession(Route(header.src, header.dest), header, userdata)) + { + return true; + } + else + { + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Frame w/ unknown route, source: %i, dest %i", header.src, header.dest); + return false; + } +} + +void IOHandler::BeginRead() +{ + this->channel->BeginRead(this->parser.WriteBuff()); +} + +void IOHandler::CheckForSend() +{ + if (this->txQueue.empty() || !this->channel || !this->channel->CanWrite()) return; + + ++statistics.numLinkFrameTx; + this->channel->BeginWrite(this->txQueue.front().txdata); +} + +bool IOHandler::SendToSession(const opendnp3::Route& route, const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + auto matches = [route](const Session & session) + { + return session.enabled && session.Matches(route); + }; + + const auto iter = std::find_if(sessions.begin(), sessions.end(), matches); + + if (iter == sessions.end()) + { + return false; + } + else + { + return iter->OnFrame(header, userdata); + } +} + +bool IOHandler::IsRouteInUse(const Route& route) const +{ + auto matches = [route](const Session & record) + { + return record.Matches(route); + }; + + return std::find_if(sessions.begin(), sessions.end(), matches) != sessions.end(); +} + +bool IOHandler::IsSessionInUse(const std::shared_ptr& session) const +{ + auto matches = [&](const Session & record) + { + return record.Matches(session); + }; + + return std::find_if(sessions.begin(), sessions.end(), matches) != sessions.end(); +} + +bool IOHandler::IsAnySessionEnabled() const +{ + auto matches = [&](const Session & record) + { + return record.enabled; + }; + + return std::find_if(sessions.begin(), sessions.end(), matches) != sessions.end(); +} + +void IOHandler::Reset() +{ + if (this->channel) + { + // shutdown the existing channel and drop the reference to it + this->channel->Shutdown(); + this->channel.reset(); + + ++this->statistics.numClose; + + this->UpdateListener(ChannelState::CLOSED); + + // notify any sessions that are online that this layer is offline + for (auto& item : this->sessions) + { + item.LowerLayerDown(); + } + } + + this->taskLock.SetOffline(); + + // reset the state of the parser + this->parser.Reset(); + + // clear any pending tranmissions + this->txQueue.clear(); +} + +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.h new file mode 100644 index 0000000..879c936 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/IOHandler.h @@ -0,0 +1,227 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_IOHANDLER_H +#define ASIODNP3_IOHANDLER_H + +#include "opendnp3/Route.h" +#include "opendnp3/link/ILinkTx.h" +#include "opendnp3/link/LinkLayerParser.h" +#include "opendnp3/master/MultidropTaskLock.h" + +#include "asiodnp3/IChannelListener.h" + +#include "openpal/logging/Logger.h" + +#include "asiopal/IAsyncChannel.h" + +#include +#include + +namespace asiodnp3 +{ + +/** + +Manages I/O for a number of link contexts + +*/ +class IOHandler : private opendnp3::IFrameSink, public asiopal::IChannelCallbacks, public std::enable_shared_from_this +{ + +public: + + IOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener + ); + + virtual ~IOHandler() {} + + opendnp3::LinkStatistics Statistics() const + { + return opendnp3::LinkStatistics(this->statistics, this->parser.Statistics()); + } + + opendnp3::ITaskLock& TaskLock() + { + return this->taskLock; + } + + void Shutdown(); + + /// --- implement ILinkTx --- + + void BeginTransmit(const std::shared_ptr& session, const openpal::RSlice& data); + + // Bind a link layer session to the handler + bool AddContext(const std::shared_ptr& session, const opendnp3::Route& route); + + // Begin sending messages to the context + bool Enable(const std::shared_ptr& session); + + // Stop sending messages to this session + bool Disable(const std::shared_ptr& session); + + // Remove this session entirely + bool Remove(const std::shared_ptr& session); + + // Query to see if a route is in use + bool IsRouteInUse(const opendnp3::Route& route) const; + +protected: + + // ------ Implement IChannelCallbacks ----- + + virtual void OnReadComplete(const std::error_code& ec, size_t num) override final; + + virtual void OnWriteComplete(const std::error_code& ec, size_t num) override final; + + // ------ Super classes will implement these ----- + + // start getting a new channel + virtual void BeginChannelAccept() = 0; + + // stop getting new channels + virtual void SuspendChannelAccept() = 0; + + // shutdown any additional state + virtual void ShutdownImpl() = 0; + + // the current channel has closed, start getting a new one + virtual void OnChannelShutdown() = 0; + + // Called by the super class when a new channel is available + void OnNewChannel(const std::shared_ptr& channel); + + openpal::Logger logger; + const std::shared_ptr listener; + opendnp3::LinkStatistics::Channel statistics; + +private: + + bool isShutdown = false; + + inline void UpdateListener(opendnp3::ChannelState state) + { + if (listener) listener->OnStateChange(state); + } + + // called by the parser when a complete frame is read + virtual bool OnFrame(const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata) override final; + + + bool IsSessionInUse(const std::shared_ptr& session) const; + bool IsAnySessionEnabled() const; + void Reset(); + void BeginRead(); + void CheckForSend(); + + bool SendToSession(const opendnp3::Route& route, const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata); + + class Session + { + + public: + + Session(const std::shared_ptr& session, const opendnp3::Route& route) : + route(route), + session(session) + {} + + Session() = default; + + inline bool Matches(const std::shared_ptr& session) const + { + return this->session == session; + } + inline bool Matches(const opendnp3::Route& route) const + { + return this->route.Equals(route); + } + + inline bool OnFrame(const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata) + { + return this->session->OnFrame(header, userdata); + } + + inline bool LowerLayerUp() + { + if (!online) + { + online = true; + return this->session->OnLowerLayerUp(); + } + else + { + return false; + } + } + + inline bool LowerLayerDown() + { + if(online) + { + online = false; + return this->session->OnLowerLayerDown(); + } + else + { + return false; + } + } + + bool enabled = false; + + private: + + opendnp3::Route route; + bool online = false; + std::shared_ptr session; + }; + + struct Transmission + { + Transmission(const openpal::RSlice& txdata, const std::shared_ptr& session) : + txdata(txdata), + session(session) + {} + + Transmission() = default; + + openpal::RSlice txdata; + std::shared_ptr session; + }; + + std::vector sessions; + std::deque txQueue; + + opendnp3::LinkLayerParser parser; + + // current value of the channel, may be empty + std::shared_ptr channel; + + opendnp3::MultidropTaskLock taskLock; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.cpp new file mode 100644 index 0000000..787fad1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.cpp @@ -0,0 +1,202 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiodnp3/LinkSession.h" + +#include + +#include + +using namespace openpal; +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +LinkSession::LinkSession( + const openpal::Logger& logger, + uint64_t sessionid, + const std::shared_ptr& manager, + const std::shared_ptr& callbacks, + const std::shared_ptr& channel) : + logger(logger), + session_id(sessionid), + manager(manager), + callbacks(callbacks), + channel(channel), + parser(logger), + first_frame_timer(*channel->executor) +{ + +} + +void LinkSession::Shutdown() +{ + auto shutdown = [self = shared_from_this()]() + { + self->ShutdownImpl(); + }; + + this->channel->executor->BlockUntilAndFlush(shutdown); +} + +void LinkSession::ShutdownImpl() +{ + if(this->is_shutdown) return; + + this->is_shutdown = true; + + this->callbacks->OnConnectionClose(this->session_id, this->stack); + + if (this->stack) + { + this->stack->OnLowerLayerDown(); + } + + this->first_frame_timer.Cancel(); + + this->channel->Shutdown(); + + auto detach = [self = shared_from_this()]() + { + self->manager->Detach(self); + }; + + this->channel->executor->strand.post(detach); +} + +void LinkSession::SetLogFilters(openpal::LogFilters filters) +{ + this->logger.SetFilters(filters); +} + +void LinkSession::OnReadComplete(const std::error_code& ec, size_t num) +{ + if (ec) + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, ec.message().c_str()); + this->ShutdownImpl(); + } + else + { + this->parser.OnRead(static_cast(num), *this); + this->BeginReceive(); + } +} + +void LinkSession::OnWriteComplete(const std::error_code& ec, size_t num) +{ + if (ec) + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, ec.message().c_str()); + this->ShutdownImpl(); + } + else + { + this->stack->OnTransmitComplete(true); + } +} + +void LinkSession::BeginTransmit(const openpal::RSlice& buffer, opendnp3::ILinkSession& session) +{ + this->channel->BeginWrite(buffer); +} + +bool LinkSession::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + if (this->stack) + { + this->stack->OnFrame(header, userdata); + } + else + { + this->first_frame_timer.Cancel(); + + this->callbacks->OnFirstFrame(this->session_id, header, *this); + + if (this->stack) + { + this->stack->OnLowerLayerUp(); + + // push the frame into the newly created stack + this->stack->OnFrame(header, userdata); + } + else + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, "No master created. Closing socket."); + this->ShutdownImpl(); + } + } + + return true; +} + +std::shared_ptr LinkSession::AcceptSession( + const std::string& loggerid, + std::shared_ptr SOEHandler, + std::shared_ptr application, + const MasterStackConfig& config) +{ + if (this->stack) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, "SocketSession already has a master bound"); + return nullptr; + } + + // rename the logger id to something meaningful + this->logger.Rename(loggerid); + + this->stack = MasterSessionStack::Create( + this->logger, + this->channel->executor, + SOEHandler, + application, + shared_from_this(), + *this, + config + ); + + return stack; +} + +void LinkSession::Start() +{ + this->channel->SetCallbacks(shared_from_this()); + + auto timeout = [self = shared_from_this()]() + { + SIMPLE_LOG_BLOCK(self->logger, flags::ERR, "Timed out before receving a frame. Closing socket."); + self->channel->Shutdown(); + }; + + this->first_frame_timer.Start(this->callbacks->GetFirstFrameTimeout(), timeout); + + this->BeginReceive(); +} + +void LinkSession::BeginReceive() +{ + auto dest = parser.WriteBuff(); + channel->BeginRead(dest); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.h new file mode 100644 index 0000000..4aafa16 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/LinkSession.h @@ -0,0 +1,123 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#ifndef ASIODNP3_LINKSESSION_H +#define ASIODNP3_LINKSESSION_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "asiodnp3/MasterSessionStack.h" +#include "asiodnp3/IListenCallbacks.h" + +namespace asiodnp3 +{ +class LinkSession final : + public opendnp3::ILinkTx, + public asiopal::IChannelCallbacks, + private opendnp3::IFrameSink, + public std::enable_shared_from_this, + public asiopal::IResource, + private ISessionAcceptor, + private openpal::Uncopyable +{ +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + uint64_t sessionid, + const std::shared_ptr& manager, + const std::shared_ptr& callbacks, + const std::shared_ptr& channel) + { + auto session = std::make_shared(logger, sessionid, manager, callbacks, channel); + + session->Start(); + + return session; + } + + LinkSession( + const openpal::Logger& logger, + uint64_t sessionid, + const std::shared_ptr& manager, + const std::shared_ptr& callbacks, + const std::shared_ptr& channel + ); + + // override IResource + void Shutdown() override; + + void SetLogFilters(openpal::LogFilters filters); + +private: + + void ShutdownImpl(); + + // IChannelCallbacks + virtual void OnReadComplete(const std::error_code& ec, size_t num) override; + + virtual void OnWriteComplete(const std::error_code& ec, size_t num) override; + + // ILinkTx + virtual void BeginTransmit(const openpal::RSlice& buffer, opendnp3::ILinkSession& session) override; + + // IFrameSink + virtual bool OnFrame(const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata) override; + + // ISessionAcceptor + virtual std::shared_ptr AcceptSession( + const std::string& loggerid, + std::shared_ptr SOEHandler, + std::shared_ptr application, + const MasterStackConfig& config) override; + + void Start(); + + void BeginReceive(); + + bool is_shutdown = false; + openpal::Logger logger; + const uint64_t session_id; + + const std::shared_ptr manager; + const std::shared_ptr callbacks; + const std::shared_ptr channel; + + opendnp3::LinkLayerParser parser; + openpal::TimerRef first_frame_timer; + opendnp3::Route route; + + std::shared_ptr stack; // initialized to null +}; +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.cpp new file mode 100644 index 0000000..75a1822 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiodnp3/MasterScan.h" + +#include "openpal/executor/IExecutor.h" +#include "opendnp3/master/MasterContext.h" +#include "opendnp3/master/IMasterTask.h" + +using namespace openpal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +MasterScan::MasterScan(const std::shared_ptr& task, const std::shared_ptr& actions) : + task(task), + actions(actions) +{ + +} +bool MasterScan::Demand() +{ + actions->Demand(task); + return true; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.h new file mode 100644 index 0000000..59f6dc4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterScan.h @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_MASTERSCAN_H +#define ASIODNP3_MASTERSCAN_H + +#include "openpal/executor/IExecutor.h" +#include "opendnp3/master/IMasterTask.h" +#include "asiodnp3/IMasterScan.h" + +#include + +namespace asiodnp3 +{ + +struct ITaskActions +{ + virtual ~ITaskActions() {} + + virtual void Demand(const std::shared_ptr& task) = 0; +}; + +/** +* Provides access to a permanently bound scan +*/ +class MasterScan final : public IMasterScan +{ +public: + + MasterScan() = default; + + MasterScan(const std::shared_ptr& task, const std::shared_ptr& actions); + + static std::shared_ptr Create(const std::shared_ptr& task, const std::shared_ptr& actions) + { + return std::make_shared(task, actions); + } + + /// Request that the scan be performed as soon as possible + virtual bool Demand() override; + +private: + + const std::shared_ptr task; + const std::shared_ptr actions; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.cpp new file mode 100644 index 0000000..8ce419a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.cpp @@ -0,0 +1,231 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiodnp3/MasterSessionStack.h" + +#include "asiopal/Executor.h" +#include "asiodnp3/Conversions.h" +#include "asiodnp3/LinkSession.h" + +using namespace opendnp3; + +namespace asiodnp3 +{ +std::shared_ptr MasterSessionStack::Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& session, + opendnp3::ILinkTx& linktx, + const MasterStackConfig& config +) +{ + return std::make_shared(logger, executor, SOEHandler, application, session, linktx, config); +} + +MasterSessionStack::MasterSessionStack( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& session, + opendnp3::ILinkTx& linktx, + const MasterStackConfig& config +) : + executor(executor), + session(session), + stack(logger, executor, application, config.master.maxRxFragSize, config.link), + context(logger, executor, stack.transport, SOEHandler, application, config.master, NullTaskLock::Instance()) +{ + stack.link->SetRouter(linktx); + stack.transport->SetAppLayer(context); +} + +void MasterSessionStack::OnLowerLayerUp() +{ + stack.link->OnLowerLayerUp(); +} + +void MasterSessionStack::OnLowerLayerDown() +{ + stack.link->OnLowerLayerDown(); + + // now we can release the socket session + session.reset(); +} + +bool MasterSessionStack::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + return stack.link->OnFrame(header, userdata); +} + +void MasterSessionStack::OnTransmitComplete(bool success) +{ + this->stack.link->OnTransmitResult(success); +} + +void MasterSessionStack::SetLogFilters(const openpal::LogFilters& filters) +{ + auto set = [this, filters]() + { + this->session->SetLogFilters(filters); + }; + + this->executor->strand.post(set); +} + +void MasterSessionStack::Demand(const std::shared_ptr& task) +{ + auto action = [task, self = shared_from_this()] + { + task->Demand(); + self->context.CheckForTask(); + }; + this->executor->strand.post(action); +} + +void MasterSessionStack::BeginShutdown() +{ + auto shutdown = [session = session]() + { + session->Shutdown(); + }; + + executor->strand.post(shutdown); +} + +StackStatistics MasterSessionStack::GetStackStatistics() +{ + auto get = [self = shared_from_this()]() -> StackStatistics + { + return self->CreateStatistics(); + }; + return executor->ReturnFrom(get); +} + +std::shared_ptr MasterSessionStack::AddScan(openpal::TimeDuration period, const std::vector
& headers, const TaskConfig& config) +{ + auto builder = ConvertToLambda(headers); + auto get = [self = shared_from_this(), period, builder, config]() + { + return self->context.AddScan(period, builder, config); + }; + return MasterScan::Create(executor->ReturnFrom>(get), shared_from_this()); +} + +std::shared_ptr MasterSessionStack::AddAllObjectsScan(GroupVariationID gvId, openpal::TimeDuration period, const TaskConfig& config) +{ + auto get = [self = shared_from_this(), gvId, period, config] { return self->context.AddAllObjectsScan(gvId, period, config); }; + return MasterScan::Create(executor->ReturnFrom>(get), shared_from_this()); +} + +std::shared_ptr MasterSessionStack::AddClassScan(const ClassField& field, openpal::TimeDuration period, const TaskConfig& config) +{ + auto get = [self = shared_from_this(), field, period, config] { return self->context.AddClassScan(field, period, config); }; + return MasterScan::Create(executor->ReturnFrom>(get), shared_from_this()); +} + +std::shared_ptr MasterSessionStack::AddRangeScan(GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, const TaskConfig& config) +{ + auto get = [self = shared_from_this(), gvId, start, stop, period, config] { return self->context.AddRangeScan(gvId, start, stop, period, config); }; + return MasterScan::Create(executor->ReturnFrom>(get), shared_from_this()); +} + +void MasterSessionStack::Scan(const std::vector
& headers, const TaskConfig& config) +{ + auto builder = ConvertToLambda(headers); + auto action = [self = shared_from_this(), builder, config]() -> void { self->context.Scan(builder, config); }; + return executor->strand.post(action); +} + +void MasterSessionStack::ScanAllObjects(GroupVariationID gvId, const TaskConfig& config) +{ + auto action = [self = shared_from_this(), gvId, config]() -> void { self->context.ScanAllObjects(gvId, config); }; + return executor->strand.post(action); +} + +void MasterSessionStack::ScanClasses(const ClassField& field, const TaskConfig& config) +{ + auto action = [self = shared_from_this(), field, config]() -> void { self->context.ScanClasses(field, config); }; + return executor->strand.post(action); +} + +void MasterSessionStack::ScanRange(GroupVariationID gvId, uint16_t start, uint16_t stop, const TaskConfig& config) +{ + auto action = [self = shared_from_this(), gvId, start, stop, config]() -> void { self->context.ScanRange(gvId, start, stop, config); }; + return executor->strand.post(action); +} + +void MasterSessionStack::Write(const TimeAndInterval& value, uint16_t index, const TaskConfig& config) +{ + auto action = [self = shared_from_this(), value, index, config]() -> void { self->context.Write(value, index, config); }; + return executor->strand.post(action); +} + +void MasterSessionStack::Restart(RestartType op, const RestartOperationCallbackT& callback, TaskConfig config) +{ + auto action = [self = shared_from_this(), op, callback, config]() -> void { self->context.Restart(op, callback, config); }; + return executor->strand.post(action); +} + +void MasterSessionStack::PerformFunction(const std::string& name, FunctionCode func, const std::vector
& headers, const TaskConfig& config) +{ + auto builder = ConvertToLambda(headers); + auto action = [self = shared_from_this(), name, func, builder, config]() -> void { self->context.PerformFunction(name, func, builder, config); }; + return executor->strand.post(action); +} + +/// --- ICommandProcessor --- + +void MasterSessionStack::SelectAndOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config) +{ + // this is required b/c move capture not supported in C++11 + auto set = std::make_shared(std::move(commands)); + + auto action = [self = shared_from_this(), set, config, callback]() -> void + { + self->context.SelectAndOperate(std::move(*set), callback, config); + }; + executor->strand.post(action); +} + +void MasterSessionStack::DirectOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config) +{ + // this is required b/c move capture not supported in C++11 + auto set = std::make_shared(std::move(commands)); + + auto action = [self = shared_from_this(), set, config, callback]() -> void + { + self->context.DirectOperate(std::move(*set), callback, config); + }; + executor->strand.post(action); +} + +opendnp3::StackStatistics MasterSessionStack::CreateStatistics() const +{ + return opendnp3::StackStatistics(this->stack.link->GetStatistics(), this->stack.transport->GetStatistics()); +} + +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.h new file mode 100644 index 0000000..e613023 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterSessionStack.h @@ -0,0 +1,117 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_MASTERSESSIONSTACK_H +#define ASIODNP3_MASTERSESSIONSTACK_H + +#include +#include + +#include "asiodnp3/IMasterSession.h" +#include "asiodnp3/MasterStackConfig.h" +#include "asiodnp3/MasterScan.h" + +namespace asiopal +{ +class Executor; +} + +namespace asiodnp3 +{ + +class LinkSession; + +/** +* Interface that represents an ephemeral master session +*/ +class MasterSessionStack final : public IMasterSession, public ITaskActions, public std::enable_shared_from_this +{ +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& session, + opendnp3::ILinkTx& linktx, + const MasterStackConfig& config + ); + + void OnLowerLayerUp(); + + void OnLowerLayerDown(); + + bool OnFrame(const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata); + + void OnTransmitComplete(bool success); + + virtual void SetLogFilters(const openpal::LogFilters& filters) override; + + virtual void Demand(const std::shared_ptr& task) override; + + /// --- IGPRSMaster --- + + virtual void BeginShutdown() override; + + /// --- ICommandOperations --- + + virtual opendnp3::StackStatistics GetStackStatistics() override; + virtual std::shared_ptr AddScan(openpal::TimeDuration period, const std::vector& headers, const opendnp3::TaskConfig& config) override; + virtual std::shared_ptr AddAllObjectsScan(opendnp3::GroupVariationID gvId, openpal::TimeDuration period, const opendnp3::TaskConfig& config) override; + virtual std::shared_ptr AddClassScan(const opendnp3::ClassField& field, openpal::TimeDuration period, const opendnp3::TaskConfig& config) override; + virtual std::shared_ptr AddRangeScan(opendnp3::GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, const opendnp3::TaskConfig& config) override; + virtual void Scan(const std::vector& headers, const opendnp3::TaskConfig& config) override; + virtual void ScanAllObjects(opendnp3::GroupVariationID gvId, const opendnp3::TaskConfig& config) override; + virtual void ScanClasses(const opendnp3::ClassField& field, const opendnp3::TaskConfig& config) override; + virtual void ScanRange(opendnp3::GroupVariationID gvId, uint16_t start, uint16_t stop, const opendnp3::TaskConfig& config) override; + virtual void Write(const opendnp3::TimeAndInterval& value, uint16_t index, const opendnp3::TaskConfig& config) override; + virtual void Restart(opendnp3::RestartType op, const opendnp3::RestartOperationCallbackT& callback, opendnp3::TaskConfig config) override; + virtual void PerformFunction(const std::string& name, opendnp3::FunctionCode func, const std::vector& headers, const opendnp3::TaskConfig& config) override; + + /// --- ICommandProcessor --- + + virtual void SelectAndOperate(opendnp3::CommandSet&& commands, const opendnp3::CommandCallbackT& callback, const opendnp3::TaskConfig& config) override; + virtual void DirectOperate(opendnp3::CommandSet&& commands, const opendnp3::CommandCallbackT& callback, const opendnp3::TaskConfig& config) override; + + MasterSessionStack( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& session, + opendnp3::ILinkTx& linktx, + const MasterStackConfig& config + ); + +private: + + opendnp3::StackStatistics CreateStatistics() const; + + std::shared_ptr executor; + std::shared_ptr session; + opendnp3::TransportStack stack; + opendnp3::MContext context; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.cpp new file mode 100644 index 0000000..2fca037 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.cpp @@ -0,0 +1,227 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MasterStack.h" + +#include + +#include + +#include "Conversions.h" + +using namespace openpal; +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +MasterStack::MasterStack( + const Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + const MasterStackConfig& config, + ITaskLock& taskLock) : + + StackBase(logger, executor, application, iohandler, manager, config.master.maxRxFragSize, config.link), + mcontext(logger, executor, tstack.transport, SOEHandler, application, config.master, taskLock) +{ + tstack.transport->SetAppLayer(mcontext); +} + +bool MasterStack::Enable() +{ + auto action = [self = shared_from_this()] { return self->iohandler->Enable(self); }; + return this->executor->ReturnFrom(action); +} + +bool MasterStack::Disable() +{ + auto action = [self = shared_from_this()] { return self->iohandler->Disable(self); }; + return this->executor->ReturnFrom(action); +} + +void MasterStack::Shutdown() +{ + this->PerformShutdown(shared_from_this()); +} + +StackStatistics MasterStack::GetStackStatistics() +{ + auto get = [self = shared_from_this()]() -> StackStatistics + { + return self->CreateStatistics(); + }; + return this->executor->ReturnFrom(get); +} + +void MasterStack::Demand(const std::shared_ptr& task) +{ + auto action = [task, self = shared_from_this()] + { + task->Demand(); + self->mcontext.CheckForTask(); + }; + this->executor->strand.post(action); +} + +void MasterStack::SetLogFilters(const openpal::LogFilters& filters) +{ + auto set = [self = this->shared_from_this(), filters]() + { + self->logger.SetFilters(filters); + }; + + this->executor->strand.post(set); +} + +std::shared_ptr MasterStack::AddScan(openpal::TimeDuration period, const std::vector
& headers, const TaskConfig& config) +{ + auto builder = ConvertToLambda(headers); + auto self = shared_from_this(); + auto add = [self, builder, period, config]() + { + return self->mcontext.AddScan(period, builder, config); + }; + return MasterScan::Create(executor->ReturnFrom>(add), self); +} + +std::shared_ptr MasterStack::AddAllObjectsScan(GroupVariationID gvId, openpal::TimeDuration period, const TaskConfig& config) +{ + auto self = shared_from_this(); + auto add = [self, gvId, period, config]() + { + return self->mcontext.AddAllObjectsScan(gvId, period, config); + }; + return MasterScan::Create(executor->ReturnFrom>(add), self); +} + +std::shared_ptr MasterStack::AddClassScan(const ClassField& field, openpal::TimeDuration period, const TaskConfig& config) +{ + auto self = shared_from_this(); + auto add = [self, field, period, config]() + { + return self->mcontext.AddClassScan(field, period, config); + }; + return MasterScan::Create(executor->ReturnFrom>(add), self); +} + +std::shared_ptr MasterStack::AddRangeScan(GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), gvId, start, stop, period, config]() + { + return self->mcontext.AddRangeScan(gvId, start, stop, period, config); + }; + return MasterScan::Create(executor->ReturnFrom>(add), shared_from_this()); +} + +void MasterStack::Scan(const std::vector
& headers, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), builder = ConvertToLambda(headers), config]() + { + return self->mcontext.Scan(builder, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::ScanAllObjects(GroupVariationID gvId, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), gvId, config]() + { + return self->mcontext.ScanAllObjects(gvId, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::ScanClasses(const ClassField& field, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), field, config]() + { + return self->mcontext.ScanClasses(field, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::ScanRange(GroupVariationID gvId, uint16_t start, uint16_t stop, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), gvId, start, stop, config]() + { + return self->mcontext.ScanRange(gvId, start, stop, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::Write(const TimeAndInterval& value, uint16_t index, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), value, index, config]() + { + return self->mcontext.Write(value, index, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::Restart(RestartType op, const RestartOperationCallbackT& callback, TaskConfig config) +{ + auto add = [self = this->shared_from_this(), op, callback, config]() + { + return self->mcontext.Restart(op, callback, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::PerformFunction(const std::string& name, FunctionCode func, const std::vector
& headers, const TaskConfig& config) +{ + auto add = [self = this->shared_from_this(), name, func, builder = ConvertToLambda(headers), config]() + { + return self->mcontext.PerformFunction(name, func, builder, config); + }; + return this->executor->strand.post(add); +} + +void MasterStack::SelectAndOperate(opendnp3::CommandSet&& commands, const opendnp3::CommandCallbackT& callback, const opendnp3::TaskConfig& config) +{ + /// this is to work around the fact that c++11 doesn't have generic move capture + auto set = std::make_shared(std::move(commands)); + + auto action = [self = this->shared_from_this(), set, config, callback]() + { + self->mcontext.SelectAndOperate(std::move(*set), callback, config); + }; + + this->executor->strand.post(action); +} + +void MasterStack::DirectOperate(opendnp3::CommandSet&& commands, const opendnp3::CommandCallbackT& callback, const opendnp3::TaskConfig& config) +{ + /// this is to work around the fact that c++11 doesn't have generic move capture + auto set = std::make_shared(std::move(commands)); + + auto action = [self = this->shared_from_this(), set, config, callback]() + { + self->mcontext.DirectOperate(std::move(*set), callback, config); + }; + + this->executor->strand.post(action); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.h new file mode 100644 index 0000000..7ef9abd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterStack.h @@ -0,0 +1,147 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_MASTERSTACK_H +#define ASIODNP3_MASTERSTACK_H + +#include "asiodnp3/IMaster.h" +#include "asiodnp3/MasterStackConfig.h" +#include "asiodnp3/StackBase.h" +#include "asiodnp3/MasterScan.h" + +#include "opendnp3/master/MasterContext.h" + +namespace asiodnp3 +{ + + +class MasterStack : public IMaster, public opendnp3::ILinkSession, public opendnp3::ILinkTx, public ITaskActions, public std::enable_shared_from_this, public StackBase +{ +public: + + MasterStack( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + const MasterStackConfig& config, + opendnp3::ITaskLock& taskLock + ); + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + const MasterStackConfig& config, + opendnp3::ITaskLock& taskLock + ) + { + auto ret = std::make_shared(logger, executor, SOEHandler, application, iohandler, manager, config, taskLock); + + ret->tstack.link->SetRouter(*ret); + + return ret; + } + + // --------- Implement IStack --------- + + virtual bool Enable() override; + + virtual bool Disable() override; + + virtual void Shutdown() override; + + virtual opendnp3::StackStatistics GetStackStatistics() override; + + virtual void Demand(const std::shared_ptr& task) override; + + // --------- Implement ILinkSession --------- + + virtual bool OnTransmitResult(bool success) override + { + return this->tstack.link->OnTransmitResult(success); + } + + virtual bool OnLowerLayerUp() override + { + return this->tstack.link->OnLowerLayerUp(); + } + + virtual bool OnLowerLayerDown() override + { + return this->tstack.link->OnLowerLayerDown(); + } + + virtual bool OnFrame(const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata) + { + return this->tstack.link->OnFrame(header, userdata); + } + + virtual void BeginTransmit(const openpal::RSlice& buffer, opendnp3::ILinkSession& context) + { + this->iohandler->BeginTransmit(shared_from_this(), buffer); + } + + // --------- Implement IMasterOperations --------- + + virtual void SetLogFilters(const openpal::LogFilters& filters) override; + + virtual std::shared_ptr AddScan(openpal::TimeDuration period, const std::vector& headers, const opendnp3::TaskConfig& config) override; + + virtual std::shared_ptr AddAllObjectsScan(opendnp3::GroupVariationID gvId, openpal::TimeDuration period, const opendnp3::TaskConfig& config) override; + + virtual std::shared_ptr AddClassScan(const opendnp3::ClassField& field, openpal::TimeDuration period, const opendnp3::TaskConfig& config) override; + + virtual std::shared_ptr AddRangeScan(opendnp3::GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, const opendnp3::TaskConfig& config) override; + + virtual void Scan(const std::vector& headers, const opendnp3::TaskConfig& config) override; + + virtual void ScanAllObjects(opendnp3::GroupVariationID gvId, const opendnp3::TaskConfig& config) override; + + virtual void ScanClasses(const opendnp3::ClassField& field, const opendnp3::TaskConfig& config) override; + + virtual void ScanRange(opendnp3::GroupVariationID gvId, uint16_t start, uint16_t stop, const opendnp3::TaskConfig& config) override; + + virtual void Write(const opendnp3::TimeAndInterval& value, uint16_t index, const opendnp3::TaskConfig& config) override; + + virtual void Restart(opendnp3::RestartType op, const opendnp3::RestartOperationCallbackT& callback, opendnp3::TaskConfig config) override; + + virtual void PerformFunction(const std::string& name, opendnp3::FunctionCode func, const std::vector& headers, const opendnp3::TaskConfig& config) override; + + // ------- implement ICommandProcessor --------- + + virtual void SelectAndOperate(opendnp3::CommandSet&& commands, const opendnp3::CommandCallbackT& callback, const opendnp3::TaskConfig& config) override; + + virtual void DirectOperate(opendnp3::CommandSet&& commands, const opendnp3::CommandCallbackT& callback, const opendnp3::TaskConfig& config) override; + +protected: + + opendnp3::MContext mcontext; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterTCPServer.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterTCPServer.cpp new file mode 100644 index 0000000..225a4ee --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/MasterTCPServer.cpp @@ -0,0 +1,103 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiodnp3/MasterTCPServer.h" + +#include "asiodnp3/LinkSession.h" + +#include +#include + +#include "asiopal/SocketChannel.h" + +#include + +using namespace opendnp3; +using namespace openpal; +using namespace asiopal; + +namespace asiodnp3 +{ + +MasterTCPServer::MasterTCPServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const std::shared_ptr& callbacks, + const std::shared_ptr& manager, + std::error_code& ec +) : + TCPServer(logger, executor, endpoint, ec), + callbacks(callbacks), + manager(manager) +{ + +} + +void MasterTCPServer::OnShutdown() +{ + this->manager->Detach(this->shared_from_this()); +} + +void MasterTCPServer::AcceptConnection(uint64_t sessionid, const std::shared_ptr& executor, asio::ip::tcp::socket socket) +{ + std::ostringstream oss; + oss << socket.remote_endpoint(); + + if (this->callbacks->AcceptConnection(sessionid, socket.remote_endpoint().address().to_string())) + { + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Accepted connection from: %s", oss.str().c_str()); + + auto channel = SocketChannel::Create(executor->Fork(), std::move(socket)); // run the link session in its own strand + + auto create = [&]() -> std::shared_ptr + { + return LinkSession::Create( + this->logger.Detach(SessionIdToString(sessionid)), + sessionid, + this->manager, + this->callbacks, + channel + ); + }; + + if (!this->manager->Bind(create)) + { + channel->Shutdown(); + } + } + else + { + socket.close(); + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Rejected connection from: %s", oss.str().c_str()); + } +} + +std::string MasterTCPServer::SessionIdToString(uint64_t sessionid) +{ + std::ostringstream oss; + oss << "session-" << sessionid; + return oss.str(); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.cpp new file mode 100644 index 0000000..fd3fa2f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.cpp @@ -0,0 +1,126 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "OutstationStack.h" + +using namespace openpal; +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +template +void assign(const T& config, U& view) +{ + for (auto i = 0; i < view.Size(); ++i) + { + view[i].config = config[i]; + } +} + +OutstationStack::OutstationStack( + const Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& commandHandler, + const std::shared_ptr& application, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + const OutstationStackConfig& config) : + + StackBase(logger, executor, application, iohandler, manager, config.outstation.params.maxRxFragSize, config.link), + ocontext(config.outstation, config.dbConfig.sizes, logger, executor, tstack.transport, commandHandler, application) +{ + this->tstack.transport->SetAppLayer(ocontext); + + // apply the database configuration + auto view = ocontext.GetConfigView(); + + assign(config.dbConfig.binary, view.binaries); + assign(config.dbConfig.doubleBinary, view.doubleBinaries); + assign(config.dbConfig.analog, view.analogs); + assign(config.dbConfig.counter, view.counters); + assign(config.dbConfig.frozenCounter, view.frozenCounters); + assign(config.dbConfig.boStatus, view.binaryOutputStatii); + assign(config.dbConfig.aoStatus, view.analogOutputStatii); + assign(config.dbConfig.timeAndInterval, view.timeAndIntervals); +} + + +bool OutstationStack::Enable() +{ + auto action = [self = shared_from_this()] { return self->iohandler->Enable(self); }; + return this->executor->ReturnFrom(action); +} + +bool OutstationStack::Disable() +{ + auto action = [self = shared_from_this()] { return self->iohandler->Disable(self); }; + return this->executor->ReturnFrom(action); +} + +void OutstationStack::Shutdown() +{ + this->PerformShutdown(shared_from_this()); +} + +StackStatistics OutstationStack::GetStackStatistics() +{ + auto get = [self = shared_from_this()] + { + return self->CreateStatistics(); + }; + return this->executor->ReturnFrom(get); +} + +void OutstationStack::SetLogFilters(const LogFilters& filters) +{ + auto set = [self = this->shared_from_this(), filters]() + { + self->logger.SetFilters(filters); + }; + this->executor->strand.post(set); +} + +void OutstationStack::SetRestartIIN() +{ + // this doesn't need to be synchronous, just post it + auto set = [self = this->shared_from_this()]() + { + self->ocontext.SetRestartIIN(); + }; + this->executor->strand.post(set); +} + +void OutstationStack::Apply(const Updates& updates) +{ + if (updates.IsEmpty()) return; + + auto task = [self = this->shared_from_this(), updates]() + { + updates.Apply(self->ocontext.GetUpdateHandler()); + self->ocontext.CheckForTaskStart(); // force the outstation to check for updates + }; + + this->executor->strand.post(task); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.h new file mode 100644 index 0000000..0e2ce43 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/OutstationStack.h @@ -0,0 +1,123 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_OUTSTATIONSTACK_H +#define ASIODNP3_OUTSTATIONSTACK_H + +#include "asiodnp3/IOutstation.h" + +#include "asiopal/Executor.h" +#include "opendnp3/outstation/OutstationContext.h" +#include "opendnp3/transport/TransportStack.h" +#include "asiodnp3/OutstationStackConfig.h" +#include "asiodnp3/StackBase.h" +#include "asiodnp3/IOHandler.h" + +namespace asiodnp3 +{ + +/** +* A stack object for an outstation +*/ +class OutstationStack final : public IOutstation, public opendnp3::ILinkSession, public opendnp3::ILinkTx, public std::enable_shared_from_this, public StackBase +{ +public: + + OutstationStack( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& commandHandler, + const std::shared_ptr& application, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + const OutstationStackConfig& config); + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& commandHandler, + const std::shared_ptr& application, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + const OutstationStackConfig& config + ) + { + auto ret = std::make_shared(logger, executor, commandHandler, application, iohandler, manager, config); + + ret->tstack.link->SetRouter(*ret); + + return ret; + } + + // --------- Implement IStack --------- + + virtual bool Enable() override; + + virtual bool Disable() override; + + virtual void Shutdown() override; + + virtual opendnp3::StackStatistics GetStackStatistics() override; + + // --------- Implement ILinkSession --------- + + virtual bool OnTransmitResult(bool success) override + { + return this->tstack.link->OnTransmitResult(success); + } + + virtual bool OnLowerLayerUp() override + { + return this->tstack.link->OnLowerLayerUp(); + } + + virtual bool OnLowerLayerDown() override + { + return this->tstack.link->OnLowerLayerDown(); + } + + virtual bool OnFrame(const opendnp3::LinkHeaderFields& header, const openpal::RSlice& userdata) + { + return this->tstack.link->OnFrame(header, userdata); + } + + virtual void BeginTransmit(const openpal::RSlice& buffer, opendnp3::ILinkSession& context) + { + this->iohandler->BeginTransmit(shared_from_this(), buffer); + } + + // --------- Implement IOutstation --------- + + + virtual void SetLogFilters(const openpal::LogFilters& filters) override; + + virtual void SetRestartIIN() override; + + virtual void Apply(const Updates& updates) override; + +private: + + opendnp3::OContext ocontext; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingCommandCallback.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingCommandCallback.cpp new file mode 100644 index 0000000..7d3497d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingCommandCallback.cpp @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiodnp3/PrintingCommandCallback.h" + +#include + +using namespace opendnp3; + +namespace asiodnp3 +{ +opendnp3::CommandCallbackT PrintingCommandCallback::Get() +{ + return [](const ICommandTaskResult & result) -> void + { + std::cout << "Received command result w/ summary: " << TaskCompletionToString(result.summary) << std::endl; + auto print = [](const CommandPointResult & res) + { + std::cout + << "Header: " << res.headerIndex + << " Index: " << res.index + << " State: " << CommandPointStateToString(res.state) + << " Status: " << CommandStatusToString(res.status); + }; + result.ForeachItem(print); + }; +} +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingSOEHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingSOEHandler.cpp new file mode 100644 index 0000000..473f618 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/PrintingSOEHandler.cpp @@ -0,0 +1,141 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiodnp3/PrintingSOEHandler.h" + +using namespace std; +using namespace opendnp3; + +namespace asiodnp3 +{ + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + return PrintAll(info, values); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + auto print = [](const Indexed& pair) + { + std::cout << "OctetString " << " [" << pair.index << "] : Size : " << pair.value.ToRSlice().Size() << std::endl; + }; + + values.ForeachItem(print); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + auto print = [](const Indexed& pair) + { + std::cout << "TimeAndInterval: " << + "[" << pair.index << "] : " << + pair.value.time << " : " << + pair.value.interval << " : " << + IntervalUnitsToString(pair.value.GetUnitsEnum()) << std::endl; + }; + + values.ForeachItem(print); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + auto print = [](const Indexed& pair) + { + std::cout << "BinaryCommandEvent: " << + "[" << pair.index << "] : " << + pair.value.time << " : " << + pair.value.value << " : " << + CommandStatusToString(pair.value.status) << std::endl; + }; + + values.ForeachItem(print); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + auto print = [](const Indexed& pair) + { + std::cout << "AnalogCommandEvent: " << + "[" << pair.index << "] : " << + pair.value.time << " : " << + pair.value.value << " : " << + CommandStatusToString(pair.value.status) << std::endl; + }; + + values.ForeachItem(print); +} + +void PrintingSOEHandler::Process(const HeaderInfo& info, const ICollection>& values) +{ + auto print = [](const Indexed& pair) + { + std::cout << "SecurityStat: " << + "[" << pair.index << "] : " << + pair.value.time << " : " << + pair.value.value.count << " : " << + static_cast(pair.value.quality) << " : " << + pair.value.value.assocId << std::endl; + }; + + values.ForeachItem(print); +} + +void PrintingSOEHandler::Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection& values) +{ + auto print = [](const DNPTime & value) + { + std::cout << "DNPTime: " << value.value << std::endl; + }; + + values.ForeachItem(print); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.cpp new file mode 100644 index 0000000..46d5b84 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.cpp @@ -0,0 +1,97 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiodnp3/SerialIOHandler.h" + +#include "openpal/logging/LogMacros.h" +#include "opendnp3/LogLevels.h" + +namespace asiodnp3 +{ + +SerialIOHandler::SerialIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::ChannelRetry& retry, + const asiopal::SerialSettings& settings +) : + IOHandler(logger, listener), + executor(executor), + retry(retry), + settings(settings), + retrytimer(*executor) +{} + +void SerialIOHandler::ShutdownImpl() +{ + this->ResetState(); +} + +void SerialIOHandler::BeginChannelAccept() +{ + this->TryOpen(retry.minOpenRetry); +} + +void SerialIOHandler::SuspendChannelAccept() +{ + this->retrytimer.Cancel(); +} + +void SerialIOHandler::OnChannelShutdown() +{ + this->BeginChannelAccept(); +} + +void SerialIOHandler::TryOpen(const openpal::TimeDuration& timeout) +{ + auto port = std::make_shared(executor); + + std::error_code ec; + port->Open(settings, ec); + + if (ec) + { + FORMAT_LOG_BLOCK(this->logger, openpal::logflags::WARN, "Error Connecting: %s", ec.message().c_str()); + + ++this->statistics.numOpenFail; + + auto callback = [this, timeout]() + { + this->TryOpen(this->retry.NextDelay(timeout)); + }; + + this->retrytimer.Start(timeout, callback); + } + else + { + this->OnNewChannel(port); + } +} + +void SerialIOHandler::ResetState() +{ + retrytimer.Cancel(); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.h new file mode 100644 index 0000000..c2b3fb9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/SerialIOHandler.h @@ -0,0 +1,82 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_SERIALIOHANDLER_H +#define ASIOPAL_SERIALIOHANDLER_H + +#include "asiodnp3/IOHandler.h" + +#include "asiopal/ChannelRetry.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/SerialTypes.h" +#include "asiopal/SerialChannel.h" + +#include "openpal/executor/TimerRef.h" + +namespace asiodnp3 +{ + +class SerialIOHandler final : public IOHandler +{ + +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::ChannelRetry& retry, + const asiopal::SerialSettings& settings) + { + return std::make_shared(logger, listener, executor, retry, settings); + } + + SerialIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::ChannelRetry& retry, + const asiopal::SerialSettings& settings + ); + +protected: + + virtual void ShutdownImpl() override; + virtual void BeginChannelAccept() override; + virtual void SuspendChannelAccept() override; + virtual void OnChannelShutdown() override; + +private: + + void TryOpen(const openpal::TimeDuration& retry); + + void ResetState(); + + const std::shared_ptr executor; + const asiopal::ChannelRetry retry; + const asiopal::SerialSettings settings; + + // connection retry timer + openpal::TimerRef retrytimer; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/StackBase.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/StackBase.h new file mode 100644 index 0000000..cfe4b76 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/StackBase.h @@ -0,0 +1,97 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef ASIODNP3_STACKBASE_H +#define ASIODNP3_STACKBASE_H + +#include "asiodnp3/IStack.h" +#include "asiopal/Executor.h" +#include "asiopal/IResourceManager.h" +#include "asiodnp3/IOHandler.h" +#include "opendnp3/transport/TransportStack.h" + +namespace asiodnp3 +{ + +/** +* Base class for masters or outstations +*/ +class StackBase +{ + +protected: + + StackBase( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& listener, + const std::shared_ptr& iohandler, + const std::shared_ptr& manager, + uint32_t maxRxFragSize, + const opendnp3::LinkConfig& config) : + logger(logger), + executor(executor), + iohandler(iohandler), + manager(manager), + tstack(logger, executor, listener, maxRxFragSize, config) + { + + } + + opendnp3::StackStatistics CreateStatistics() const + { + return opendnp3::StackStatistics(tstack.link->GetStatistics(), tstack.transport->GetStatistics()); + } + + template + void PerformShutdown(const std::shared_ptr& self); + + openpal::Logger logger; + const std::shared_ptr executor; + const std::shared_ptr iohandler; + const std::shared_ptr manager; + opendnp3::TransportStack tstack; + +}; + +template +void StackBase::PerformShutdown(const std::shared_ptr& self) +{ + auto shutdown = [self] + { + self->iohandler->Remove(self); + + // since posting to a strand from the strand is ordered, posting + // this forces the MasterStack to hang around long enough for + // any previously submitted post operations on the strand to complete + auto detach = [self]() + { + self->manager->Detach(self); + }; + self->executor->strand.post(detach); + }; + + this->executor->BlockUntilAndFlush(shutdown); +} + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.cpp new file mode 100644 index 0000000..b8f5b0f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.cpp @@ -0,0 +1,115 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "TCPClientIOHandler.h" + +#include "asiopal/SocketChannel.h" + +using namespace asiopal; + +namespace asiodnp3 +{ + +TCPClientIOHandler::TCPClientIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::ChannelRetry& retry, + const asiopal::IPEndpoint& remote, + const std::string& adapter +) : + IOHandler(logger, listener), + executor(executor), + retry(retry), + remote(remote), + adapter(adapter), + retrytimer(*executor) +{} + +void TCPClientIOHandler::ShutdownImpl() +{ + this->ResetState(); +} + +void TCPClientIOHandler::BeginChannelAccept() +{ + this->client = TCPClient::Create(logger, executor, remote, adapter); + this->StartConnect(this->client, this->retry.minOpenRetry); +} + +void TCPClientIOHandler::SuspendChannelAccept() +{ + this->ResetState(); +} + +void TCPClientIOHandler::OnChannelShutdown() +{ + this->BeginChannelAccept(); +} + +void TCPClientIOHandler::StartConnect(const std::shared_ptr& client, const openpal::TimeDuration& delay) +{ + FORMAT_LOG_BLOCK(this->logger, openpal::logflags::INFO, "Connecting to: %s", this->remote.address.c_str()); + + auto cb = [ =, self = shared_from_this()](const std::shared_ptr& executor, asio::ip::tcp::socket socket, const std::error_code & ec) -> void + { + if (ec) + { + FORMAT_LOG_BLOCK(this->logger, openpal::logflags::WARN, "Error Connecting: %s", ec.message().c_str()); + + ++this->statistics.numOpenFail; + + const auto newDelay = this->retry.NextDelay(delay); + + auto cb = [self, newDelay, client, this]() + { + this->StartConnect(client, newDelay); + }; + + this->retrytimer.Start(delay, cb); + } + else + { + FORMAT_LOG_BLOCK(this->logger, openpal::logflags::INFO, "Connected to: %s", this->remote.address.c_str()); + + this->OnNewChannel(SocketChannel::Create(executor, std::move(socket))); + } + + }; + + this->client->BeginConnect(cb); +} + +void TCPClientIOHandler::ResetState() +{ + if (this->client) + { + this->client->Cancel(); + this->client.reset(); + } + + retrytimer.Cancel(); +} + +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.h new file mode 100644 index 0000000..fcd2a01 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPClientIOHandler.h @@ -0,0 +1,87 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TCPCLIENTIOHANDLER_H +#define ASIOPAL_TCPCLIENTIOHANDLER_H + +#include "asiodnp3/IOHandler.h" + +#include "asiopal/ChannelRetry.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/TCPClient.h" + +#include "openpal/executor/TimerRef.h" + +namespace asiodnp3 +{ + +class TCPClientIOHandler final : public IOHandler +{ + +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::ChannelRetry& retry, + const asiopal::IPEndpoint& remote, + const std::string& adapter) + { + return std::make_shared(logger, listener, executor, retry, remote, adapter); + } + + TCPClientIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::ChannelRetry& retry, + const asiopal::IPEndpoint& remote, + const std::string& adapter + ); + +protected: + + virtual void ShutdownImpl() override; + virtual void BeginChannelAccept() override; + virtual void SuspendChannelAccept() override; + virtual void OnChannelShutdown() override; + +private: + + void StartConnect(const std::shared_ptr& client, const openpal::TimeDuration& delay); + + void ResetState(); + + const std::shared_ptr executor; + const asiopal::ChannelRetry retry; + const asiopal::IPEndpoint remote; + const std::string adapter; + + // current value of the client + std::shared_ptr client; + + // connection retry timer + openpal::TimerRef retrytimer; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.cpp new file mode 100644 index 0000000..f28d1c3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.cpp @@ -0,0 +1,103 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "TCPServerIOHandler.h" + +#include "asiopal/SocketChannel.h" + +#include "opendnp3/LogLevels.h" + +#include "openpal/logging/LogMacros.h" + +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + + +void TCPServerIOHandler::Server::AcceptConnection(uint64_t sessionid, const std::shared_ptr& executor, asio::ip::tcp::socket socket) +{ + this->callback(executor, std::move(socket)); +} + +TCPServerIOHandler::TCPServerIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + std::error_code& ec +) : + IOHandler(logger, listener), + executor(executor), + endpoint(endpoint) +{} + +void TCPServerIOHandler::ShutdownImpl() +{ + if (this->server) + { + this->server->Shutdown(); + this->server.reset(); + } +} + +void TCPServerIOHandler::BeginChannelAccept() +{ + auto callback = [self = shared_from_this(), this](const std::shared_ptr& executor, asio::ip::tcp::socket socket) + { + this->OnNewChannel(SocketChannel::Create(executor, std::move(socket))); + }; + + if (this->server) + { + this->server->StartAcceptingConnection(callback); + } + else + { + std::error_code ec; + this->server = std::make_shared(this->logger, this->executor, this->endpoint, ec); + + if (ec) + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, ec.message().c_str()); + + // TODO - should we retry? + } + else + { + this->server->StartAcceptingConnection(callback); + } + } +} + +void TCPServerIOHandler::SuspendChannelAccept() +{ + if (this->server) + { + this->server->Shutdown(); + this->server.reset(); + } +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.h new file mode 100644 index 0000000..8e35a43 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/TCPServerIOHandler.h @@ -0,0 +1,104 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#ifndef ASIOPAL_TCPSERVERIOHANDLER_H +#define ASIOPAL_TCPSERVERIOHANDLER_H + +#include "asiodnp3/IOHandler.h" + +#include "asiopal/ChannelRetry.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/TCPServer.h" + +#include "openpal/executor/TimerRef.h" + +namespace asiodnp3 +{ + +class TCPServerIOHandler final : public IOHandler +{ + class Server final : public asiopal::TCPServer + { + public: + + typedef std::function& executor, asio::ip::tcp::socket)> callback_t; + + Server( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + std::error_code& ec + ) : + TCPServer(logger, executor, endpoint, ec) + {} + + void StartAcceptingConnection(const callback_t& callback) + { + this->callback = callback; + this->StartAccept(); + } + + private: + + callback_t callback; + + virtual void OnShutdown() override {} + + virtual void AcceptConnection(uint64_t sessionid, const std::shared_ptr& executor, asio::ip::tcp::socket) override; + }; + +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + std::error_code& ec) + { + return std::make_shared(logger, listener, executor, endpoint, ec); + } + + TCPServerIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + std::error_code& ec + ); + +protected: + + virtual void ShutdownImpl() override; + virtual void BeginChannelAccept() override; + virtual void SuspendChannelAccept() override; + virtual void OnChannelShutdown() override {} // do nothing, always accepting new connections + +private: + + const std::shared_ptr executor; + const asiopal::IPEndpoint endpoint; + std::shared_ptr server; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/UpdateBuilder.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/UpdateBuilder.cpp new file mode 100644 index 0000000..693ae5d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/UpdateBuilder.cpp @@ -0,0 +1,107 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiodnp3/UpdateBuilder.h" + +using namespace opendnp3; + +namespace asiodnp3 +{ + +Updates UpdateBuilder::Build() const +{ + return Updates(std::move(this->updates)); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::Binary& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::DoubleBitBinary& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::Analog& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::Counter& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::FrozenCounter& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::BinaryOutputStatus& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::AnalogOutputStatus& meas, uint16_t index, opendnp3::EventMode mode) +{ + return this->AddMeas(meas, index, mode); +} + +UpdateBuilder& UpdateBuilder::Update(const opendnp3::TimeAndInterval& meas, uint16_t index) +{ + this->Add([ = ](IUpdateHandler & handler) + { + handler.Update(meas, index); + }); + return *this; +} + +UpdateBuilder& UpdateBuilder::Modify(FlagsType type, uint16_t start, uint16_t stop, uint8_t flags) +{ + this->Add([ = ](IUpdateHandler & handler) + { + handler.Modify(type, start, stop, flags); + }); + return *this; +} + +template +UpdateBuilder& UpdateBuilder::AddMeas(const T& meas, uint16_t index, opendnp3::EventMode mode) +{ + this->Add([ = ](IUpdateHandler & handler) + { + handler.Update(meas, index, mode); + }); + return *this; +} + +void UpdateBuilder::Add(const update_func_t& fun) +{ + if (!this->updates) + { + this->updates = std::make_shared(); + } + + updates->push_back(fun); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.cpp new file mode 100644 index 0000000..2116126 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.cpp @@ -0,0 +1,137 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiodnp3/tls/MasterTLSServer.h" + +#include "asiodnp3/LinkSession.h" + +#include "asiopal/tls/TLSStreamChannel.h" + +#include +#include + +using namespace openpal; +using namespace asiopal; +using namespace opendnp3; + +namespace asiodnp3 +{ + +MasterTLSServer::MasterTLSServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const asiopal::TLSConfig& config, + const std::shared_ptr& callbacks, + const std::shared_ptr& manager, + std::error_code& ec +) : + TLSServer(logger, executor, endpoint, config, ec), + callbacks(callbacks), + manager(manager) +{ + +} + +bool MasterTLSServer::AcceptConnection(uint64_t sessionid, const asio::ip::tcp::endpoint& remote) +{ + std::ostringstream oss; + oss << remote; + + if (this->callbacks->AcceptConnection(sessionid, remote.address().to_string())) + { + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Accepted connection from: %s", oss.str().c_str()); + return true; + } + else + { + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Rejected connection from: %s", oss.str().c_str()); + return false; + } +} + +bool MasterTLSServer::VerifyCallback(uint64_t sessionid, bool preverified, asio::ssl::verify_context& ctx) +{ + const int MAX_SUBJECT_NAME = 512; + int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); + + // lookup the subject name + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + char subjectName[MAX_SUBJECT_NAME]; + X509_NAME_oneline(X509_get_subject_name(cert), subjectName, MAX_SUBJECT_NAME); + + X509Info info( + depth, + RSlice(cert->sha1_hash, SHA_DIGEST_LENGTH), // the thumbprint + std::string(subjectName) + ); + + if (!preverified) + { + int err = X509_STORE_CTX_get_error(ctx.native_handle()); + + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Error verifying certificate at depth: %d subject: %s error: %d:%s", depth, subjectName, err, X509_verify_cert_error_string(err)); + + this->callbacks->OnCertificateError(sessionid, info, err); + + return preverified; + } + + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Verified certificate at depth: %d subject: %s", depth, subjectName); + + return this->callbacks->AcceptCertificate(sessionid, info); +} + +void MasterTLSServer::AcceptStream(uint64_t sessionid, const std::shared_ptr& executor, std::shared_ptr> stream) +{ + auto channel = TLSStreamChannel::Create(executor->Fork(), stream); // run the link session in a new strand + + auto create = [&]() -> std::shared_ptr + { + return LinkSession::Create( + this->logger.Detach(SessionIdToString(sessionid)), + sessionid, + this->manager, + callbacks, + channel + ); + }; + + if (!this->manager->Bind(create)) + { + channel->Shutdown(); + } +} + +void MasterTLSServer::OnShutdown() +{ + this->manager->Detach(this->shared_from_this()); +} + +std::string MasterTLSServer::SessionIdToString(uint64_t sessionid) +{ + std::ostringstream oss; + oss << "session-" << sessionid; + return oss.str(); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.h new file mode 100644 index 0000000..a8def24 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/MasterTLSServer.h @@ -0,0 +1,98 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_MASTERTLSSERVER_H +#define ASIOPAL_MASTERTLSSERVER_H + +#include + +#include + +#include +#include +#include + +#include "asiodnp3/IListenCallbacks.h" + +namespace asiodnp3 +{ + +class MasterTLSServer final : public asiopal::TLSServer +{ + +public: + + MasterTLSServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const asiopal::TLSConfig& tlsConfig, + const std::shared_ptr& callbacks, + const std::shared_ptr& manager, + std::error_code& ec + ); + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr executor, + const asiopal::IPEndpoint endpoint, + const asiopal::TLSConfig& tlsConfig, + const std::shared_ptr callbacks, + const std::shared_ptr& manager, + std::error_code& ec) + { + auto ret = std::make_shared(logger, executor, endpoint, tlsConfig, callbacks, manager, ec); + + if (ec) return nullptr; + + ret->StartAccept(ec); + + if (ec) + { + return nullptr; + } + + return ret; + } + + virtual bool AcceptConnection(uint64_t sessionid, const asio::ip::tcp::endpoint& remote) override; + + virtual bool VerifyCallback(uint64_t sessionid, bool preverified, asio::ssl::verify_context& ctx) override; + + virtual void AcceptStream( + uint64_t sessionid, + const std::shared_ptr& executor, + std::shared_ptr> stream + ) override; + + virtual void OnShutdown() override; + +private: + + std::shared_ptr callbacks; + std::shared_ptr manager; + + static std::string SessionIdToString(uint64_t sessionid); + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.cpp new file mode 100644 index 0000000..3fbb4e7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.cpp @@ -0,0 +1,125 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "TLSClientIOHandler.h" + +#include "asiopal/tls/TLSStreamChannel.h" +#include "opendnp3/LogLevels.h" + +using namespace asiopal; + +namespace asiodnp3 +{ + +TLSClientIOHandler::TLSClientIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::TLSConfig& config, + const asiopal::ChannelRetry& retry, + const asiopal::IPEndpoint& remote, + const std::string& adapter +) : + IOHandler(logger, listener), + executor(executor), + config(config), + retry(retry), + remote(remote), + adapter(adapter), + retrytimer(*executor) +{} + +void TLSClientIOHandler::ShutdownImpl() +{ + this->ResetState(); +} + +void TLSClientIOHandler::BeginChannelAccept() +{ + std::error_code ec; + + this->client = TLSClient::Create(logger, executor, remote, adapter, config, ec); + + if (ec) + { + this->client.reset(); + } + else + { + this->StartConnect(this->client, this->retry.minOpenRetry); + } +} + +void TLSClientIOHandler::SuspendChannelAccept() +{ + this->ResetState(); +} + +void TLSClientIOHandler::OnChannelShutdown() +{ + this->BeginChannelAccept(); +} + +void TLSClientIOHandler::StartConnect(const std::shared_ptr& client, const openpal::TimeDuration& delay) +{ + auto cb = [ =, self = shared_from_this()](const std::shared_ptr& executor, const std::shared_ptr>& stream, const std::error_code & ec) -> void + { + if (ec) + { + FORMAT_LOG_BLOCK(this->logger, openpal::logflags::WARN, "Error Connecting: %s", ec.message().c_str()); + + ++this->statistics.numOpenFail; + + const auto newDelay = this->retry.NextDelay(delay); + + auto cb = [self, newDelay, client, this]() + { + this->StartConnect(client, newDelay); + }; + + this->retrytimer.Start(delay, cb); + } + else + { + FORMAT_LOG_BLOCK(this->logger, openpal::logflags::INFO, "Connected to: %s", this->remote.address.c_str()); + + this->OnNewChannel(TLSStreamChannel::Create(executor, stream)); + } + + }; + + this->client->BeginConnect(cb); +} + +void TLSClientIOHandler::ResetState() +{ + if (this->client) + { + this->client->Cancel(); + this->client.reset(); + } + + retrytimer.Cancel(); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.h new file mode 100644 index 0000000..389270d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSClientIOHandler.h @@ -0,0 +1,92 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TLSCLIENTIOHANDLER_H +#define ASIOPAL_TLSCLIENTIOHANDLER_H + +#include "asiodnp3/IOHandler.h" + +#include "asiopal/ChannelRetry.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/TCPClient.h" +#include "asiopal/TLSConfig.h" +#include "asiopal/tls/TLSClient.h" + +#include "openpal/executor/TimerRef.h" + +namespace asiodnp3 +{ + +class TLSClientIOHandler final : public IOHandler +{ + +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::TLSConfig& config, + const asiopal::ChannelRetry& retry, + const asiopal::IPEndpoint& remote, + const std::string& adapter) + { + return std::make_shared(logger, listener, executor, config, retry, remote, adapter); + } + + TLSClientIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::TLSConfig& config, + const asiopal::ChannelRetry& retry, + const asiopal::IPEndpoint& remote, + const std::string& adapter + ); + +protected: + + virtual void ShutdownImpl() override; + virtual void BeginChannelAccept() override; + virtual void SuspendChannelAccept() override; + virtual void OnChannelShutdown() override; + +private: + + void StartConnect(const std::shared_ptr& client, const openpal::TimeDuration& delay); + + void ResetState(); + + const std::shared_ptr executor; + const asiopal::TLSConfig config; + const asiopal::ChannelRetry retry; + const asiopal::IPEndpoint remote; + const std::string adapter; + + // current value of the client + std::shared_ptr client; + + // connection retry timer + openpal::TimerRef retrytimer; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.cpp b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.cpp new file mode 100644 index 0000000..ef7c488 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.cpp @@ -0,0 +1,97 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiodnp3/tls/TLSServerIOHandler.h" + +#include "asiopal/tls/TLSStreamChannel.h" + +#include "opendnp3/LogLevels.h" + +#include "openpal/logging/LogMacros.h" + +using namespace opendnp3; +using namespace asiopal; + +namespace asiodnp3 +{ + +void TLSServerIOHandler::Server::AcceptStream(uint64_t sessionid, const std::shared_ptr& executor, std::shared_ptr> stream) +{ + this->callback(asiopal::TLSStreamChannel::Create(executor, stream)); +} + +TLSServerIOHandler::TLSServerIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const asiopal::TLSConfig& config, + std::error_code& ec +) : + IOHandler(logger, listener), + executor(executor), + endpoint(endpoint), + config(config) +{} + + +void TLSServerIOHandler::ShutdownImpl() +{ + if (this->server) + { + this->server->Shutdown(); + this->server.reset(); + } +} + +void TLSServerIOHandler::BeginChannelAccept() +{ + auto callback = [self = shared_from_this(), this](const std::shared_ptr& channel) + { + this->OnNewChannel(channel); + }; + + std::error_code ec; + this->server = std::make_shared(this->logger, this->executor, this->endpoint, this->config, ec); + + if (ec) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, ec.message().c_str()); + } + else + { + this->server->StartAcceptingConnection(callback, ec); + FORMAT_LOG_BLOCK(this->logger, flags::ERR, "Unable to begin accepting connections: %s", ec.message().c_str()); + } +} + +void TLSServerIOHandler::SuspendChannelAccept() +{ + if (this->server) + { + this->server->Shutdown(); + this->server.reset(); + } +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.h b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.h new file mode 100644 index 0000000..64a3174 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiodnp3/tls/TLSServerIOHandler.h @@ -0,0 +1,116 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#ifndef ASIOPAL_TLSSERVERIOHANDLER_H +#define ASIOPAL_TLSSERVERIOHANDLER_H + +#include "asiodnp3/IOHandler.h" + +#include "asiopal/ChannelRetry.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/tls/TLSServer.h" + +#include "openpal/executor/TimerRef.h" + +namespace asiodnp3 +{ + +class TLSServerIOHandler final : public IOHandler +{ + class Server final : public asiopal::TLSServer + { + public: + + typedef std::function& )> callback_t; + + Server( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const asiopal::TLSConfig& config, + std::error_code& ec + ) : + TLSServer(logger, executor, endpoint, config, ec) + {} + + void StartAcceptingConnection(const callback_t& callback, std::error_code& ec) + { + this->callback = callback; + this->StartAccept(ec); + } + + private: + + callback_t callback; + + virtual bool AcceptConnection(uint64_t sessionid, const asio::ip::tcp::endpoint& remote) override + { + return true; + } + virtual bool VerifyCallback(uint64_t sessionid, bool preverified, asio::ssl::verify_context& ctx) override + { + return preverified; + } + virtual void OnShutdown() override {} + + virtual void AcceptStream(uint64_t sessionid, const std::shared_ptr& executor, std::shared_ptr> stream) override; + }; + +public: + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const asiopal::TLSConfig& config, + std::error_code& ec) + { + return std::make_shared(logger, listener, executor, endpoint, config, ec); + } + + TLSServerIOHandler( + const openpal::Logger& logger, + const std::shared_ptr& listener, + const std::shared_ptr& executor, + const asiopal::IPEndpoint& endpoint, + const asiopal::TLSConfig& config, + std::error_code& ec + ); + +protected: + + virtual void ShutdownImpl() override; + virtual void BeginChannelAccept() override; + virtual void SuspendChannelAccept() override; + virtual void OnChannelShutdown() override {} // do nothing, always accepting new connections + +private: + + const std::shared_ptr executor; + const asiopal::IPEndpoint endpoint; + const asiopal::TLSConfig config; + std::shared_ptr server; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/ASIOSerialHelpers.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/ASIOSerialHelpers.cpp new file mode 100644 index 0000000..65d1125 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/ASIOSerialHelpers.cpp @@ -0,0 +1,131 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiopal/ASIOSerialHelpers.h" + +#include + +#include +#include + +#include + +using namespace asio; +using namespace opendnp3; + +namespace asiopal +{ + +////////////////////////////////////////////// +// Private Helpers +////////////////////////////////////////////// +serial_port_base::stop_bits ConvertStopBits(opendnp3::StopBits stopBits) +{ + serial_port_base::stop_bits::type t = serial_port_base::stop_bits::one; + + switch(stopBits) + { + case(opendnp3::StopBits::One): + t = serial_port_base::stop_bits::one; + break; + case(opendnp3::StopBits::OnePointFive) : + t = serial_port_base::stop_bits::onepointfive; + break; + case(opendnp3::StopBits::Two) : + t = serial_port_base::stop_bits::two; + break; + default: + break; + } + + return serial_port_base::stop_bits(t); +} + +serial_port_base::flow_control ConvertFlow(opendnp3::FlowControl flowType) +{ + serial_port_base::flow_control::type t = serial_port_base::flow_control::none; + + switch(flowType) + { + case(opendnp3::FlowControl::None): + t = serial_port_base::flow_control::none; + break; + case(opendnp3::FlowControl::XONXOFF) : + t = serial_port_base::flow_control::software; + break; + case(opendnp3::FlowControl::Hardware) : + t = serial_port_base::flow_control::hardware; + break; + default: + break; + } + + return serial_port_base::flow_control(t); +} + +serial_port_base::character_size ConvertDataBits(int aDataBits) +{ + return serial_port_base::character_size(static_cast(aDataBits)); +} + +serial_port_base::baud_rate ConvertBaud(int aBaud) +{ + return serial_port_base::baud_rate(static_cast(aBaud)); +} + +serial_port_base::parity ConvertParity(opendnp3::Parity parity) +{ + serial_port_base::parity::type t = serial_port_base::parity::none; + + switch(parity) + { + case(opendnp3::Parity::Even): + t = serial_port_base::parity::even; + break; + case(opendnp3::Parity::Odd) : + t = serial_port_base::parity::odd; + break; + default: + break; + } + + return serial_port_base::parity(t); +} + +bool Configure(const SerialSettings& settings, asio::serial_port& port, error_code& ec) +{ + //Set all the various options + port.set_option(ConvertBaud(settings.baud), ec); + if (ec) return false; + + port.set_option(ConvertDataBits(settings.dataBits), ec); + if (ec) return false; + + port.set_option(ConvertParity(settings.parity), ec); + if (ec) return false; + + port.set_option(ConvertStopBits(settings.stopBits), ec); + if (ec) return false; + + return true; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/ChannelRetry.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/ChannelRetry.cpp new file mode 100644 index 0000000..a5e29c8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/ChannelRetry.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiopal/ChannelRetry.h" + +using namespace openpal; + +namespace asiopal +{ + +ChannelRetry::ChannelRetry( + openpal::TimeDuration minOpenRetry_, + openpal::TimeDuration maxOpenRetry_, + IOpenDelayStrategy& strategy_ +) : + minOpenRetry(minOpenRetry_), + maxOpenRetry(maxOpenRetry_), + strategy(strategy_) +{} + +ChannelRetry ChannelRetry::Default() +{ + return ChannelRetry(TimeDuration::Seconds(1), TimeDuration::Minutes(1)); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/Executor.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/Executor.cpp new file mode 100644 index 0000000..6c3b70f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/Executor.cpp @@ -0,0 +1,118 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiopal/Executor.h" +#include "asiopal/Timer.h" + +#include "asiopal/TimeConversions.h" + +#include + +using namespace openpal; + +namespace asiopal +{ + +Executor::Executor(const std::shared_ptr& io) : + io(io), + strand(io->service) +{ + +} + +MonotonicTimestamp Executor::GetTime() +{ + return TimeConversions::Convert(steady_clock_t::now()); +} + +ITimer* Executor::Start(const TimeDuration& delay, const action_t& runnable) +{ + const auto now = steady_clock_t::now(); + const auto max_ms = std::chrono::duration_cast(steady_clock_t::time_point::max() - now).count(); + const auto expiration = (delay.milliseconds > max_ms) ? steady_clock_t::time_point::max() : (now + std::chrono::milliseconds(delay.milliseconds)); + + return Start(expiration, runnable); +} + +ITimer* Executor::Start(const MonotonicTimestamp& time, const action_t& runnable) +{ + return Start(TimeConversions::Convert(time), runnable); +} + +openpal::ITimer* Executor::Start(const steady_clock_t::time_point& expiration, const openpal::action_t& runnable) +{ + auto timer = std::make_shared(this->strand.get_io_service()); + + timer->timer.expires_at(expiration); + + // neither the executor nor the timer can be deleted while the timer is still active + auto callback = [timer, runnable, self = shared_from_this()](const std::error_code & ec) + { + if (!ec) // an error indicate timer was canceled + { + runnable(); + } + }; + + timer->timer.async_wait(strand.wrap(callback)); + + return timer.get(); +} + +void Executor::Post(const action_t& runnable) +{ + auto callback = [runnable, self = shared_from_this()]() + { + runnable(); + }; + strand.post(callback); +} + +void Executor::BlockUntil(const std::function& action) +{ + if (strand.running_in_this_thread()) + { + action(); + return; + } + + std::promise ready; + + auto future = ready.get_future(); + + auto run = [&] + { + action(); + ready.set_value(true); + }; + + strand.post(run); + + future.wait(); +} + +void Executor::BlockUntilAndFlush(const std::function& action) +{ + this->BlockUntil(action); + this->BlockUntil([]() {}); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/IOpenDelayStrategy.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/IOpenDelayStrategy.cpp new file mode 100644 index 0000000..4bd55e8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/IOpenDelayStrategy.cpp @@ -0,0 +1,42 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiopal/IOpenDelayStrategy.h" + + +namespace asiopal +{ + +ExponentialBackoffStrategy ExponentialBackoffStrategy::instance; + +IOpenDelayStrategy& ExponentialBackoffStrategy::Instance() +{ + return instance; +} + +openpal::TimeDuration ExponentialBackoffStrategy::GetNextDelay(const openpal::TimeDuration& current, const openpal::TimeDuration& max) const +{ + int64_t doubled = 2 * current.GetMilliseconds(); + return (doubled > max.GetMilliseconds()) ? max : openpal::TimeDuration::Milliseconds(doubled); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/ResourceManager.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/ResourceManager.cpp new file mode 100644 index 0000000..816163c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/ResourceManager.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiopal/ResourceManager.h" + +namespace asiopal +{ + +void ResourceManager::Detach(const std::shared_ptr& resource) +{ + std::lock_guard lock(this->mutex); + this->resources.erase(resource); +} + +void ResourceManager::Shutdown() +{ + std::set> copy; + + { + std::lock_guard lock(this->mutex); + this->is_shutting_down = true; + for (auto& resource : this->resources) + { + copy.insert(resource); + } + resources.clear(); + } + + for (auto& resource : copy) + { + resource->Shutdown(); + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/SerialChannel.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/SerialChannel.cpp new file mode 100644 index 0000000..7ab49f3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/SerialChannel.cpp @@ -0,0 +1,77 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/SerialChannel.h" + +#include "asiopal/ASIOSerialHelpers.h" + + +namespace asiopal +{ + +SerialChannel::SerialChannel(std::shared_ptr executor) : IAsyncChannel(executor), port(executor->strand.get_io_service()) +{} + +bool SerialChannel::Open(const SerialSettings& settings, std::error_code& ec) +{ + port.open(settings.deviceName, ec); + if (ec) return false; + + Configure(settings, port, ec); + + if (ec) + { + port.close(); + return false; + } + + return true; +} + +void SerialChannel::BeginReadImpl(openpal::WSlice buffer) +{ + auto callback = [this](const std::error_code & ec, size_t num) + { + this->OnReadCallback(ec, num); + }; + + port.async_read_some(asio::buffer(buffer, buffer.Size()), this->executor->strand.wrap(callback)); +} + +void SerialChannel::BeginWriteImpl(const openpal::RSlice& buffer) +{ + auto callback = [this](const std::error_code & ec, size_t num) + { + this->OnWriteCallback(ec, num); + }; + + async_write(port, asio::buffer(buffer, buffer.Size()), this->executor->strand.wrap(callback)); +} + +void SerialChannel::ShutdownImpl() +{ + std::error_code ec; + port.close(ec); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/SocketChannel.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/SocketChannel.cpp new file mode 100644 index 0000000..b22afe7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/SocketChannel.cpp @@ -0,0 +1,59 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/SocketChannel.h" + +namespace asiopal +{ + +SocketChannel::SocketChannel(std::shared_ptr executor, asio::ip::tcp::socket socket) : IAsyncChannel(executor), socket(std::move(socket)) +{ + +} + +void SocketChannel::BeginReadImpl(openpal::WSlice dest) +{ + auto callback = [this](const std::error_code & ec, size_t num) + { + this->OnReadCallback(ec, num); + }; + + socket.async_read_some(asio::buffer(dest, dest.Size()), this->executor->strand.wrap(callback)); +} + +void SocketChannel::BeginWriteImpl(const openpal::RSlice& buffer) +{ + auto callback = [this](const std::error_code & ec, size_t num) + { + this->OnWriteCallback(ec, num); + }; + + asio::async_write(socket, asio::buffer(buffer, buffer.Size()), this->executor->strand.wrap(callback)); +} + +void SocketChannel::ShutdownImpl() +{ + std::error_code ec; + socket.shutdown(asio::socket_base::shutdown_type::shutdown_both, ec); + socket.close(ec); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/TCPClient.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/TCPClient.cpp new file mode 100644 index 0000000..7ff6c2c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/TCPClient.cpp @@ -0,0 +1,153 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/TCPClient.h" + +#include "asiopal/SocketHelpers.h" + +namespace asiopal +{ + +TCPClient::TCPClient( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& remote, + const std::string& adapter +) : + condition(logger), + executor(executor), + host(remote.address), + adapter(adapter), + socket(executor->strand.get_io_service()), + remoteEndpoint(asio::ip::tcp::v4(), remote.port), + localEndpoint(), + resolver(executor->strand.get_io_service()) +{} + + +bool TCPClient::Cancel() +{ + if (this->canceled || !this->connecting) + { + return false; + } + + std::error_code ec; + socket.cancel(ec); + resolver.cancel(); + this->canceled = true; + return true; +} + +bool TCPClient::BeginConnect(const connect_callback_t& callback) +{ + if (connecting || canceled) return false; + + this->connecting = true; + + std::error_code ec; + SocketHelpers::BindToLocalAddress(this->adapter, this->localEndpoint, this->socket, ec); + + if (ec) + { + return this->PostConnectError(callback, ec); + } + + const auto address = asio::ip::address::from_string(this->host, ec); + auto self = this->shared_from_this(); + if (ec) + { + // Try DNS resolution instead + auto cb = [self, callback](const std::error_code & ec, asio::ip::tcp::resolver::iterator endpoints) + { + self->HandleResolveResult(callback, endpoints, ec); + }; + + std::stringstream portstr; + portstr << remoteEndpoint.port(); + + resolver.async_resolve( + asio::ip::tcp::resolver::query(host, portstr.str()), + executor->strand.wrap(cb) + ); + + return true; + } + else + { + remoteEndpoint.address(address); + auto cb = [self, callback](const std::error_code & ec) + { + self->connecting = false; + if (!self->canceled) + { + callback(self->executor, std::move(self->socket), ec); + } + }; + + socket.async_connect(remoteEndpoint, executor->strand.wrap(cb)); + return true; + } +} + +void TCPClient::HandleResolveResult( + const connect_callback_t& callback, + const asio::ip::tcp::resolver::iterator& endpoints, + const std::error_code& ec +) +{ + if (ec) + { + this->PostConnectError(callback, ec); + } + else + { + // attempt a connection to each endpoint in the iterator until we connect + auto cb = [self = shared_from_this(), callback](const std::error_code & ec, asio::ip::tcp::resolver::iterator endpoints) + { + self->connecting = false; + if (!self->canceled) + { + callback(self->executor, std::move(self->socket), ec); + } + }; + + asio::async_connect(this->socket, endpoints, this->condition, this->executor->strand.wrap(cb)); + } +} + +bool TCPClient::PostConnectError(const connect_callback_t& callback, const std::error_code& ec) +{ + auto cb = [self = shared_from_this(), ec, callback]() + { + self->connecting = false; + if (!self->canceled) + { + callback(self->executor, std::move(self->socket), ec); + } + }; + executor->strand.post(cb); + return true; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/TCPServer.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/TCPServer.cpp new file mode 100644 index 0000000..08548bd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/TCPServer.cpp @@ -0,0 +1,132 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/TCPServer.h" + +#include +#include + +#include + +using namespace asio; +using namespace asio::ip; +using namespace opendnp3; + +namespace asiopal +{ + +TCPServer::TCPServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& endpoint, + std::error_code& ec) : + logger(logger), + executor(executor), + endpoint(ip::tcp::v4(), endpoint.port), + acceptor(executor->strand.get_io_service()), + socket(executor->strand.get_io_service()) +{ + this->Configure(endpoint.address, ec); +} + +void TCPServer::Shutdown() +{ + std::error_code ec; + this->acceptor.close(ec); + + if (ec) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, ec.message().c_str()); + } +} + +void TCPServer::Configure(const std::string& adapter, std::error_code& ec) +{ + auto address = asio::ip::address::from_string(adapter, ec); + + if (ec) + { + return; + } + + endpoint.address(address); + acceptor.open(this->endpoint.protocol(), ec); + + if (ec) + { + return; + } + + acceptor.set_option(ip::tcp::acceptor::reuse_address(true), ec); + + if (ec) + { + return; + } + + acceptor.bind(this->endpoint, ec); + + if (ec) + { + return; + } + + acceptor.listen(socket_base::max_connections, ec); + + if (!ec) + { + std::ostringstream oss; + oss << this->endpoint; + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Listening on: %s", oss.str().c_str()); + } +} + +void TCPServer::StartAccept() +{ + // this ensures that the TCPListener is never deleted during an active callback + auto callback = [self = shared_from_this()](std::error_code ec) + { + if (ec) + { + SIMPLE_LOG_BLOCK(self->logger, flags::INFO, ec.message().c_str()); + self->OnShutdown(); + } + else + { + const auto ID = self->session_id; + ++self->session_id; + + + FORMAT_LOG_BLOCK(self->logger, flags::INFO, "Accepted connection from: %s", self->remote_endpoint.address().to_string().c_str()); + + // method responsible for closing + self->AcceptConnection(ID, self->executor, std::move(self->socket)); + self->StartAccept(); + } + }; + + + this->acceptor.async_accept(socket, remote_endpoint, this->executor->strand.wrap(callback)); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/ThreadPool.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/ThreadPool.cpp new file mode 100644 index 0000000..c9bbf0b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/ThreadPool.cpp @@ -0,0 +1,98 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiopal/ThreadPool.h" + +#include +#include + +#include + +using namespace std; +using namespace std::chrono; +using namespace openpal; + +namespace asiopal +{ + +ThreadPool::ThreadPool( + const openpal::Logger& logger, + const std::shared_ptr& io, + uint32_t concurrency, + std::function onThreadStart, + std::function onThreadExit) : + logger(logger), + io(io), + onThreadStart(onThreadStart), + onThreadExit(onThreadExit), + isShutdown(false), + infiniteTimer(io->service) +{ + if(concurrency == 0) + { + concurrency = 1; + SIMPLE_LOG_BLOCK(this->logger, logflags::WARN, "Concurrency was set to 0, defaulting to 1 thread"); + } + + infiniteTimer.expires_at(asiopal::steady_clock_t::time_point::max()); + infiniteTimer.async_wait([](const std::error_code&) {}); + for(uint32_t i = 0; i < concurrency; ++i) + { + auto run = [this, i]() + { + this->Run(i); + }; + threads.push_back(std::make_unique(run)); + } +} + +ThreadPool::~ThreadPool() +{ + this->Shutdown(); + threads.clear(); +} + +void ThreadPool::Shutdown() +{ + if(!isShutdown) + { + isShutdown = true; + infiniteTimer.cancel(); + for (auto& thread : threads) + { + thread->join(); + } + } +} + +void ThreadPool::Run(int threadnum) +{ + onThreadStart(); + + FORMAT_LOG_BLOCK(this->logger, logflags::INFO, "Starting thread (%d)", threadnum); + + this->io->service.run(); + + FORMAT_LOG_BLOCK(this->logger, logflags::INFO, "Exiting thread (%d)", threadnum); + + onThreadExit(); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/TimeConversions.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/TimeConversions.cpp new file mode 100644 index 0000000..120409a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/TimeConversions.cpp @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiopal/TimeConversions.h" + +namespace asiopal +{ + +steady_clock_t::time_point TimeConversions::Convert(const openpal::MonotonicTimestamp& timestamp) +{ + return (timestamp.milliseconds > MAX_MILLISECONDS) ? steady_clock_t::time_point::max() : steady_clock_t::time_point(std::chrono::milliseconds(timestamp.milliseconds)); +} + +openpal::MonotonicTimestamp TimeConversions::Convert(const steady_clock_t::time_point& timestamp) +{ + auto ms = std::chrono::duration_cast(timestamp.time_since_epoch()).count(); + return openpal::MonotonicTimestamp(ms); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/Timer.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/Timer.cpp new file mode 100644 index 0000000..6e9df7e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/Timer.cpp @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "asiopal/Timer.h" + +#include + +using namespace openpal; + +namespace asiopal +{ + +void Timer::Cancel() +{ + timer.cancel(); +} + +MonotonicTimestamp Timer::ExpiresAt() +{ + auto millisec = std::chrono::duration_cast(timer.expires_at().time_since_epoch()).count(); + return MonotonicTimestamp(millisec); +} + +Timer::Timer(asio::io_service& service) : timer(service) +{} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/UTCTimeSource.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/UTCTimeSource.cpp new file mode 100644 index 0000000..d4194e2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/UTCTimeSource.cpp @@ -0,0 +1,43 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "asiopal/UTCTimeSource.h" + +#include + +namespace asiopal +{ + +UTCTimeSource UTCTimeSource::instance; + +openpal::IUTCTimeSource& UTCTimeSource::Instance() +{ + return instance; +} + +openpal::UTCTimestamp UTCTimeSource::Now() +{ + auto time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + return openpal::UTCTimestamp(time); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.cpp new file mode 100644 index 0000000..9c3dfaf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.cpp @@ -0,0 +1,118 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/tls/SSLContext.h" + +#include +#include + +using namespace opendnp3; + +namespace asiopal +{ +SSLContext::SSLContext(const openpal::Logger& logger, bool server, const TLSConfig& config, std::error_code& ec) : + value(server ? asio::ssl::context_base::sslv23_server : asio::ssl::context_base::sslv23_client), + logger(logger) +{ + this->ApplyConfig(config, server, ec); +} + +int SSLContext::GetVerifyMode(bool server) +{ + return server ? (asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert) : asio::ssl::verify_peer; +} + +std::error_code SSLContext::ApplyConfig(const TLSConfig& config, bool server, std::error_code& ec) +{ + // turn off session caching completely + SSL_CTX_set_session_cache_mode(value.native_handle(), SSL_SESS_CACHE_OFF); + + auto OPTIONS = asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3 | SSL_OP_NO_TICKET; + + if (!config.allowTLSv10) + { + OPTIONS |= asio::ssl::context::no_tlsv1; + } + + if (!config.allowTLSv11) + { + OPTIONS |= asio::ssl::context::no_tlsv1_1; + } + + if (!config.allowTLSv12) + { + OPTIONS |= asio::ssl::context::no_tlsv1_2; + } + + if (value.set_options(OPTIONS, ec)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::set_options(..): %s", ec.message().c_str()); + return ec; + } + + if (value.set_verify_depth(config.maxVerifyDepth, ec)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::set_verify_depth(..): %s", ec.message().c_str()); + return ec; + } + + // optionally, configure the cipher-list + if (!config.cipherList.empty()) + { + if (SSL_CTX_set_cipher_list(value.native_handle(), config.cipherList.c_str()) == 0) + { + ec = asio::error_code(); + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::set_cipher_list(..): %s", ec.message().c_str()); + return ec; + } + } + + // verify the peer certificate + if (value.set_verify_mode(GetVerifyMode(server), ec)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::set_verify_mode(..): %s", ec.message().c_str()); + return ec; + } + + // The public certificate file used to verify the peer + if (value.load_verify_file(config.peerCertFilePath, ec)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::load_verify_file(..): %s", ec.message().c_str()); + return ec; + } + + // the certificate we present to the server + the private key we use are placed into the same file + if (value.use_certificate_chain_file(config.localCertFilePath, ec)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::use_certificate_chain_file(..): %s", ec.message().c_str()); + return ec; + } + + if (value.use_private_key_file(config.privateKeyFilePath, asio::ssl::context_base::file_format::pem, ec)) + { + FORMAT_LOG_BLOCK(logger, flags::ERR, "Error calling ssl::context::use_private_key_file(..): %s", ec.message().c_str()); + } + + return ec; +} +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.h b/utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.h new file mode 100644 index 0000000..4f5169d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/SSLContext.h @@ -0,0 +1,57 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_SSLCONTEXT_H +#define ASIOPAL_SSLCONTEXT_H + +#include "asiopal/TLSConfig.h" + +#include +#include + +#include + +namespace asiopal +{ +/** +* Create and fully configure an asio::ssl::context +*/ +class SSLContext : private openpal::Uncopyable +{ + +public: + + SSLContext(const openpal::Logger& logger, bool server, const TLSConfig& cfg, std::error_code&); + + + asio::ssl::context value; + +private: + + openpal::Logger logger; + + static int GetVerifyMode(bool server); + + std::error_code ApplyConfig(const TLSConfig& config, bool server, std::error_code& ec); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.cpp new file mode 100644 index 0000000..ceee00f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.cpp @@ -0,0 +1,221 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/tls/TLSClient.h" + +#include "asiopal/SocketHelpers.h" + +#include "opendnp3/LogLevels.h" + +using namespace openpal; +using namespace opendnp3; + +namespace asiopal +{ + +TLSClient::TLSClient( + const Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& remote, + const std::string& adapter, + const TLSConfig& config, + std::error_code& ec) + : + logger(logger), + condition(logger), + executor(executor), + host(remote.address), + adapter(adapter), + ctx(logger, false, config, ec), + remoteEndpoint(asio::ip::tcp::v4(), remote.port), + localEndpoint(), + resolver(executor->strand.get_io_service()) +{ + +} + +bool TLSClient::Cancel() +{ + if (this->canceled) + { + return false; + } + + std::error_code ec; + resolver.cancel(); + this->canceled = true; + return true; +} + +bool TLSClient::BeginConnect(const connect_callback_t& callback) +{ + if (canceled) return false; + + auto stream = std::make_shared>(this->executor->strand.get_io_service(), this->ctx.value); + + auto verify = [self = shared_from_this()](bool preverified, asio::ssl::verify_context & ctx) -> bool + { + self->LogVerifyCallback(preverified, ctx); + return preverified; + }; + + std::error_code ec; + stream->set_verify_callback(verify, ec); + + if (ec) + { + auto cb = [self = shared_from_this(), callback, stream, ec] + { + if (!self->canceled) + { + callback(self->executor, stream, ec); + } + }; + + this->executor->strand.post(cb); + return true; + } + + SocketHelpers::BindToLocalAddress(this->adapter, this->localEndpoint, stream->lowest_layer(), ec); + + if (ec) + { + auto cb = [self = shared_from_this(), callback, stream, ec] + { + if (!self->canceled) + { + callback(self->executor, stream, ec); + } + }; + + this->executor->strand.post(cb); + return true; + } + + const auto address = asio::ip::address::from_string(this->host, ec); + auto self = this->shared_from_this(); + if (ec) + { + // Try DNS resolution instead + auto cb = [self, callback, stream](const std::error_code & ec, asio::ip::tcp::resolver::iterator endpoints) + { + self->HandleResolveResult(callback, stream, endpoints, ec); + }; + + std::stringstream portstr; + portstr << remoteEndpoint.port(); + + resolver.async_resolve( + asio::ip::tcp::resolver::query(host, portstr.str()), + executor->strand.wrap(cb) + ); + + return true; + } + else + { + remoteEndpoint.address(address); + auto cb = [self, stream, callback](const std::error_code & ec) + { + self->HandleConnectResult(callback, stream, ec); + }; + + stream->lowest_layer().async_connect(remoteEndpoint, executor->strand.wrap(cb)); + return true; + } +} + +void TLSClient::LogVerifyCallback(bool preverified, asio::ssl::verify_context& ctx) +{ + const int MAX_SUBJECT_NAME = 512; + + int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); + + // lookup the subject name + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + char subjectName[MAX_SUBJECT_NAME]; + X509_NAME_oneline(X509_get_subject_name(cert), subjectName, MAX_SUBJECT_NAME); + + if (preverified) + { + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Verified certificate at depth: %d subject: %s", depth, subjectName); + } + else + { + const int err = X509_STORE_CTX_get_error(ctx.native_handle()); + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Error verifying certificate at depth: %d subject: %s error: %d:%s", depth, subjectName, err, X509_verify_cert_error_string(err)); + } +} + +void TLSClient::HandleResolveResult( + const connect_callback_t& callback, + const std::shared_ptr>& stream, + const asio::ip::tcp::resolver::iterator& endpoints, + const std::error_code& ec) +{ + if (ec) + { + if (!this->canceled) + { + callback(this->executor, stream, ec); + } + } + else + { + // attempt a connection to each endpoint in the iterator until we connect + auto cb = [self = this->shared_from_this(), callback, stream](const std::error_code & ec, asio::ip::tcp::resolver::iterator endpoints) + { + self->HandleConnectResult(callback, stream, ec); + }; + + asio::async_connect(stream->lowest_layer(), endpoints, this->condition, this->executor->strand.wrap(cb)); + } +} + +void TLSClient::HandleConnectResult( + const connect_callback_t& callback, + const std::shared_ptr>& stream, + const std::error_code& ec) +{ + if (ec) + { + if (!this->canceled) + { + callback(this->executor, stream, ec); + } + } + else + { + auto cb = [self = shared_from_this(), callback, stream](const std::error_code & ec) + { + if (!self->canceled) + { + callback(self->executor, stream, ec); + } + }; + + stream->async_handshake(asio::ssl::stream_base::client, executor->strand.wrap(cb)); + } +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.h b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.h new file mode 100644 index 0000000..4287815 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSClient.h @@ -0,0 +1,101 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TLSCLIENT_H +#define ASIOPAL_TLSCLIENT_H + +#include "asiopal/Executor.h" +#include "asiopal/IPEndpoint.h" +#include "asiopal/LoggingConnectionCondition.h" +#include "asiopal/TLSConfig.h" + +#include "asiopal/tls/SSLContext.h" + +#include + +namespace asiopal +{ + +class TLSClient final : public std::enable_shared_from_this, private openpal::Uncopyable +{ + +public: + + typedef std::function& executor, const std::shared_ptr>& stream, const std::error_code& ec)> connect_callback_t; + + static std::shared_ptr Create( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& remote, + const std::string& adapter, + const TLSConfig& config, + std::error_code& ec) + { + auto ret = std::make_shared(logger, executor, remote, adapter, config, ec); + return ec ? nullptr : ret; + } + + TLSClient( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& remote, + const std::string& adapter, + const TLSConfig& config, + std::error_code& ec + ); + + bool Cancel(); + + bool BeginConnect(const connect_callback_t& callback); + +private: + + void LogVerifyCallback(bool preverified, asio::ssl::verify_context& ctx); + + void HandleResolveResult( + const connect_callback_t& callback, + const std::shared_ptr>& stream, + const asio::ip::tcp::resolver::iterator& endpoints, + const std::error_code& ec + ); + + void HandleConnectResult( + const connect_callback_t& callback, + const std::shared_ptr>& stream, + const std::error_code& ec + ); + + bool canceled = false; + + openpal::Logger logger; + LoggingConnectionCondition condition; + const std::shared_ptr executor; + const std::string host; + const std::string adapter; + SSLContext ctx; + asio::ip::tcp::endpoint remoteEndpoint; + asio::ip::tcp::endpoint localEndpoint; + asio::ip::tcp::resolver resolver; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSContext.h b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSContext.h new file mode 100644 index 0000000..79a2879 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSContext.h @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_TLS_CONTEXT_H +#define ASIOPAL_TLS_CONTEXT_H + +#include + +#include + +#include "TLSConfig.h" + +namespace asiopal +{ + +/** +* A wrapper type for an ASIO ssl_context +*/ +class TLSContext : private openpal::Uncopyable +{ +public: + + TLSContext(asio::ssl::context_base::method method, const TLSConfig& config, std::error_code& ec); + +private: + + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.cpp new file mode 100644 index 0000000..5a0a771 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.cpp @@ -0,0 +1,148 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/tls/TLSServer.h" + +#include +#include + +#include + +using namespace asio; +using namespace asio::ip; +using namespace opendnp3; + +namespace asiopal +{ + +TLSServer::TLSServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& endpoint, + const TLSConfig& config, + std::error_code& ec +) : + logger(logger), + executor(executor), + ctx(logger, true, config, ec), + endpoint(ip::tcp::v4(), endpoint.port), + acceptor(executor->strand.get_io_service()), + session_id(0) +{ + if (!ec) + { + this->ConfigureListener(endpoint.address, ec); + } +} + +void TLSServer::Shutdown() +{ + this->acceptor.close(); +} + +std::error_code TLSServer::ConfigureListener(const std::string& adapter, std::error_code& ec) +{ + auto address = asio::ip::address::from_string(adapter, ec); + + if (ec) + { + return ec; + } + + this->endpoint.address(address); + + if (this->acceptor.open(this->endpoint.protocol(), ec)) return ec; + if (this->acceptor.set_option(ip::tcp::acceptor::reuse_address(true), ec)) return ec; + if (this->acceptor.bind(this->endpoint, ec)) return ec; + + if (this->acceptor.listen(socket_base::max_connections, ec)) return ec; + + + std::ostringstream oss; + oss << this->endpoint; + FORMAT_LOG_BLOCK(this->logger, flags::INFO, "Listening on: %s", oss.str().c_str()); + return ec; +} + +void TLSServer::StartAccept(std::error_code& ec) +{ + const auto ID = this->session_id; + ++this->session_id; + + // this ensures that the TCPListener is never deleted during an active callback + auto self(shared_from_this()); + + // this could be a unique_ptr once move semantics are supported in lambdas + auto stream = std::make_shared>(this->executor->strand.get_io_service(), self->ctx.value); + + auto verify = [this, ID](bool preverified, asio::ssl::verify_context & ctx) + { + return this->VerifyCallback(ID, preverified, ctx); + }; + + stream->set_verify_callback(verify, ec); + + if (ec) return; + + auto accept_cb = [self, stream, ID](std::error_code ec) -> void + { + if (ec) + { + SIMPLE_LOG_BLOCK(self->logger, flags::INFO, ec.message().c_str()); + self->OnShutdown(); + return; + } + + // begin accepting another session + self->StartAccept(ec); + + if (!self->AcceptConnection(ID, stream->lowest_layer().remote_endpoint())) + { + std::ostringstream oss; + oss << stream->lowest_layer().remote_endpoint(); + + FORMAT_LOG_BLOCK(self->logger, flags::INFO, "Remote endpoint rejected: %s", oss.str().c_str()); + + stream->lowest_layer().close(); + return; + } + + auto handshake_cb = [stream, ID, self](const std::error_code & ec) + { + if (ec) + { + FORMAT_LOG_BLOCK(self->logger, flags::INFO, "TLS handshake failed: %s", ec.message().c_str()); + return; + } + + self->AcceptStream(ID, self->executor, stream); + }; + + // Begin the TLS handshake + stream->async_handshake(asio::ssl::stream_base::server, self->executor->strand.wrap(handshake_cb)); + }; + + this->acceptor.async_accept(stream->lowest_layer(), this->executor->strand.wrap(accept_cb)); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.h b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.h new file mode 100644 index 0000000..9350135 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSServer.h @@ -0,0 +1,88 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TLSSERVER_H +#define ASIOPAL_TLSSERVER_H + +#include "asiopal/IPEndpoint.h" +#include "asiopal/IListener.h" +#include "asiopal/TLSConfig.h" +#include "asiopal/Executor.h" + +#include +#include + +#include "asiopal/tls/SSLContext.h" + +namespace asiopal +{ +/** +* Binds and listens on an IPv4 TCP port. Implement TLS negotiation. +* +* Meant to be used exclusively as a shared_ptr +*/ +class TLSServer : + public IListener, + public std::enable_shared_from_this, + private openpal::Uncopyable +{ + +public: + + TLSServer( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const IPEndpoint& endpoint, + const TLSConfig& config, + std::error_code& ec + ); + + /// Stop listening for connections, permanently shutting down the listener + void Shutdown() override; + +protected: + + // Inherited classes must implement these methods + + virtual bool AcceptConnection(uint64_t sessionid, const asio::ip::tcp::endpoint& remote) = 0; + virtual bool VerifyCallback(uint64_t sessionid, bool preverified, asio::ssl::verify_context& ctx) = 0; + virtual void AcceptStream(uint64_t sessionid, const std::shared_ptr& executor, std::shared_ptr> stream) = 0; + virtual void OnShutdown() = 0; + + void StartAccept(std::error_code& ec); + + openpal::Logger logger; + std::shared_ptr executor; + +private: + + std::error_code ConfigureContext(const TLSConfig& config, std::error_code& ec); + std::error_code ConfigureListener(const std::string& adapter, std::error_code& ec); + + SSLContext ctx; + asio::ip::tcp::endpoint endpoint; + asio::ip::tcp::acceptor acceptor; + + uint64_t session_id; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.cpp b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.cpp new file mode 100644 index 0000000..5c72030 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.cpp @@ -0,0 +1,62 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "asiopal/tls/TLSStreamChannel.h" + +namespace asiopal +{ + +TLSStreamChannel::TLSStreamChannel(const std::shared_ptr& executor, const std::shared_ptr>& stream) : + IAsyncChannel(executor), + stream(stream) +{} + +void TLSStreamChannel::BeginReadImpl(openpal::WSlice dest) +{ + auto callback = [this](const std::error_code & ec, size_t num) + { + this->OnReadCallback(ec, num); + }; + + stream->async_read_some(asio::buffer(dest, dest.Size()), this->executor->strand.wrap(callback)); +} + +void TLSStreamChannel::BeginWriteImpl(const openpal::RSlice& data) +{ + auto callback = [this](const std::error_code & ec, size_t num) + { + this->OnWriteCallback(ec, num); + }; + + asio::async_write(*stream, asio::buffer(data, data.Size()), this->executor->strand.wrap(callback)); +} + +void TLSStreamChannel::ShutdownImpl() +{ + // Don't bother with a TLS shutdown. Just shutdown the socket. + std::error_code ec; + stream->lowest_layer().shutdown(asio::socket_base::shutdown_both, ec); + stream->lowest_layer().close(ec); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.h b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.h new file mode 100644 index 0000000..50d0558 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/asiopal/tls/TLSStreamChannel.h @@ -0,0 +1,54 @@ +/* +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef ASIOPAL_TLSSTREAMCHANNEL_H +#define ASIOPAL_TLSSTREAMCHANNEL_H + +#include "asiopal/IAsyncChannel.h" + +#include + +namespace asiopal +{ + +class TLSStreamChannel final : public IAsyncChannel +{ + +public: + + static std::shared_ptr Create(const std::shared_ptr& executor, const std::shared_ptr>& stream) + { + return std::make_shared(executor, stream); + } + + TLSStreamChannel(const std::shared_ptr& executor, const std::shared_ptr>& stream); + +private: + + virtual void BeginReadImpl(openpal::WSlice buffer) override; + virtual void BeginWriteImpl(const openpal::RSlice& buffer) override; + virtual void ShutdownImpl() override; + + const std::shared_ptr> stream; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/dnp3decode/Decoder.cpp b/utils/dnp3_src/cpp/libs/src/dnp3decode/Decoder.cpp new file mode 100644 index 0000000..6b51a6e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/dnp3decode/Decoder.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include + +#include "DecoderImpl.h" + +namespace opendnp3 +{ +Decoder::Decoder(IDecoderCallbacks& callbacks, openpal::Logger logger) : + impl(new DecoderImpl(callbacks, logger)) +{} + +void Decoder::DecodeLPDU(const openpal::RSlice& data) +{ + impl->DecodeLPDU(data); +} + +void Decoder::DecodeTPDU(const openpal::RSlice& data) +{ + impl->DecodeTPDU(data); +} + +void Decoder::DecodeAPDU(const openpal::RSlice& data) +{ + impl->DecodeAPDU(data); +} + +Decoder::~Decoder() +{ + delete impl; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.cpp b/utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.cpp new file mode 100644 index 0000000..c22b58e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.cpp @@ -0,0 +1,173 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "DecoderImpl.h" + +#include "dnp3decode/Indent.h" + +#include "opendnp3/app/parsing/APDUHeaderParser.h" +#include "opendnp3/app/parsing/APDUParser.h" +#include "dnp3decode/LoggingHandler.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +DecoderImpl::DecoderImpl(IDecoderCallbacks& callbacks, const openpal::Logger& logger) : + callbacks(&callbacks), + logger(logger), + link(logger), + transportRx(logger, 2048) +{} + +void DecoderImpl::DecodeLPDU(const openpal::RSlice& data) +{ + Indent i(*callbacks); + + RSlice remaining(data); + + while (remaining.IsNotEmpty()) + { + auto dest = this->link.WriteBuff(); + + const auto NUM = (remaining.Size() > dest.Size()) ? dest.Size() : remaining.Size(); + + remaining.Take(NUM).CopyTo(dest); + link.OnRead(NUM, *this); + + remaining.Advance(NUM); + } + +} + +void DecoderImpl::DecodeTPDU(const openpal::RSlice& data) +{ + Indent i(*callbacks); + FORMAT_HEX_BLOCK(logger, flags::TRANSPORT_RX, data, 18, 18); + + auto asdu = transportRx.ProcessReceive(data); + if (asdu.IsNotEmpty()) + { + this->DecodeAPDU(asdu); + } +} + +void DecoderImpl::DecodeAPDU(const openpal::RSlice& data) +{ + Indent i(*callbacks); + + FORMAT_HEX_BLOCK(this->logger, flags::APP_HEX_RX, data, 18, 18); + + if (IsResponse(data)) + { + APDUResponseHeader header; + if (APDUHeaderParser::ParseResponse(data, header, &logger)) + { + FORMAT_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, + "FIR: %i FIN: %i CON: %i UNS: %i SEQ: %i FUNC: %s IIN: [0x%02x, 0x%02x]", + header.control.FIR, + header.control.FIN, + header.control.CON, + header.control.UNS, + header.control.SEQ, + FunctionCodeToString(header.function), + header.IIN.LSB, + header.IIN.MSB); + if (header.IIN.LSB & 0x01) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.0 - All stations"); + if (header.IIN.LSB & 0x02) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.1 - Class 1 events"); + if (header.IIN.LSB & 0x04) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.2 - Class 2 events"); + if (header.IIN.LSB & 0x08) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.3 - Class 3 events"); + if (header.IIN.LSB & 0x10) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.4 - Need time"); + if (header.IIN.LSB & 0x20) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.5 - Local control"); + if (header.IIN.LSB & 0x40) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.6 - Device trouble"); + if (header.IIN.LSB & 0x80) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN1.7 - Device restart"); + if (header.IIN.MSB & 0x01) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.0 - Function code not supported"); + if (header.IIN.MSB & 0x02) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.1 - Object unknown"); + if (header.IIN.MSB & 0x04) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.2 - Parameter error"); + if (header.IIN.MSB & 0x08) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.3 - Event buffer overflow"); + if (header.IIN.MSB & 0x10) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.4 - Already executing"); + if (header.IIN.MSB & 0x20) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.5 - Configuration corrupt"); + if (header.IIN.MSB & 0x40) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.6 - Reserved 1"); + if (header.IIN.MSB & 0x80) SIMPLE_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, "IIN2.7 - Reserved 2"); + + Indent i(*callbacks); + LoggingHandler handler(logger, *callbacks); + APDUParser::ParseSinglePass(data.Skip(4), &logger, &handler, nullptr, ParserSettings::Default()); + } + } + else + { + APDUHeader header; + if (APDUHeaderParser::ParseRequest(data, header, &logger)) + { + + FORMAT_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, + "FIR: %i FIN: %i CON: %i UNS: %i SEQ: %i FUNC: %s", + header.control.FIR, + header.control.FIN, + header.control.CON, + header.control.UNS, + header.control.SEQ, + FunctionCodeToString(header.function)); + + + Indent i(*callbacks); + LoggingHandler handler(logger, *callbacks); + auto settings = (header.function == FunctionCode::READ) ? ParserSettings::NoContents() : ParserSettings::Default(); + APDUParser::ParseSinglePass(data.Skip(2), &logger, &handler, nullptr, settings); + } + } +} + +bool DecoderImpl::IsResponse(const openpal::RSlice& data) +{ + if (data.Size() < 2) + { + return false; + } + + switch (FunctionCodeFromType(data[1])) + { + case(FunctionCode::RESPONSE) : + case(FunctionCode::UNSOLICITED_RESPONSE) : + case(FunctionCode::AUTH_RESPONSE) : + return true; + default: + return false; + } +} + +bool DecoderImpl::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + if (header.func == LinkFunction::PRI_CONFIRMED_USER_DATA || header.func == LinkFunction::PRI_UNCONFIRMED_USER_DATA) + { + this->DecodeTPDU(userdata); + } + + return true; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.h b/utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.h new file mode 100644 index 0000000..98ad4de --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/dnp3decode/DecoderImpl.h @@ -0,0 +1,64 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DECODERIMPL_H +#define OPENDNP3_DECODERIMPL_H + +#include +#include + +#include + +#include "opendnp3/link/LinkLayerParser.h" +#include "opendnp3/link/IFrameSink.h" +#include "opendnp3/transport/TransportRx.h" + +namespace opendnp3 +{ +class DecoderImpl; + +// stand-alone DNP3 decoder +class DecoderImpl final : private IFrameSink +{ +public: + + DecoderImpl(IDecoderCallbacks& callbacks, const openpal::Logger& logger); + + void DecodeLPDU(const openpal::RSlice& data); + void DecodeTPDU(const openpal::RSlice& data); + void DecodeAPDU(const openpal::RSlice& data); + +private: + + static bool IsResponse(const openpal::RSlice& data); + + /// --- Implement IFrameSink --- + virtual bool OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) override; + + IDecoderCallbacks* callbacks; + openpal::Logger logger; + LinkLayerParser link; + TransportRx transportRx; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/dnp3decode/Indent.h b/utils/dnp3_src/cpp/libs/src/dnp3decode/Indent.h new file mode 100644 index 0000000..0dd1b3f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/dnp3decode/Indent.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_INDENT_H +#define OPENDNP3_INDENT_H + +#include + +namespace opendnp3 +{ +class Indent : openpal::Uncopyable +{ +public: + + Indent(IDecoderCallbacks& callbacks) : m_callbacks(&callbacks) + { + m_callbacks->PushIndent(); + } + + ~Indent() + { + m_callbacks->PopIndent(); + } + + +private: + + Indent() = delete; + + IDecoderCallbacks* m_callbacks; + +}; +} + +#endif + + diff --git a/utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.cpp b/utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.cpp new file mode 100644 index 0000000..a7e108d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.cpp @@ -0,0 +1,604 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "LoggingHandler.h" + +#include +#include + +using namespace openpal; + +namespace opendnp3 +{ + +LoggingHandler::LoggingHandler(openpal::Logger logger_, IDecoderCallbacks& callbacks_) : + logger(logger_), + callbacks(&callbacks_) +{} + +void LoggingHandler::OnHeaderResult(const HeaderRecord& record, const IINField& result) +{ + if (result.Any()) + { + Indent i(*callbacks); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "Pretty printing not supported for this type"); + } +} + +std::string LoggingHandler::ToUTCString(const DNPTime& dnptime) +{ + time_t seconds = static_cast(dnptime / 1000); + uint16_t milliseconds = static_cast(dnptime % 1000); + +#ifdef WIN32 + tm t; + if (gmtime_s(&t, &seconds)) + { + return "BAD TIME"; + } +#else + tm t; + if (!gmtime_r(&seconds, &t)) + { + return "BAD TIME"; + } +#endif + + std::ostringstream oss; + oss << (1900 + t.tm_year); + oss << "-" << std::setfill('0') << std::setw(2) << (1 + t.tm_mon); + oss << "-" << std::setfill('0') << std::setw(2) << t.tm_mday; + oss << " " << std::setfill('0') << std::setw(2) << t.tm_hour; + oss << ":" << std::setfill('0') << std::setw(2) << t.tm_min; + oss << ":" << std::setfill('0') << std::setw(2) << t.tm_sec; + oss << "." << std::setfill('0') << std::setw(3) << milliseconds; + return oss.str(); +} + +IINField LoggingHandler::PrintCrob(const ICollection>& items) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - code: 0x" << ToHex(item.value.rawCode) << " (" << ControlCodeToString(item.value.functionCode) << ")"; + oss << " count: " << static_cast(item.value.count); + oss << " on-time: " << static_cast(item.value.onTimeMS); + oss << " off-time: " << static_cast(item.value.offTimeMS); + oss << " status: " << CommandStatusToString(item.value.status); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + +IINField LoggingHandler::PrintOctets(const ICollection>& items) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + auto slice = item.value.ToRSlice(); + FORMAT_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "[%u] value: (length = %u)", item.index, slice.Size()); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, slice, 18, 18); + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + +IINField LoggingHandler::PrintTimeAndInterval(const ICollection>& values) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - startTime: " << ToUTCString(item.value.time); + oss << " count: " << item.value.interval; + oss << " units: " << IntervalUnitsToString(item.value.GetUnitsEnum()) << " (" << static_cast(item.value.units) << ")"; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(logItem); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + std::ostringstream oss; + oss << "csq: " << value.challengeSeqNum; + oss << " user: " << value.userNum; + oss << " MAC: " << HMACTypeToString(value.hmacAlgo); + oss << " reason: " << ChallengeReasonToString(value.challengeReason); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "challenge data: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.challengeData, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + std::ostringstream oss; + oss << "csq: " << value.challengeSeqNum; + oss << " user: " << value.userNum; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "MAC value: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.hmacValue, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + std::ostringstream oss; + oss << "ksq: " << value.keyChangeSeqNum; + oss << " user: " << value.userNum; + oss << " KW: " << KeyWrapAlgorithmToString(value.keyWrapAlgo); + oss << " KS: " << KeyStatusToString(value.keyStatus); + oss << " MAC: " << HMACTypeToString(value.hmacAlgo); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "challenge data: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.challengeData, 18, 18); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "MAC value: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.hmacValue, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + std::ostringstream oss; + oss << "ksq: " << value.keyChangeSeqNum; + oss << " user: " << value.userNum; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "key data: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.keyWrapData, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var7& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + { + std::ostringstream oss; + oss << "seq: " << value.challengeSeqNum; + oss << " user: " << value.userNum; + oss << " assoc: " << value.assocId; + oss << " error: " << AuthErrorCodeToString(value.errorCode); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + } + + { + std::ostringstream oss; + oss << "time of error: " << ToUTCString(value.time); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + } + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "error text: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.errorText, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var8& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + std::ostringstream oss; + oss << "kcm: " << KeyChangeMethodToString(value.keyChangeMethod); + oss << " type: " << CertificateTypeToString(value.certificateType); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "certificate: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.certificate, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var9& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "MAC: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.hmacValue, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var10& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + { + std::ostringstream oss; + oss << "kcm: " << KeyChangeMethodToString(value.keyChangeMethod); + oss << " op: " << UserOperationToString(value.userOperation); + oss << " scsn: " << value.statusChangeSeqNum; + oss << " role: " << value.userRole; + oss << "exp: " << value.userRoleExpDays; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + } + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "user name: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.userName, 18, 18); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "pub key: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.userPublicKey, 18, 18); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "cert data: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.certificationData, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var11& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + { + std::ostringstream oss; + oss << "kcm: " << KeyChangeMethodToString(value.keyChangeMethod); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + } + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "user name: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.userName, 18, 18); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "master challenge data: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.challengeData, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var12& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + { + std::ostringstream oss; + oss << "ksq: " << value.keyChangeSeqNum; + oss << " user: " << value.userNum; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + } + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "outstation challenge data: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.challengeData, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var13& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + { + std::ostringstream oss; + oss << "ksq: " << value.keyChangeSeqNum; + oss << " user: " << value.userNum; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + } + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "encrypted update key: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.encryptedUpdateKey, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var14& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "Digital Signature: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.digitalSignature, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var15& value, const openpal::RSlice& object) +{ + Indent i(*callbacks); + + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "MAC value: "); + FORMAT_HEX_BLOCK(logger, flags::APP_OBJECT_RX, value.hmacValue, 18, 18); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + return this->PrintTime(values); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + return this->PrintTime(values); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + return this->PrintTime(values); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + return this->PrintTime16(values); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + return this->PrintTime16(values); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + Indent i(*callbacks); + + auto print = [this](const Group120Var3 & value) + { + std::ostringstream oss; + oss << "csq: " << value.challengeSeqNum; + oss << " user: " << value.userNum; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(print); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + Indent i(*callbacks); + + auto print = [this](const Group120Var4 & value) + { + std::ostringstream oss; + oss << "user: " << value.userNum; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(print); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintV(values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + auto stringify = [](bool value) -> const char* + { + return GetStringValue(value); + }; + return this->PrintVQTStringify(header.enumeration, values, stringify); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + auto stringify = [](DoubleBit db) -> const char* + { + return DoubleBitToString(db); + }; + return this->PrintVQTStringify(header.enumeration, values, stringify); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintOctets(values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintTimeAndInterval(values); +} + +IINField LoggingHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->PrintSecStat(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + auto stringify = [](DoubleBit db) -> const char* + { + return DoubleBitToString(db); + }; + return this->PrintVQTStringify(header.enumeration, values, stringify); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintVQT(header.enumeration, values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintOctets(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintTimeAndInterval(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + Indent i(*callbacks); + const bool HAS_TIME = HasAbsoluteTime(header.enumeration); + auto logItem = [this, HAS_TIME](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - value: " << GetStringValue(item.value.value) << " status: " << CommandStatusToString(item.value.status); + if (HAS_TIME) + { + oss << " time: " << ToUTCString(item.value.time); + } + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(logItem); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + Indent i(*callbacks); + const bool HAS_TIME = HasAbsoluteTime(header.enumeration); + auto logItem = [this, HAS_TIME](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - value: " << item.value.value << " status: " << CommandStatusToString(item.value.status); + if (HAS_TIME) + { + oss << " time: " << ToUTCString(item.value.time); + } + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(logItem); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->PrintSecStat(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - flags: 0x" << ToHex(item.value.flags); + oss << " assoc: " << item.value.assocId; + oss << " value: " << item.value.value; + oss << " time: " << ToUTCString(item.value.time); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(logItem); + + return IINField::Empty(); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return PrintCrob(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return PrintAO(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return PrintAO(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return PrintAO(values); +} + +IINField LoggingHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return PrintAO(values); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.h b/utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.h new file mode 100644 index 0000000..36b330d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/dnp3decode/LoggingHandler.h @@ -0,0 +1,304 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LOGGINGHANDLER_H +#define OPENDNP3_LOGGINGHANDLER_H + +#include +#include +#include + +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/gen/Attributes.h" +#include "opendnp3/LogLevels.h" + +#include "dnp3decode/IDecoderCallbacks.h" +#include "dnp3decode/Indent.h" + +#include +#include + +namespace opendnp3 +{ +// stand-alone DNP3 decoder +class LoggingHandler final : public IAPDUHandler +{ +public: + + LoggingHandler(openpal::Logger logger, IDecoderCallbacks& callbacks); + +private: + + virtual void OnHeaderResult(const HeaderRecord& record, const IINField& result) override; + + static std::string ToUTCString(const DNPTime& time); + + openpal::Logger logger; + IDecoderCallbacks* callbacks; + + static const char* GetStringValue(bool value) + { + return value ? "1" : "0"; + } + + static std::string ToHex(uint8_t b) + { + std::ostringstream oss; + oss << openpal::ToHexChar((b & 0xf0) >> 4) << openpal::ToHexChar(b & 0xf); + return oss.str(); + } + + /// --- templated helpers --- + + template + IINField PrintV(const ICollection>& items); + + template + IINField PrintTime(const ICollection& items); + + template + IINField PrintTime16(const ICollection& items); + + template + IINField PrintAO(const ICollection>& items); + + IINField PrintCrob(const ICollection>& items); + IINField PrintOctets(const ICollection>& values); + IINField PrintTimeAndInterval(const ICollection>& values); + + template + IINField PrintVQT(GroupVariation gv, const ICollection>& items); + + template + IINField PrintSecStat(const ICollection>& values); + + template + IINField PrintVQTStringify(GroupVariation gv, const ICollection>& items, const Stringify& stringify); + + /// --- Implement IAPDUHandler --- + + virtual bool IsAllowed(uint32_t, GroupVariation, QualifierCode) override + { + return true; + } + + virtual IINField ProcessHeader(const AllObjectsHeader& record) override + { + return IINField::Empty(); + } + virtual IINField ProcessHeader(const RangeHeader& header) override + { + return IINField::Empty(); + } + virtual IINField ProcessHeader(const CountHeader& header) override + { + return IINField::Empty(); + } + + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var7& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var8& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var9& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var10& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var11& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var12& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var13& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var14& value, const openpal::RSlice& object) override; + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var15& value, const openpal::RSlice& object) override; + + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; +}; + +template +IINField LoggingHandler::PrintV(const ICollection>& items) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + FORMAT_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "[%u] - value: %s", item.index, GetStringValue(item.value.value)); + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + +template +IINField LoggingHandler::PrintTime(const ICollection& items) +{ + Indent i(*callbacks); + uint32_t count = 0; + auto logItem = [this, &count](const T & item) + { + auto time = ToUTCString(item.time); + FORMAT_LOG_BLOCK(logger, flags::APP_OBJECT_RX, "[%u] - time: %s", count, time.c_str()); + ++count; + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + +template +IINField LoggingHandler::PrintTime16(const ICollection& items) +{ + Indent i(*callbacks); + uint32_t count = 0; + auto logItem = [this, &count](const T & item) + { + std::ostringstream oss; + oss << "[" << count << "] - time: " << item.time; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + ++count; + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + +template +IINField LoggingHandler::PrintVQT(GroupVariation gv, const ICollection>& items) +{ + Indent i(*callbacks); + auto logItem = [this, gv](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - value: " << item.value.value; + if (HasFlags(gv)) + { + oss << " flags: 0x" << std::hex << ToHex(item.value.flags.value) << std::dec; + } + if (HasAbsoluteTime(gv) || HasRelativeTime(gv)) + { + oss << " time: " << ToUTCString(item.value.time); + } + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + +template +IINField LoggingHandler::PrintSecStat(const ICollection>& values) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - flags: 0x" << ToHex(item.value.flags); + oss << " assoc: " << item.value.assocId; + oss << " value: " << item.value.value; + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + values.ForeachItem(logItem); + + return IINField::Empty(); +} + +template +IINField LoggingHandler::PrintAO(const ICollection>& items) +{ + Indent i(*callbacks); + auto logItem = [this](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - value: " << item.value.value; + oss << " status: " << CommandStatusToString(item.value.status); + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} + + +template +IINField LoggingHandler::PrintVQTStringify(GroupVariation gv, const ICollection>& items, const Stringify& stringify) +{ + Indent i(*callbacks); + auto logItem = [this, gv, stringify](const Indexed& item) + { + std::ostringstream oss; + oss << "[" << item.index << "] - value: " << stringify(item.value.value); + if (HasFlags(gv)) + { + oss << " flags: 0x" << std::hex << ToHex(item.value.flags.value) << std::dec; + } + if (HasAbsoluteTime(gv) || HasRelativeTime(gv)) + { + oss << " time: " << item.value.time; + } + SIMPLE_LOG_BLOCK(logger, flags::APP_OBJECT_RX, oss.str().c_str()); + }; + + items.ForeachItem(logItem); + + return IINField::Empty(); +} +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/LayerInterfaces.h b/utils/dnp3_src/cpp/libs/src/opendnp3/LayerInterfaces.h new file mode 100644 index 0000000..fbb3e5e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/LayerInterfaces.h @@ -0,0 +1,127 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LAYERINTERFACES_H +#define OPENDNP3_LAYERINTERFACES_H + +#include +#include + +#include "Route.h" + +#include + +namespace opendnp3 +{ + +/** +* Describes a layer that can be opened or closed in response to the +* availability of the layer below it. +*/ +class IUpDown +{ + +public: + + virtual ~IUpDown() {} + + // Called by a lower Layer when it is available to this layer + // return false if the layer is already up + virtual bool OnLowerLayerUp() = 0; + + // Called by a lower layer when it is no longer available to this layer + // return false if the layer is already down + virtual bool OnLowerLayerDown() = 0; +}; + + +class IUpperLayer : public IUpDown +{ + +public: + + virtual ~IUpperLayer() {} + + // Called by the lower layer when data arrives + // return false if the layer is down + virtual bool OnReceive(const openpal::RSlice&) = 0; + + // Called by lower layer when a previously requested send operation succeeds or fails. + // Layers can only have 1 outstanding send operation. The callback is guaranteed + // unless the the OnLowerLayerDown() function is called beforehand + // return false if the layer is down or wasn't transmitting + virtual bool OnSendResult(bool isSucccess) = 0; + +}; + +class ILowerLayer +{ + +public: + + virtual ~ILowerLayer() {} + + virtual bool BeginTransmit(const openpal::RSlice&) = 0; +}; + +class HasLowerLayer +{ + +public: + + HasLowerLayer() : pLowerLayer(nullptr) {} + + // Called by the lower layer when data arrives + + void SetLowerLayer(ILowerLayer& lowerLayer) + { + assert(pLowerLayer == nullptr); + pLowerLayer = &lowerLayer; + } + +protected: + + ILowerLayer* pLowerLayer; +}; + +class HasUpperLayer +{ + +public: + + HasUpperLayer() : pUpperLayer(nullptr) {} + + // Called by the lower layer when data arrives + + void SetUpperLayer(IUpperLayer& upperLayer) + { + assert(pUpperLayer == nullptr); + pUpperLayer = &upperLayer; + } + +protected: + + IUpperLayer* pUpperLayer; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/LogLevels.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/LogLevels.cpp new file mode 100644 index 0000000..77fd3a3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/LogLevels.cpp @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "opendnp3/LogLevels.h" + +namespace opendnp3 +{ + +const char* LogFlagToString(int32_t flag) +{ + switch (flag) + { + + case(flags::EVENT) : + return "EVENT "; + case(flags::ERR) : + return "ERROR "; + case(flags::WARN) : + return "WARN "; + case(flags::INFO) : + return "INFO "; + case(flags::DBG) : + return "DEBUG "; + case(flags::LINK_RX) : + case(flags::LINK_RX_HEX) : + return "<-LL-- "; + case(flags::LINK_TX) : + case(flags::LINK_TX_HEX) : + return "--LL-> "; + case(flags::TRANSPORT_RX) : + return "<-TL-- "; + case(flags::TRANSPORT_TX) : + return "--TL-> "; + case(flags::APP_HEADER_RX) : + case(flags::APP_OBJECT_RX) : + case(flags::APP_HEX_RX) : + return "<-AL-- "; + case(flags::APP_HEADER_TX) : + case(flags::APP_OBJECT_TX) : + case(flags::APP_HEX_TX) : + return "--AL-> "; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/Route.h b/utils/dnp3_src/cpp/libs/src/opendnp3/Route.h new file mode 100644 index 0000000..b4c880f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/Route.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ROUTE_H +#define OPENDNP3_ROUTE_H + +#include + +namespace opendnp3 +{ + +/** +* DNP3 source/destination address pair +*/ +struct Route +{ + Route(uint16_t destination, uint16_t source) : + destination(destination), + source(source) + {} + + Route() : destination(0), source(0) {} + + uint16_t destination; + uint16_t source; + + bool Equals(const Route& rhs) const + { + return (this->destination == rhs.destination) && (this->source == rhs.source); + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.cpp new file mode 100644 index 0000000..5721da7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.cpp @@ -0,0 +1,123 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUBuilders.h" + +#include "opendnp3/objects/Group60.h" +#include "opendnp3/app/IINField.h" + +#include + + +namespace opendnp3 +{ +namespace build +{ + +void ReadIntegrity(APDURequest& request, const ClassField& classes, uint8_t seq) +{ + ClassRequest(request, FunctionCode::READ, classes, seq); +} + +void ReadAllObjects(APDURequest& request, GroupVariationID gvId, uint8_t seq) +{ + request.SetControl(AppControlField(true, true, false, false, seq)); + request.SetFunction(FunctionCode::READ); + auto writer = request.GetWriter(); + writer.WriteHeader(gvId, QualifierCode::ALL_OBJECTS); +} + +void ClassRequest(APDURequest& request, FunctionCode fc, const ClassField& classes, uint8_t seq) +{ + request.SetControl(AppControlField(true, true, false, false, seq)); + request.SetFunction(fc); + auto writer = request.GetWriter(); + WriteClassHeaders(writer, classes); +} + +bool WriteClassHeaders(HeaderWriter& writer, const ClassField& classes) +{ + if (classes.HasClass1()) + { + if (!writer.WriteHeader(Group60Var2::ID(), QualifierCode::ALL_OBJECTS)) + { + return false; + } + } + if (classes.HasClass2()) + { + if (!writer.WriteHeader(Group60Var3::ID(), QualifierCode::ALL_OBJECTS)) + { + return false; + } + } + if (classes.HasClass3()) + { + if (!writer.WriteHeader(Group60Var4::ID(), QualifierCode::ALL_OBJECTS)) + { + return false; + } + } + if (classes.HasClass0()) + { + if (!writer.WriteHeader(Group60Var1::ID(), QualifierCode::ALL_OBJECTS)) + { + return false; + } + } + + return true; +} + +void DisableUnsolicited(APDURequest& request, uint8_t seq) +{ + ClassRequest(request, FunctionCode::DISABLE_UNSOLICITED, ClassField::AllEventClasses(), seq); +} + +void EnableUnsolicited(APDURequest& request, const ClassField& classes, uint8_t seq) +{ + ClassRequest(request, FunctionCode::ENABLE_UNSOLICITED, classes, seq); +} + +void ClearRestartIIN(APDURequest& request, uint8_t seq) +{ + request.SetFunction(FunctionCode::WRITE); + request.SetControl(AppControlField(true, true, false, false, seq)); + auto writer = request.GetWriter(); + auto iter = writer.IterateOverSingleBitfield(GroupVariationID(80, 1), QualifierCode::UINT8_START_STOP, static_cast(IINBit::DEVICE_RESTART)); + iter.Write(false); +} + +void MeasureDelay(APDURequest& request, uint8_t seq) +{ + request.SetFunction(FunctionCode::DELAY_MEASURE); + request.SetControl(AppControlField::Request(seq)); +} + +void NullUnsolicited(APDUResponse& response, uint8_t seq, const IINField& iin) +{ + response.SetControl(AppControlField(true, true, true, true, seq)); + response.SetFunction(FunctionCode::UNSOLICITED_RESPONSE); + response.SetIIN(iin); +} + +} +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.h new file mode 100644 index 0000000..808e431 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUBuilders.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDUBUILDERS_H +#define OPENDNP3_APDUBUILDERS_H + +#include "opendnp3/app/APDURequest.h" +#include "opendnp3/app/APDUResponse.h" +#include "opendnp3/app/ClassField.h" + +namespace opendnp3 +{ +namespace build +{ +// -------- requests ------------- + +void ClassRequest(APDURequest& request, FunctionCode code, const ClassField& classes, uint8_t seq); + +bool WriteClassHeaders(HeaderWriter& writer, const ClassField& classes); + +void ReadIntegrity(APDURequest& request, const ClassField& classes, uint8_t seq = 0); + +void ReadAllObjects(APDURequest& request, GroupVariationID gvId, uint8_t seq = 0); + +void DisableUnsolicited(APDURequest& request, uint8_t seq = 0); + +void EnableUnsolicited(APDURequest& request, const ClassField& classes, uint8_t seq = 0); + +void ClearRestartIIN(APDURequest& request, uint8_t seq = 0); + +void MeasureDelay(APDURequest& request, uint8_t seq = 0); + +// -------- responses ------------- + +void NullUnsolicited(APDUResponse& response, uint8_t seq, const IINField& iin); + +} +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.cpp new file mode 100644 index 0000000..4c7b878 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUHeader.h" + +namespace opendnp3 +{ + +APDUHeader APDUHeader::SolicitedConfirm(uint8_t seq) +{ + return Confirm(seq, false); +} + +APDUHeader APDUHeader::UnsolicitedConfirm(uint8_t seq) +{ + return Confirm(seq, true); +} + +APDUHeader APDUHeader::Confirm(uint8_t seq, bool unsolicited) +{ + APDUHeader header; + header.function = FunctionCode::CONFIRM; + header.control = AppControlField(true, true, false, unsolicited, seq); + return header; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.h new file mode 100644 index 0000000..7c88c32 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUHeader.h @@ -0,0 +1,71 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDUHEADER_H +#define OPENDNP3_APDUHEADER_H + +#include "opendnp3/gen/FunctionCode.h" +#include "opendnp3/app/AppControlField.h" +#include "opendnp3/app/IINField.h" + +namespace opendnp3 +{ + +const uint32_t APDU_REQUEST_HEADER_SIZE = 2; +const uint32_t APDU_RESPONSE_HEADER_SIZE = 4; + +struct APDUHeader +{ + static APDUHeader SolicitedConfirm(uint8_t seq); + static APDUHeader UnsolicitedConfirm(uint8_t seq); + static APDUHeader Confirm(uint8_t seq, bool unsolicited); + + APDUHeader() : function(FunctionCode::UNKNOWN), control(true, true, false, false) + {} + + explicit APDUHeader(const AppControlField& control_) : function(FunctionCode::UNKNOWN), control(control_) + {} + + bool Equals(const APDUHeader& header) const + { + return (header.function == function) && (header.control.ToByte() == control.ToByte()); + } + + FunctionCode function; + AppControlField control; +}; + +struct APDUResponseHeader : public APDUHeader +{ + APDUResponseHeader(const AppControlField control_, const IINField& iin) : APDUHeader(control_), IIN(iin) + {} + + explicit APDUResponseHeader(const IINField& iin) : IIN(iin) + {} + + APDUResponseHeader() + {} + + IINField IIN; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.cpp new file mode 100644 index 0000000..4a0c2f1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.cpp @@ -0,0 +1,123 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "APDULogging.h" + +#include "opendnp3/app/parsing/APDUHeaderParser.h" +#include "opendnp3/app/parsing/APDUParser.h" + +#include + +namespace opendnp3 +{ +namespace logging +{ + +void ParseAndLogRequestTx(openpal::Logger logger, const openpal::RSlice& apdu) +{ + +#ifndef OPENPAL_STRIP_LOGGING + + FORMAT_HEX_BLOCK(logger, flags::APP_HEX_TX, apdu, 18, 18); + + if (logger.IsEnabled(flags::APP_HEADER_TX)) + { + APDUHeader header; + if (APDUHeaderParser::ParseRequest(apdu, header, &logger)) + { + FORMAT_LOG_BLOCK(logger, flags::APP_HEADER_TX, + "FIR: %i FIN: %i CON: %i UNS: %i SEQ: %i FUNC: %s", + header.control.FIR, + header.control.FIN, + header.control.CON, + header.control.UNS, + header.control.SEQ, + FunctionCodeToString(header.function)); + + if (logger.IsEnabled(flags::APP_OBJECT_TX)) + { + auto expectsContents = header.function != FunctionCode::READ; + APDUParser::ParseAndLogAll(apdu.Skip(APDU_REQUEST_HEADER_SIZE), &logger, ParserSettings::Create(expectsContents, flags::APP_OBJECT_TX)); + } + } + } + +#endif + +} + +void ParseAndLogResponseTx(openpal::Logger logger, const openpal::RSlice& apdu) +{ + +#ifndef OPENPAL_STRIP_LOGGING + + FORMAT_HEX_BLOCK(logger, flags::APP_HEX_TX, apdu, 18, 18); + + if (logger.IsEnabled(flags::APP_HEADER_TX)) + { + APDUResponseHeader header; + if (APDUHeaderParser::ParseResponse(apdu, header, &logger)) + { + FORMAT_LOG_BLOCK(logger, flags::APP_HEADER_TX, + "FIR: %i FIN: %i CON: %i UNS: %i SEQ: %i FUNC: %s IIN: [0x%02x, 0x%02x]", + header.control.FIR, + header.control.FIN, + header.control.CON, + header.control.UNS, + header.control.SEQ, + FunctionCodeToString(header.function), + header.IIN.LSB, + header.IIN.MSB); + + if (logger.IsEnabled(flags::APP_OBJECT_TX)) + { + APDUParser::ParseAndLogAll(apdu.Skip(APDU_RESPONSE_HEADER_SIZE), &logger, ParserSettings::Create(true, flags::APP_OBJECT_TX)); + } + } + } + +#endif + +} + +} +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.h new file mode 100644 index 0000000..bc938ef --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDULogging.h @@ -0,0 +1,61 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#ifndef OPENDNP3_APDULOGGING_H +#define OPENDNP3_APDULOGGING_H + +#include +#include +#include + +namespace opendnp3 +{ +namespace logging +{ + +void ParseAndLogRequestTx(openpal::Logger logger, const openpal::RSlice& apdu); + +void ParseAndLogResponseTx(openpal::Logger logger, const openpal::RSlice& apdu); + +} +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.cpp new file mode 100644 index 0000000..ec05051 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.cpp @@ -0,0 +1,40 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDURequest.h" + +using namespace openpal; + +namespace opendnp3 +{ + +APDURequest::APDURequest(const openpal::WSlice& aBuffer) : APDUWrapper(aBuffer) +{ + +} + +void APDURequest::ConfigureHeader(FunctionCode code, uint8_t seq) +{ + this->SetFunction(FunctionCode::AUTH_REQUEST); + this->SetControl(AppControlField::Request(seq)); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.h new file mode 100644 index 0000000..40e653d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDURequest.h @@ -0,0 +1,49 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDUREQUEST_H +#define OPENDNP3_APDUREQUEST_H + +#include "APDUWrapper.h" +#include "HeaderWriter.h" + +namespace opendnp3 +{ + +// this is what the application layer sees from the master / outstation for transmission +class APDURequest : public APDUWrapper +{ +public: + + explicit APDURequest(const openpal::WSlice& buffer); + + void ConfigureHeader(FunctionCode code, uint8_t seq); + + + static APDUEquality Compare(const openpal::RSlice& lhs, const openpal::RSlice& rhs); + +private: + + APDURequest(); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.cpp new file mode 100644 index 0000000..9286376 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.cpp @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUResponse.h" + +#include +#include + +using namespace openpal; + +namespace opendnp3 +{ + +APDUResponse::APDUResponse(const openpal::WSlice& buffer) : APDUWrapper(buffer) +{ + assert(buffer.Size() >= 4); + remaining.Advance(2); +} + +void APDUResponse::SetIIN(const IINField& indications) +{ + buffer[2] = indications.LSB; + buffer[3] = indications.MSB; +} + +IINField APDUResponse::GetIIN() const +{ + return IINField(buffer[2], buffer[3]); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.h new file mode 100644 index 0000000..921ad0b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUResponse.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDURESPONSE_H +#define OPENDNP3_APDURESPONSE_H + +#include "opendnp3/app/APDUWrapper.h" +#include "opendnp3/app/IINField.h" + +namespace opendnp3 +{ + +// this is what the application layer sees from the master / outstation for transmission +class APDUResponse : public APDUWrapper +{ +public: + + explicit APDUResponse(const openpal::WSlice& buffer); + + void SetIIN(const IINField& indications); + + IINField GetIIN() const; + +private: + + APDUResponse(); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.cpp new file mode 100644 index 0000000..4efbcf9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.cpp @@ -0,0 +1,93 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUWrapper.h" + +#include +#include + +#include "AppControlField.h" + +using namespace openpal; + +namespace opendnp3 +{ + +APDUWrapper::APDUWrapper() : valid(false) +{ + +} + +APDUWrapper::APDUWrapper(const openpal::WSlice& buffer_) : valid(true), buffer(buffer_), remaining(buffer_) +{ + assert(buffer.Size() >= 2); // need a control & function at a minimum + remaining.Advance(2); +} + +bool APDUWrapper::IsValid() const +{ + return valid; +} + +HeaderWriter APDUWrapper::GetWriter() +{ + return HeaderWriter(&remaining); +} + +uint32_t APDUWrapper::Remaining() const +{ + return remaining.Size(); +} + +void APDUWrapper::SetFunction(FunctionCode code) +{ + assert(buffer.IsNotEmpty()); + buffer[1] = FunctionCodeToType(code); +} + +FunctionCode APDUWrapper::GetFunction() const +{ + assert(buffer.IsNotEmpty()); + return FunctionCodeFromType(buffer[1]); +} + +AppControlField APDUWrapper::GetControl() const +{ + assert(buffer.IsNotEmpty()); + return AppControlField(buffer[0]); +} + +void APDUWrapper::SetControl(AppControlField control) +{ + buffer[0] = control.ToByte(); +} + +uint32_t APDUWrapper::Size() const +{ + return buffer.Size() - remaining.Size(); +} + +openpal::RSlice APDUWrapper::ToRSlice() const +{ + return buffer.ToRSlice().Take(this->Size()); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.h new file mode 100644 index 0000000..ee803d8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/APDUWrapper.h @@ -0,0 +1,75 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDUWRAPPER_H +#define OPENDNP3_APDUWRAPPER_H + +#include +#include + +#include "opendnp3/gen/FunctionCode.h" +#include "opendnp3/app/AppControlField.h" +#include "opendnp3/app/HeaderWriter.h" + +namespace opendnp3 +{ + +enum class APDUEquality +{ + FULL_EQUALITY, + OBJECT_HEADERS_EQUAL, + NONE +}; + +// This class is used to write to an underlying buffer +class APDUWrapper +{ +public: + + APDUWrapper(); + + explicit APDUWrapper(const openpal::WSlice& aBuffer); + + bool IsValid() const; + + void SetFunction(FunctionCode code); + FunctionCode GetFunction() const; + + AppControlField GetControl() const; + void SetControl(AppControlField control); + + uint32_t Size() const; + + openpal::RSlice ToRSlice() const; + + HeaderWriter GetWriter(); + + uint32_t Remaining() const; + +protected: + + bool valid; + openpal::WSlice buffer; + openpal::WSlice remaining; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogCommandEvent.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogCommandEvent.cpp new file mode 100644 index 0000000..23a287b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogCommandEvent.cpp @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "opendnp3/app/AnalogCommandEvent.h" + +namespace opendnp3 +{ + +AnalogCommandEvent::AnalogCommandEvent() : + value(0), + status(CommandStatus::SUCCESS) +{} + +AnalogCommandEvent::AnalogCommandEvent(double value_, CommandStatus status_) : + value(value_), + status(status_) +{} + +AnalogCommandEvent::AnalogCommandEvent(double value_, CommandStatus status_, DNPTime time_) : + value(value_), + status(status_), + time(time_) +{} + +bool AnalogCommandEvent::operator==(const AnalogCommandEvent& rhs) const +{ + return (value == rhs.value) && (status == rhs.status) && (time == rhs.time); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogOutput.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogOutput.cpp new file mode 100644 index 0000000..1a255f8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AnalogOutput.cpp @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/AnalogOutput.h" + + +namespace opendnp3 +{ + +AnalogOutputInt16::AnalogOutputInt16(int16_t aValue) : AnalogOutput(aValue) +{} + +AnalogOutputInt16::AnalogOutputInt16(int16_t aValue, CommandStatus aStatus) : AnalogOutput(aValue, aStatus) +{} + +AnalogOutputInt16::AnalogOutputInt16() : AnalogOutput(0) +{} + +bool AnalogOutputInt16::operator==(const AnalogOutputInt16& arRHS) const +{ + return this->ValuesEqual(arRHS) && status == arRHS.status; +} + +AnalogOutputInt32::AnalogOutputInt32(int32_t aValue) : AnalogOutput(aValue) +{} + +AnalogOutputInt32::AnalogOutputInt32(int32_t aValue, CommandStatus aStatus) : AnalogOutput(aValue, aStatus) +{} + +AnalogOutputInt32::AnalogOutputInt32() : AnalogOutput(0) +{} + +bool AnalogOutputInt32::operator==(const AnalogOutputInt32& arRHS) const +{ + return this->ValuesEqual(arRHS) && status == arRHS.status; +} + +AnalogOutputFloat32::AnalogOutputFloat32(float aValue) : AnalogOutput(aValue) +{} + +AnalogOutputFloat32::AnalogOutputFloat32(float aValue, CommandStatus aStatus) : AnalogOutput(aValue, aStatus) +{} + +AnalogOutputFloat32::AnalogOutputFloat32() : AnalogOutput(0) +{} + +bool AnalogOutputFloat32::operator==(const AnalogOutputFloat32& arRHS) const +{ + return this->ValuesEqual(arRHS) && status == arRHS.status; +} + +AnalogOutputDouble64::AnalogOutputDouble64(double aValue) : AnalogOutput(aValue) +{} + +AnalogOutputDouble64::AnalogOutputDouble64(double aValue, CommandStatus aStatus) : AnalogOutput(aValue, aStatus) +{} + +AnalogOutputDouble64::AnalogOutputDouble64() : AnalogOutput(0) +{} + +bool AnalogOutputDouble64::operator==(const AnalogOutputDouble64& arRHS) const +{ + return this->ValuesEqual(arRHS) && status == arRHS.status; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.cpp new file mode 100644 index 0000000..9dc2870 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.cpp @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "AppControlField.h" + +namespace opendnp3 +{ + +const AppControlField AppControlField::DEFAULT(true, true, false, false, 0); + +AppControlField::AppControlField(uint8_t byte) : + FIR((byte & FIR_MASK) != 0), + FIN((byte & FIN_MASK) != 0), + CON((byte & CON_MASK) != 0), + UNS((byte & UNS_MASK) != 0), + SEQ(byte & SEQ_MASK) +{ +} + +AppControlField AppControlField::Request(uint8_t seq) +{ + return AppControlField(true, true, false, false, seq); +} + +AppControlField::AppControlField() : + FIR(true), + FIN(true), + CON(false), + UNS(false), + SEQ(0) +{} + +AppControlField::AppControlField(bool fir, bool fin, bool con, bool uns, uint8_t seq) : + FIR(fir), + FIN(fin), + CON(con), + UNS(uns), + SEQ(seq) +{} + +uint8_t AppControlField::ToByte() const +{ + uint8_t ret = 0; + + if (FIR) + { + ret |= FIR_MASK; + } + if (FIN) + { + ret |= FIN_MASK; + } + if (CON) + { + ret |= CON_MASK; + } + if (UNS) + { + ret |= UNS_MASK; + } + + uint8_t seq = SEQ % 16; + + return ret | seq; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.h new file mode 100644 index 0000000..6ede199 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppControlField.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APPCONTROLFIELD_H +#define OPENDNP3_APPCONTROLFIELD_H + +#include + +namespace opendnp3 +{ + +/** Represents the first byte in every APDU +*/ +struct AppControlField +{ + const static AppControlField DEFAULT; + + static AppControlField Request(uint8_t seq); + + AppControlField(); + + explicit AppControlField(uint8_t byte); + + AppControlField(bool fir, bool fin, bool con, bool uns, uint8_t seq = 0); + + uint8_t ToByte() const; + + bool IsFirAndFin() const + { + return FIR && FIN; + } + + bool FIR; + bool FIN; + bool CON; + bool UNS; + uint8_t SEQ; + +private: + + static const uint8_t FIR_MASK = 0x80; + static const uint8_t FIN_MASK = 0x40; + static const uint8_t CON_MASK = 0x20; + static const uint8_t UNS_MASK = 0x10; + static const uint8_t SEQ_MASK = 0x0F; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppSeqNum.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppSeqNum.h new file mode 100644 index 0000000..0689f15 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/AppSeqNum.h @@ -0,0 +1,35 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APPSEQNUM_H +#define OPENDNP3_APPSEQNUM_H + +#include + +#include + +namespace opendnp3 +{ + +typedef openpal::SequenceNum AppSeqNum; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/BinaryCommandEvent.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/BinaryCommandEvent.cpp new file mode 100644 index 0000000..30135ae --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/BinaryCommandEvent.cpp @@ -0,0 +1,95 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "opendnp3/app/BinaryCommandEvent.h" + +namespace opendnp3 +{ + +BinaryCommandEvent::BinaryCommandEvent() : + value(false), + status(CommandStatus::SUCCESS), + time(0) +{} + +BinaryCommandEvent::BinaryCommandEvent(Flags flags) : + value(GetValueFromFlags(flags)), + status(GetStatusFromFlags(flags)) +{} + +BinaryCommandEvent::BinaryCommandEvent(Flags flags, DNPTime time) : + value(GetValueFromFlags(flags)), + status(GetStatusFromFlags(flags)), + time(time) +{} + +BinaryCommandEvent::BinaryCommandEvent(bool value, CommandStatus status) : + value(value), + status(status) +{} + +BinaryCommandEvent::BinaryCommandEvent(bool value, CommandStatus status, DNPTime time) : + value(value), + status(status), + time(time) +{} + +Flags BinaryCommandEvent::GetFlags() const +{ + return (static_cast(value) << 7) | (CommandStatusToType(status)); +} + +bool BinaryCommandEvent::operator==(const BinaryCommandEvent& rhs) const +{ + return value == rhs.value && status == rhs.status && time == rhs.time; +} + +bool BinaryCommandEvent::GetValueFromFlags(Flags flags) +{ + return (flags.value & ValueMask) == ValueMask; +} + +CommandStatus BinaryCommandEvent::GetStatusFromFlags(Flags flags) +{ + return CommandStatusFromType(flags.value & StatusMask); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/BitfieldRangeWriteIterator.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/BitfieldRangeWriteIterator.h new file mode 100644 index 0000000..b0a39b9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/BitfieldRangeWriteIterator.h @@ -0,0 +1,121 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_BITFIELDRANGEWRITEITERATOR_H +#define OPENDNP3_BITFIELDRANGEWRITEITERATOR_H + +#include + +namespace opendnp3 +{ + +// A facade for writing APDUs to an external buffer +template +class BitfieldRangeWriteIterator +{ +public: + + static BitfieldRangeWriteIterator Null() + { + auto buffer = openpal::WSlice::Empty(); + return BitfieldRangeWriteIterator(0, buffer); + } + + BitfieldRangeWriteIterator(typename IndexType::Type start_, openpal::WSlice& position_) : + start(start_), + count(0), + maxCount(0), + isValid(position_.Size() >= (2 * IndexType::SIZE)), + range(position_), + pPosition(&position_) + { + if(isValid) + { + openpal::Format::Write(range, start_); + pPosition->Advance(2 * IndexType::SIZE); + maxCount = pPosition->Size() * 8; + } + } + + ~BitfieldRangeWriteIterator() + { + if (isValid && count > 0) + { + typename IndexType::Type stop = start + count - 1; + openpal::Format::Write(range, stop); + + auto num = count / 8; + + if ((count % 8) > 0) + { + ++num; + } + + pPosition->Advance(num); + } + } + + bool Write(bool value) + { + if (isValid && count < maxCount) + { + auto byte = count / 8; + auto bit = count % 8; + + if (bit == 0) + { + (*pPosition)[byte] = 0; // initialize byte to 0 + } + + if (value) + { + (*pPosition)[byte] = ((*pPosition)[byte] | (1 << bit)); + } + + ++count; + return true; + } + else + { + return false; + } + } + + bool IsValid() const + { + return isValid; + } + +private: + + typename IndexType::Type start; + typename IndexType::Type count; + + uint32_t maxCount; + + bool isValid; + + openpal::WSlice range; // make a copy to record where we write the range + openpal::WSlice* pPosition; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/ClassField.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/ClassField.cpp new file mode 100644 index 0000000..2725b2c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/ClassField.cpp @@ -0,0 +1,136 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/ClassField.h" + +namespace opendnp3 +{ + +ClassField ClassField::None() +{ + return ClassField(); +} + +ClassField ClassField::AllClasses() +{ + return ClassField(ALL_CLASSES); +} + +ClassField ClassField::AllEventClasses() +{ + return ClassField(EVENT_CLASSES); +} + +ClassField::ClassField() : bitfield(0) +{} + +ClassField::ClassField(PointClass pc) : bitfield(static_cast(pc)) +{} + +ClassField::ClassField(bool class0, bool class1, bool class2, bool class3) : bitfield(0) +{ + bitfield = class0 ? ClassField::CLASS_0 : 0; + bitfield |= class1 ? ClassField::CLASS_1 : 0; + bitfield |= class2 ? ClassField::CLASS_2 : 0; + bitfield |= class3 ? ClassField::CLASS_3 : 0; +} + +ClassField::ClassField(uint8_t mask_) : bitfield(mask_ & ALL_CLASSES) +{} + +bool ClassField::IsEmpty() const +{ + return (bitfield == 0); +} + +bool ClassField::Intersects(const ClassField& other) const +{ + return (bitfield & other.bitfield) > 0; +} + +ClassField ClassField::OnlyEventClasses() const +{ + return ClassField(bitfield & EVENT_CLASSES); +} + +void ClassField::Set(PointClass pc) +{ + bitfield |= static_cast(pc); +} + +void ClassField::Clear(const ClassField& field) +{ + bitfield &= ~(field.bitfield); +} + +void ClassField::Set(const ClassField& field) +{ + bitfield |= field.bitfield; +} + +bool ClassField::HasEventType(EventClass ec) const +{ + switch (ec) + { + case(EventClass::EC1) : + return HasClass1(); + case(EventClass::EC2) : + return HasClass2(); + case(EventClass::EC3) : + return HasClass3(); + default: + return false; + } +} + +bool ClassField::HasClass0() const +{ + return (bitfield & CLASS_0) != 0; +} + +bool ClassField::HasClass1() const +{ + return (bitfield & CLASS_1) != 0; +} + +bool ClassField::HasClass2() const +{ + return (bitfield & CLASS_2) != 0; +} + +bool ClassField::HasClass3() const +{ + return (bitfield & CLASS_3) != 0; +} + +bool ClassField::HasEventClass() const +{ + return (bitfield & EVENT_CLASSES) != 0; +} + +bool ClassField::HasAnyClass() const +{ + return bitfield != 0; +} + +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/ControlRelayOutputBlock.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/ControlRelayOutputBlock.cpp new file mode 100644 index 0000000..5945b95 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/ControlRelayOutputBlock.cpp @@ -0,0 +1,51 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/ControlRelayOutputBlock.h" + + +namespace opendnp3 +{ + +ControlRelayOutputBlock::ControlRelayOutputBlock(ControlCode code_, uint8_t count_, uint32_t onTime_, uint32_t offTime_, CommandStatus status_) : + functionCode(code_), + rawCode(ControlCodeToType(code_)), + count(count_), + onTimeMS(onTime_), + offTimeMS(offTime_), + status(status_) +{ + +} + +ControlRelayOutputBlock::ControlRelayOutputBlock(uint8_t rawCode_, uint8_t count_, uint32_t onTime_, uint32_t offTime_, CommandStatus status_) : + functionCode(ControlCodeFromType((rawCode_))), + rawCode(rawCode_), + count(count_), + onTimeMS(onTime_), + offTimeMS(offTime_), + status(status_) +{ + +} + + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/CountWriteIterator.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/CountWriteIterator.h new file mode 100644 index 0000000..63dcb85 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/CountWriteIterator.h @@ -0,0 +1,96 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COUNTWRITEITERATOR_H +#define OPENDNP3_COUNTWRITEITERATOR_H + +#include + +namespace opendnp3 +{ + +// A facade for writing APDUs to an external buffer +template +class CountWriteIterator +{ +public: + + static CountWriteIterator Null() + { + return CountWriteIterator(); + } + + CountWriteIterator() : count(0), isValid(false), pPosition(nullptr) + {} + + CountWriteIterator(const openpal::Serializer& serializer_, openpal::WSlice& position) : + count(0), + serializer(serializer_), + isValid(position.Size() >= CountType::SIZE), + countPosition(position), + pPosition(&position) + { + if(isValid) + { + position.Advance(CountType::SIZE); + } + } + + ~CountWriteIterator() + { + if (isValid) + { + openpal::Format::Write(countPosition, count); + } + } + + bool Write(const WriteType& value) + { + if (isValid && (serializer.Size() <= pPosition->Size()) && (count < CountType::Max)) + { + serializer.Write(value, *this->pPosition); + ++count; + return true; + } + else + { + return false; + } + } + + bool IsValid() const + { + return isValid; + } + +private: + + typename CountType::Type count; + openpal::Serializer serializer; + + bool isValid; + + openpal::WSlice countPosition; // make a copy to record where we write the count + openpal::WSlice* pPosition; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/DNP3Serializer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/DNP3Serializer.h new file mode 100644 index 0000000..a85a168 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/DNP3Serializer.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DNP3SERIALIZER_H +#define OPENDNP3_DNP3SERIALIZER_H + +#include + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 +{ + +template +class DNP3Serializer : public openpal::Serializer +{ +public: + + DNP3Serializer(GroupVariationID id_, uint32_t size_, typename openpal::Serializer::ReadFunc pReadFunc_, typename openpal::Serializer::WriteFunc pWriteFunc_) : + openpal::Serializer(size_, pReadFunc_, pWriteFunc_), + id(id_) + {} + + GroupVariationID ID() const + { + return id; + } + +private: + + GroupVariationID id; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/DownSampling.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/DownSampling.h new file mode 100644 index 0000000..9ffabe4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/DownSampling.h @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DOWNSAMPLING_H +#define OPENDNP3_DOWNSAMPLING_H + +#include +#include + +#include + +namespace opendnp3 +{ +// A safe down sampling class +template +class DownSampling : private openpal::Uncopyable +{ + static const Target TARGET_MAX; + static const Target TARGET_MIN; + +public: + + static bool Apply(Source src, Target& target) + { + if(src > TARGET_MAX) + { + target = TARGET_MAX; + return true; + } + else if( src < TARGET_MIN) + { + target = TARGET_MIN; + return true; + } + else + { + target = static_cast(src); + return false; + } + } +}; + +template +const Target DownSampling::TARGET_MAX(openpal::MaxValue()); + +template +const Target DownSampling::TARGET_MIN(openpal::MinValue()); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/EventTriggers.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/EventTriggers.cpp new file mode 100644 index 0000000..9368f77 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/EventTriggers.cpp @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/EventTriggers.h" + +#include + +namespace opendnp3 +{ +namespace measurements +{ +bool IsEvent(const TypedMeasurement& newMeas, const TypedMeasurement& oldMeas, double deadband) +{ + if (newMeas.flags.value != oldMeas.flags.value) + { + return true; + } + else + { + double diff = fabs(newMeas.value - oldMeas.value); + if (diff == INFINITY) + { + return true; + } + else + { + return diff > deadband; + } + } +} +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.cpp new file mode 100644 index 0000000..74f7c5d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.cpp @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "Functions.h" + +namespace opendnp3 +{ +bool Functions::IsNoAckFuncCode(FunctionCode code) +{ + switch (code) + { + case(FunctionCode::DIRECT_OPERATE_NR) : + case(FunctionCode::IMMED_FREEZE_NR) : + case(FunctionCode::FREEZE_AT_TIME_NR) : + case(FunctionCode::FREEZE_CLEAR_NR) : + return true; + default: + return false; + } +} +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.h new file mode 100644 index 0000000..c10c4b3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/Functions.h @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ +#ifndef OPENDNP3_FUNCTIONS_H +#define OPENDNP3_FUNCTIONS_H + +#include "opendnp3/gen/FunctionCode.h" + +#include + +namespace opendnp3 +{ + +class Functions : private openpal::StaticOnly +{ +public: + + static bool IsNoAckFuncCode(FunctionCode code); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.cpp new file mode 100644 index 0000000..84dceeb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.cpp @@ -0,0 +1,177 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "GroupVariationRecord.h" + +namespace opendnp3 +{ + +GroupVariationRecord::GroupVariationRecord(uint8_t group_, uint8_t variation_, GroupVariation enumeration_, GroupVariationType type_) : + enumeration(enumeration_), + type(type_), + group(group_), + variation(variation_) +{ + +} + +HeaderRecord::HeaderRecord(const GroupVariationRecord& gv, uint8_t qualifier_, uint32_t headerIndex_) : + GroupVariationRecord(gv), + qualifier(qualifier_), + headerIndex(headerIndex_) +{ + +} + +QualifierCode HeaderRecord::GetQualifierCode() const +{ + return QualifierCodeFromType(qualifier); +} + +GroupVariationRecord GroupVariationRecord::GetRecord(uint8_t group, uint8_t variation) +{ + auto pair = GetEnumAndType(group, variation); + return GroupVariationRecord(group, variation, pair.enumeration, pair.type); +} + +uint16_t GroupVariationRecord::GetGroupVar(uint8_t group, uint8_t variation) +{ + return (group << 8) | variation; +} + +EnumAndType GroupVariationRecord::GetEnumAndType(uint8_t group, uint8_t variation) +{ + auto type = GetType(group, variation); + auto enumeration = GroupVariationFromType(GetGroupVar(group, variation)); + + if (enumeration == GroupVariation::UNKNOWN) + { + switch (group) + { + case(110) : + enumeration = GroupVariation::Group110Var0; + break; + case(111) : + enumeration = GroupVariation::Group111Var0; + break; + case(112) : + enumeration = GroupVariation::Group112Var0; + break; + case(113) : + enumeration = GroupVariation::Group113Var0; + break; + default: + break; + } + } + + return EnumAndType(enumeration, type); +} + +GroupVariationType GroupVariationRecord::GetType(uint8_t group, uint8_t variation) +{ + switch (group) + { + case(1) : + return GroupVariationType::STATIC; + + case(2) : + return GroupVariationType::EVENT; + + case(3) : + return GroupVariationType::STATIC; + + case(4) : + return GroupVariationType::EVENT; + + case(10) : + return GroupVariationType::STATIC; + + case(11) : + return GroupVariationType::EVENT; + + case(13) : + return GroupVariationType::EVENT; + + case(20) : + return GroupVariationType::STATIC; + + case(21) : + return GroupVariationType::STATIC; + + case(22) : + return GroupVariationType::EVENT; + + case(23) : + return GroupVariationType::EVENT; + + case(30) : + return GroupVariationType::STATIC; + + case(32) : + return GroupVariationType::EVENT; + + case(40) : + return GroupVariationType::STATIC; + + case(41) : + return GroupVariationType::EVENT; + + case(42) : + return GroupVariationType::EVENT; + + case(43) : + return GroupVariationType::EVENT; + + case(50) : + switch (variation) + { + case(4) : + return GroupVariationType::STATIC; + default: + return GroupVariationType::OTHER; + } + + case(60): + switch (variation) + { + case(1) : + return GroupVariationType::STATIC; + default: + return GroupVariationType::EVENT; + } + + case(110): + return GroupVariationType::STATIC; + + case(111): + return GroupVariationType::EVENT; + + case(121) : + return GroupVariationType::STATIC; + case(122) : + return GroupVariationType::EVENT; + + default: + return GroupVariationType::OTHER; + } +} + +} //end ns diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.h new file mode 100644 index 0000000..1e755f4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/GroupVariationRecord.h @@ -0,0 +1,147 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_GROUPVARIATIONRECORD_H +#define OPENDNP3_GROUPVARIATIONRECORD_H + +#include + +#include + +#include "opendnp3/gen/QualifierCode.h" +#include "opendnp3/gen/TimestampMode.h" +#include "opendnp3/gen/GroupVariation.h" + +#include "opendnp3/app/Range.h" + + +namespace opendnp3 +{ + +enum class GroupVariationType : int +{ + STATIC, + EVENT, + OTHER +}; + +struct EnumAndType +{ + EnumAndType(GroupVariation enumeration_, GroupVariationType type_) : + enumeration(enumeration_), type(type_) + {} + + GroupVariation enumeration; + GroupVariationType type; +}; + +class GroupVariationRecord +{ + +public: + + static EnumAndType GetEnumAndType(uint8_t group, uint8_t variation); + + static uint16_t GetGroupVar(uint8_t group, uint8_t variation); + + static GroupVariationRecord GetRecord(uint8_t group, uint8_t variation); + + static GroupVariationType GetType(uint8_t group, uint8_t variation); + + GroupVariationRecord(uint8_t group_, uint8_t variation_, GroupVariation enumeration_, GroupVariationType type_); + + GroupVariationRecord() : enumeration(GroupVariation::UNKNOWN), type(GroupVariationType::OTHER), group(0), variation(0) + {} + + GroupVariation enumeration; + GroupVariationType type; + uint8_t group; + uint8_t variation; +}; + +class HeaderRecord : public GroupVariationRecord +{ +public: + + HeaderRecord() : qualifier(0), headerIndex(0) + {} + + HeaderRecord(const GroupVariationRecord& gv, uint8_t qualifier, uint32_t headerIndex); + + QualifierCode GetQualifierCode() const; + + uint8_t qualifier; + uint32_t headerIndex; +}; + +// ---- Specific header types --- + +class AllObjectsHeader : public HeaderRecord +{ +public: + + explicit AllObjectsHeader(const HeaderRecord& record) : HeaderRecord(record) + {} + +}; + +class CountHeader : public HeaderRecord +{ +public: + + CountHeader(const HeaderRecord& record, uint16_t count_) : HeaderRecord(record), count(count_) + {} + + uint16_t count; +}; + +class FreeFormatHeader : public HeaderRecord +{ +public: + + FreeFormatHeader(const HeaderRecord& record, uint16_t count_) : HeaderRecord(record), count(count_) + {} + + uint16_t count; +}; + +class RangeHeader : public HeaderRecord +{ +public: + + RangeHeader(const HeaderRecord& record, const Range& range_) : HeaderRecord(record), range(range_) + {} + + Range range; +}; + +class PrefixHeader : public HeaderRecord +{ +public: + + PrefixHeader(const HeaderRecord& record, uint16_t count_) : HeaderRecord(record), count(count_) + {} + + uint16_t count; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.cpp new file mode 100644 index 0000000..066824e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.cpp @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "HeaderWriter.h" + +#include + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +HeaderWriter::HeaderWriter(openpal::WSlice* position_) : position(position_) +{} + +uint32_t HeaderWriter::Remaining() const +{ + return position->Size(); +} + +void HeaderWriter::Mark() +{ + mark.Set(*position); +} + +bool HeaderWriter::Rollback() +{ + if (mark.IsSet()) + { + *position = mark.Get(); + mark.Clear(); + return true; + } + else + { + return false; + } +} + +bool HeaderWriter::WriteHeader(GroupVariationID id, QualifierCode qc) +{ + if (position->Size() < 3) + { + return false; + } + else + { + UInt8::WriteBuffer(*position, id.group); + UInt8::WriteBuffer(*position, id.variation); + UInt8::WriteBuffer(*position, QualifierCodeToType(qc)); + return true; + } +} + +bool HeaderWriter::WriteHeaderWithReserve(GroupVariationID id, QualifierCode qc, uint32_t reserve) +{ + return (position->Size() < (3 + reserve)) ? false : WriteHeader(id, qc); +} + +bool HeaderWriter::WriteFreeFormat(const IVariableLength& value) +{ + uint32_t reserveSize = 1 + openpal::UInt16::SIZE + value.Size(); + if (this->WriteHeaderWithReserve(value.InstanceID(), QualifierCode::UINT16_FREE_FORMAT, reserveSize)) + { + openpal::UInt8::WriteBuffer(*position, 1); + openpal::UInt16::WriteBuffer(*position, value.Size()); + return value.Write(*position); + } + else + { + return false; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.h new file mode 100644 index 0000000..f1c7424 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/HeaderWriter.h @@ -0,0 +1,241 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_HEADERWRITER_H +#define OPENDNP3_HEADERWRITER_H + +#include "opendnp3/app/GroupVariationRecord.h" +#include "opendnp3/gen/QualifierCode.h" + +#include "opendnp3/app/IVariableLength.h" +#include "opendnp3/app/RangeWriteIterator.h" +#include "opendnp3/app/CountWriteIterator.h" +#include "opendnp3/app/PrefixedWriteIterator.h" +#include "opendnp3/app/BitfieldRangeWriteIterator.h" + +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/GroupVariationID.h" + +#include +#include + +namespace opendnp3 +{ + +// A facade for writing APDUs to an external buffer +class HeaderWriter +{ + friend class APDUWrapper; + +public: + + bool WriteHeader(GroupVariationID id, QualifierCode qc); + + template + RangeWriteIterator IterateOverRange(QualifierCode qc, const DNP3Serializer& serializer, typename IndexType::Type start); + + template + bool WriteRangeHeader(QualifierCode qc, GroupVariationID gvId, typename IndexType::Type start, typename IndexType::Type stop); + + template + bool WriteCountHeader(QualifierCode qc, GroupVariationID gvId, typename IndexType::Type count); + + template + CountWriteIterator IterateOverCount(QualifierCode qc, const DNP3Serializer& serializer); + + template + BitfieldRangeWriteIterator IterateOverSingleBitfield(GroupVariationID id, QualifierCode qc, typename IndexType::Type start); + + template + bool WriteSingleValue(QualifierCode qc, const DNP3Serializer& serializer, const ValueType&); + + bool WriteFreeFormat(const IVariableLength&); + + template + bool WriteSingleValue(QualifierCode qc, const WriteType&); + + template + bool WriteSingleIndexedValue(QualifierCode qc, const DNP3Serializer& serializer, const ValueType&, typename CountType::Type index); + + template + PrefixedWriteIterator IterateOverCountWithPrefix(QualifierCode qc, const DNP3Serializer& serializer); + + template + PrefixedWriteIterator IterateOverCountWithPrefixAndCTO(QualifierCode qc, const DNP3Serializer& serializer, const CTOType& cto); + + + // record the current position in case we need to rollback + void Mark(); + + // roll back to the last mark + bool Rollback(); + + uint32_t Remaining() const; + +private: + + explicit HeaderWriter(openpal::WSlice* position_); + + bool WriteHeaderWithReserve(GroupVariationID id, QualifierCode qc, uint32_t reserve); + + openpal::WSlice* position; + + openpal::Settable mark; +}; + +template +bool HeaderWriter::WriteRangeHeader(QualifierCode qc, GroupVariationID gvId, typename IndexType::Type start, typename IndexType::Type stop) +{ + if (WriteHeaderWithReserve(gvId, qc, 2 * IndexType::SIZE)) + { + IndexType::WriteBuffer(*position, start); + IndexType::WriteBuffer(*position, stop); + return true; + } + else + { + return false; + } +} + +template +bool HeaderWriter::WriteCountHeader(QualifierCode qc, GroupVariationID gvId, typename IndexType::Type count) +{ + if (WriteHeaderWithReserve(gvId, qc, IndexType::SIZE)) + { + IndexType::WriteBuffer(*position, count); + return true; + } + else + { + return false; + } +} + +template +bool HeaderWriter::WriteSingleValue(QualifierCode qc, const DNP3Serializer& serializer, const ValueType& value) +{ + auto reserveSize = CountType::SIZE + serializer.Size(); + if(this->WriteHeaderWithReserve(ValueType::ID, qc, reserveSize)) + { + CountType::WSlice(*position, 1); //write the count + serializer.Write(value, *position); + return true; + } + else return false; +} + +template +bool HeaderWriter::WriteSingleValue(QualifierCode qc, const WriteType& value) +{ + uint32_t reserveSize = CountType::SIZE + WriteType::Size(); + if(this->WriteHeaderWithReserve(WriteType::ID(), qc, reserveSize)) + { + CountType::WriteBuffer(*position, 1); //write the count + WriteType::Write(value, *position); + return true; + } + else + { + return false; + } +} + +template +bool HeaderWriter::WriteSingleIndexedValue(QualifierCode qc, const DNP3Serializer& serializer, const ValueType& value, typename CountType::Type index) +{ + uint32_t reserveSize = 2 * CountType::SIZE + serializer.Size(); + if(this->WriteHeaderWithReserve(serializer.ID(), qc, reserveSize)) + { + CountType::WriteBuffer(*position, 1); //write the count + CountType::WriteBuffer(*position, index); // write the index + serializer.Write(value, *position); + return true; + } + else return false; +} + +template +RangeWriteIterator HeaderWriter::IterateOverRange(QualifierCode qc, const DNP3Serializer& serializer, typename IndexType::Type start) +{ + uint32_t reserveSize = 2 * IndexType::SIZE + serializer.Size(); + if(this->WriteHeaderWithReserve(serializer.ID(), qc, reserveSize)) + { + return RangeWriteIterator(start, serializer, *position); + } + else return RangeWriteIterator::Null(); +} + +template +CountWriteIterator HeaderWriter::IterateOverCount(QualifierCode qc, const DNP3Serializer& serializer) +{ + uint32_t reserveSize = CountType::SIZE + serializer.Size(); + if(this->WriteHeaderWithReserve(serializer.ID(), qc, reserveSize)) + { + return CountWriteIterator(serializer, *position); + } + else return CountWriteIterator::Null(); +} + +template +BitfieldRangeWriteIterator HeaderWriter::IterateOverSingleBitfield(GroupVariationID id, QualifierCode qc, typename IndexType::Type start) +{ + uint32_t reserveSize = 2 * IndexType::SIZE + 1; //need at least 1 byte + if (this->WriteHeaderWithReserve(id, qc, reserveSize)) + { + return BitfieldRangeWriteIterator(start, *position); + } + else return BitfieldRangeWriteIterator::Null(); +} + +template +PrefixedWriteIterator HeaderWriter::IterateOverCountWithPrefix(QualifierCode qc, const DNP3Serializer& serializer) +{ + uint32_t reserveSize = 2 * PrefixType::SIZE + serializer.Size(); //enough space for the count, 1 prefix + object + if(this->WriteHeaderWithReserve(serializer.ID(), qc, reserveSize)) + { + return PrefixedWriteIterator(serializer, *position); + } + else return PrefixedWriteIterator::Null(); +} + +template +PrefixedWriteIterator HeaderWriter::IterateOverCountWithPrefixAndCTO(QualifierCode qc, const DNP3Serializer& serializer, const CTOType& cto) +{ + this->Mark(); + if (this->WriteSingleValue(QualifierCode::UINT8_CNT, cto)) + { + auto iter = IterateOverCountWithPrefix(qc, serializer); + if (!iter.IsValid()) + { + // remove the CTO header, if there's no space to write a value + this->Rollback(); + } + return iter; + } + else + { + return PrefixedWriteIterator::Null(); + } +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/IINField.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/IINField.cpp new file mode 100644 index 0000000..cdca501 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/IINField.cpp @@ -0,0 +1,204 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/IINField.h" + +#include + +using namespace openpal; +using namespace std; + +namespace opendnp3 +{ + +bool IINField::IsSet(IINBit bit) const +{ + switch(bit) + { + case(IINBit::ALL_STATIONS): + return Get(LSBMask::ALL_STATIONS); + case(IINBit::CLASS1_EVENTS): + return Get(LSBMask::CLASS1_EVENTS); + case(IINBit::CLASS2_EVENTS): + return Get(LSBMask::CLASS2_EVENTS); + case(IINBit::CLASS3_EVENTS): + return Get(LSBMask::CLASS3_EVENTS); + case(IINBit::NEED_TIME): + return Get(LSBMask::NEED_TIME); + case(IINBit::LOCAL_CONTROL): + return Get(LSBMask::LOCAL_CONTROL); + case(IINBit::DEVICE_TROUBLE): + return Get(LSBMask::DEVICE_TROUBLE); + case(IINBit::DEVICE_RESTART): + return Get(LSBMask::DEVICE_RESTART); + case(IINBit::FUNC_NOT_SUPPORTED): + return Get(MSBMask::FUNC_NOT_SUPPORTED); + case(IINBit::OBJECT_UNKNOWN): + return Get(MSBMask::OBJECT_UNKNOWN); + case(IINBit::PARAM_ERROR): + return Get(MSBMask::PARAM_ERROR); + case(IINBit::EVENT_BUFFER_OVERFLOW): + return Get(MSBMask::EVENT_BUFFER_OVERFLOW); + case(IINBit::ALREADY_EXECUTING): + return Get(MSBMask::ALREADY_EXECUTING); + case(IINBit::CONFIG_CORRUPT): + return Get(MSBMask::CONFIG_CORRUPT); + case(IINBit::RESERVED1): + return Get(MSBMask::RESERVED1); + case(IINBit::RESERVED2): + return Get(MSBMask::RESERVED2); + default: + return false; + }; +} + +void IINField::SetBitToValue(IINBit bit, bool value) +{ + if (value) + { + SetBit(bit); + } + else + { + ClearBit(bit); + } +} + +void IINField::SetBit(IINBit bit) +{ + switch(bit) + { + case(IINBit::ALL_STATIONS): + Set(LSBMask::ALL_STATIONS); + break; + case(IINBit::CLASS1_EVENTS): + Set(LSBMask::CLASS1_EVENTS); + break; + case(IINBit::CLASS2_EVENTS): + Set(LSBMask::CLASS2_EVENTS); + break; + case(IINBit::CLASS3_EVENTS): + Set(LSBMask::CLASS3_EVENTS); + break; + case(IINBit::NEED_TIME): + Set(LSBMask::NEED_TIME); + break; + case(IINBit::LOCAL_CONTROL): + Set(LSBMask::LOCAL_CONTROL); + break; + case(IINBit::DEVICE_TROUBLE): + Set(LSBMask::DEVICE_TROUBLE); + break; + case(IINBit::DEVICE_RESTART): + Set(LSBMask::DEVICE_RESTART); + break; + case(IINBit::FUNC_NOT_SUPPORTED): + Set(MSBMask::FUNC_NOT_SUPPORTED); + break; + case(IINBit::OBJECT_UNKNOWN): + Set(MSBMask::OBJECT_UNKNOWN); + break; + case(IINBit::PARAM_ERROR): + Set(MSBMask::PARAM_ERROR); + break; + case(IINBit::EVENT_BUFFER_OVERFLOW): + Set(MSBMask::EVENT_BUFFER_OVERFLOW); + break; + case(IINBit::ALREADY_EXECUTING): + Set(MSBMask::ALREADY_EXECUTING); + break; + case(IINBit::CONFIG_CORRUPT): + Set(MSBMask::CONFIG_CORRUPT); + break; + case(IINBit::RESERVED1): + Set(MSBMask::RESERVED1); + break; + case(IINBit::RESERVED2): + Set(MSBMask::RESERVED2); + break; + default: + break; + }; +} + +void IINField::ClearBit(IINBit bit) +{ + switch(bit) + { + case(IINBit::ALL_STATIONS): + Clear(LSBMask::ALL_STATIONS); + break; + case(IINBit::CLASS1_EVENTS): + Clear(LSBMask::CLASS1_EVENTS); + break; + case(IINBit::CLASS2_EVENTS): + Clear(LSBMask::CLASS2_EVENTS); + break; + case(IINBit::CLASS3_EVENTS): + Clear(LSBMask::CLASS3_EVENTS); + break; + case(IINBit::NEED_TIME): + Clear(LSBMask::NEED_TIME); + break; + case(IINBit::LOCAL_CONTROL): + Clear(LSBMask::LOCAL_CONTROL); + break; + case(IINBit::DEVICE_TROUBLE): + Clear(LSBMask::DEVICE_TROUBLE); + break; + case(IINBit::DEVICE_RESTART): + Clear(LSBMask::DEVICE_RESTART); + break; + case(IINBit::FUNC_NOT_SUPPORTED): + Clear(MSBMask::FUNC_NOT_SUPPORTED); + break; + case(IINBit::OBJECT_UNKNOWN): + Clear(MSBMask::OBJECT_UNKNOWN); + break; + case(IINBit::PARAM_ERROR): + Clear(MSBMask::PARAM_ERROR); + break; + case(IINBit::EVENT_BUFFER_OVERFLOW): + Clear(MSBMask::EVENT_BUFFER_OVERFLOW); + break; + case(IINBit::ALREADY_EXECUTING): + Clear(MSBMask::ALREADY_EXECUTING); + break; + case(IINBit::CONFIG_CORRUPT): + Clear(MSBMask::CONFIG_CORRUPT); + break; + case(IINBit::RESERVED1): + Clear(MSBMask::RESERVED1); + break; + case(IINBit::RESERVED2): + Clear(MSBMask::RESERVED2); + break; + default: + break; + }; +} + +bool IINField::operator==(const IINField& aRHS) const +{ + return (LSB == aRHS.LSB) && (MSB == aRHS.MSB); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/IINValue.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/IINValue.h new file mode 100644 index 0000000..cf85bc0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/IINValue.h @@ -0,0 +1,41 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IINVALUE_H +#define OPENDNP3_IINVALUE_H + +namespace opendnp3 +{ +// a simple wrapper type to differentiate an IIN from a bool +class IINValue +{ +public: + + IINValue() : value(false) + {} + + IINValue(bool value_) : value(value_) + {} + + bool value; +}; +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/IVariableLength.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/IVariableLength.h new file mode 100644 index 0000000..99e69e5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/IVariableLength.h @@ -0,0 +1,53 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IVARIABLELENGTH_H +#define OPENDNP3_IVARIABLELENGTH_H + +#include + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 +{ + +class IVariableLength +{ + +public: + + virtual ~IVariableLength() {} + + virtual GroupVariationID InstanceID() const = 0; + + // The size of the object in its current configuration + virtual uint32_t Size() const = 0; + + // attempt to write the object to the destination buffer + virtual bool Write(openpal::WSlice& dest) const = 0; + + // attempt to read the object from the input buffer + virtual bool Read(const openpal::RSlice& input) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementFactory.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementFactory.h new file mode 100644 index 0000000..11b90f6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementFactory.h @@ -0,0 +1,223 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MEASUREMENTFACTORY_H +#define OPENDNP3_MEASUREMENTFACTORY_H + +#include +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/app/BinaryCommandEvent.h" +#include "opendnp3/app/AnalogCommandEvent.h" +#include "opendnp3/app/ControlRelayOutputBlock.h" +#include "opendnp3/app/AnalogOutput.h" +#include "opendnp3/app/SecurityStat.h" + +namespace opendnp3 +{ + +struct BinaryFactory: private openpal::StaticOnly +{ + inline static Binary From(Flags flags) + { + return Binary(flags); + } + + inline static Binary From(uint8_t flags, uint16_t time) + { + return From(flags, DNPTime(time)); + } + + inline static Binary From(uint8_t flags, DNPTime time) + { + return Binary(flags, time); + } +}; + +struct DoubleBitBinaryFactory : private openpal::StaticOnly +{ + inline static DoubleBitBinary From(Flags flags) + { + return DoubleBitBinary(flags); + } + + inline static DoubleBitBinary From(Flags flags, uint16_t time) + { + return From(flags, DNPTime(time)); + } + + inline static DoubleBitBinary From(Flags flags, DNPTime time) + { + return DoubleBitBinary(flags, time); + } +}; + +struct AnalogFactory: private openpal::StaticOnly +{ + static Analog From(int32_t count) + { + return Analog(count); + } + static Analog From(Flags flags, double value) + { + return Analog(value, flags); + } + static Analog From(Flags flags, double value, DNPTime time) + { + return Analog(value, flags, time); + } +}; + +struct CounterFactory: private openpal::StaticOnly +{ + inline static Counter From(uint32_t count) + { + return Counter(count); + } + inline static Counter From(Flags flags, uint32_t count) + { + return Counter(count, flags); + } + inline static Counter From(Flags flags, uint32_t count, DNPTime time) + { + return Counter(count, flags, time); + } +}; + +struct FrozenCounterFactory: private openpal::StaticOnly +{ + inline static FrozenCounter From(uint32_t count) + { + return FrozenCounter(count); + } + inline static FrozenCounter From(Flags flags, uint32_t count) + { + return FrozenCounter(count, flags); + } + inline static FrozenCounter From(Flags flags, uint32_t count, DNPTime time) + { + return FrozenCounter(count, flags, time); + } +}; + +struct TimeAndIntervalFactory : private openpal::StaticOnly +{ + inline static TimeAndInterval From(DNPTime time, uint32_t interval, uint8_t units) + { + return TimeAndInterval(time, interval, units); + } +}; + +struct ControlRelayOutputBlockFactory: private openpal::StaticOnly +{ + inline static ControlRelayOutputBlock From( + uint8_t code, + uint8_t count, + uint32_t onTime, + uint32_t offTime, + uint8_t status) + { + return ControlRelayOutputBlock(code, count, onTime, offTime, CommandStatusFromType(status)); + } +}; + +struct BinaryOutputStatusFactory: private openpal::StaticOnly +{ + inline static BinaryOutputStatus From(Flags flags) + { + return BinaryOutputStatus(flags); + } + + inline static BinaryOutputStatus From(Flags flags, DNPTime time) + { + return BinaryOutputStatus(flags, time); + } +}; + +struct BinaryCommandEventFactory : private openpal::StaticOnly +{ + inline static BinaryCommandEvent From(Flags flags) + { + return BinaryCommandEvent(flags); + } + + inline static BinaryCommandEvent From(uint8_t flags, DNPTime time) + { + return BinaryCommandEvent(flags, time); + } +}; + +struct AnalogOutputStatusFactory: private openpal::StaticOnly +{ + inline static AnalogOutputStatus From(uint8_t flags, double value) + { + return AnalogOutputStatus(value, flags); + } + + inline static AnalogOutputStatus From(uint8_t flags, double value, DNPTime time) + { + return AnalogOutputStatus(value, flags, time); + } +}; + +struct AnalogCommandEventFactory : private openpal::StaticOnly +{ + inline static AnalogCommandEvent From(uint8_t status, double value) + { + return AnalogCommandEvent(value, CommandStatusFromType(status)); + } + + inline static AnalogCommandEvent From(uint8_t status, double value, DNPTime time) + { + return AnalogCommandEvent(value, CommandStatusFromType(status), time); + } +}; + +struct SecurityStatFactory : private openpal::StaticOnly +{ + inline static SecurityStat From(uint8_t flags, uint16_t assocId, uint32_t value) + { + return SecurityStat(flags, assocId, value); + } + + inline static SecurityStat From(uint8_t flags, uint16_t assocId, uint32_t value, DNPTime time) + { + return SecurityStat(flags, assocId, value, time); + } +}; + +template +struct AnalogOutputFactory: private openpal::StaticOnly +{ + inline static Target From(ValueType value, uint8_t status) + { + return Target(value, CommandStatusFromType(status)); + } +}; + +typedef AnalogOutputFactory AnalogOutputInt32Factory; +typedef AnalogOutputFactory AnalogOutputInt16Factory; +typedef AnalogOutputFactory AnalogOutputFloat32Factory; +typedef AnalogOutputFactory AnalogOutputDouble64Factory; + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementTypes.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementTypes.cpp new file mode 100644 index 0000000..fcfaa80 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/MeasurementTypes.cpp @@ -0,0 +1,183 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/MeasurementTypes.h" + +#include "opendnp3/app/QualityFlags.h" +#include "opendnp3/gen/BinaryQuality.h" + +namespace opendnp3 +{ + +// ------------ Binary --------------- + +Binary::Binary() : TypedMeasurement(false, flags::RESTART) +{} + +Binary::Binary(bool value) : TypedMeasurement(value, flags::GetBinaryFlags(flags::ONLINE, value)) +{} + +Binary::Binary(Flags flags) : TypedMeasurement(flags::GetBinaryValue(flags), flags) +{} + +Binary::Binary(Flags flags, DNPTime time) : TypedMeasurement(flags::GetBinaryValue(flags), flags, time) +{} + +Binary::Binary(bool value, Flags flags) : TypedMeasurement(value, flags::GetBinaryFlags(flags, value)) +{} + +Binary::Binary(bool value, Flags flags, DNPTime time) : TypedMeasurement(value, flags::GetBinaryFlags(flags, value), time) +{} + +// ------------ Double Bit Binary --------------- + +DoubleBitBinary::DoubleBitBinary() : TypedMeasurement(DoubleBit::INDETERMINATE, flags::RESTART) +{} + +DoubleBitBinary::DoubleBitBinary(DoubleBit value) : TypedMeasurement(value, GetFlags(flags::ONLINE, value)) +{} + +DoubleBitBinary::DoubleBitBinary(Flags flags) : TypedMeasurement(GetValue(flags), flags) +{} + +DoubleBitBinary::DoubleBitBinary(Flags flags, DNPTime time) : TypedMeasurement(GetValue(flags), flags, time) +{} + +DoubleBitBinary::DoubleBitBinary(DoubleBit value, Flags flags) : TypedMeasurement(value, GetFlags(flags, value)) +{} + +DoubleBitBinary::DoubleBitBinary(DoubleBit value, Flags flags, DNPTime time) : TypedMeasurement(value, GetFlags(flags, value), time) +{} + +DoubleBit DoubleBitBinary::GetValue(Flags flags) +{ + // the value is the top 2 bits, so down-shift 6 + uint8_t value = flags.value >> 6; + return DoubleBitFromType(value); +} + +Flags DoubleBitBinary::GetFlags(Flags flags, DoubleBit state) +{ + uint8_t value = DoubleBitToType(state) << 6; + return (QualityMask & flags.value) | value; +} + +// ------------ Binary Output Status --------------- + + +BinaryOutputStatus::BinaryOutputStatus() : TypedMeasurement(false, flags::RESTART) +{} + +BinaryOutputStatus::BinaryOutputStatus(bool value) : TypedMeasurement(value, flags::GetBinaryFlags(flags::ONLINE, value)) +{} + +BinaryOutputStatus::BinaryOutputStatus(Flags flags) : TypedMeasurement(flags::GetBinaryValue(flags), flags) +{} + +BinaryOutputStatus::BinaryOutputStatus(Flags flags, DNPTime time) : TypedMeasurement(flags::GetBinaryValue(flags), flags, time) +{} + +BinaryOutputStatus::BinaryOutputStatus(bool value, Flags flags) : TypedMeasurement(value, flags::GetBinaryFlags(flags, value)) +{} + +BinaryOutputStatus::BinaryOutputStatus(bool value, Flags flags, DNPTime time) : TypedMeasurement(value, flags::GetBinaryFlags(flags, value), time) +{} + +// ------------ Analog --------------- + +Analog::Analog() : TypedMeasurement(flags::RESTART) +{} + +Analog::Analog(double value) : TypedMeasurement(value, flags::ONLINE) +{} + +Analog::Analog(double value, Flags flags) : TypedMeasurement(value, flags) +{} + +Analog::Analog(double value, Flags flags, DNPTime time) : TypedMeasurement(value, flags, time) +{} + + +// ------------ Counter --------------- + + + +Counter::Counter() : TypedMeasurement(0, flags::RESTART) {} + +Counter::Counter(uint32_t value) : TypedMeasurement(value, flags::ONLINE) +{} + +Counter::Counter(uint32_t value, Flags flags) : TypedMeasurement(value, flags) +{} + +Counter::Counter(uint32_t value, Flags flags, DNPTime time) : TypedMeasurement(value, flags, time) +{} + +// ------------ Frozen Counter --------------- + + +FrozenCounter::FrozenCounter() : TypedMeasurement(0, flags::RESTART) {} + +FrozenCounter::FrozenCounter(uint32_t value) : TypedMeasurement(value, flags::ONLINE) +{} + +FrozenCounter::FrozenCounter(uint32_t value, Flags flags) : TypedMeasurement(value, flags) +{} + +FrozenCounter::FrozenCounter(uint32_t value, Flags flags, DNPTime time) : TypedMeasurement(value, flags, time) +{} + +// ------------ Analog Output Status --------------- + +AnalogOutputStatus::AnalogOutputStatus() : TypedMeasurement(flags::RESTART) {} + +AnalogOutputStatus::AnalogOutputStatus(double value) : TypedMeasurement(value, flags::ONLINE) +{} + +AnalogOutputStatus::AnalogOutputStatus(double value, Flags flags) : TypedMeasurement(value, flags) +{} + +AnalogOutputStatus::AnalogOutputStatus(double value, Flags flags, DNPTime time) : TypedMeasurement(value, flags, time) +{} + +// ------------ TimeAndInterval --------------- + +TimeAndInterval::TimeAndInterval() : time(0), interval(0), units(0) +{} + +TimeAndInterval::TimeAndInterval(DNPTime time_, uint32_t interval_, uint8_t units_) : + time(time_), + interval(interval_), + units(units_) +{} + +TimeAndInterval::TimeAndInterval(DNPTime time_, uint32_t interval_, IntervalUnits units_) : + time(time_), + interval(interval_), + units(static_cast(units_)) +{} + +IntervalUnits TimeAndInterval::GetUnitsEnum() const +{ + return IntervalUnitsFromType(units); +} + +} // end ns + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/OctetData.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/OctetData.cpp new file mode 100644 index 0000000..94d618b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/OctetData.cpp @@ -0,0 +1,49 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/OctetData.h" + +#include +#include + +using namespace openpal; + +namespace opendnp3 +{ + +OctetData::OctetData() : size(0) {} + +OctetData::OctetData(const RSlice& input) : + size(openpal::Min(MAX_SIZE, input.Size())) +{ + auto dest = buffer.GetWSlice(); + input.Take(size).CopyTo(dest); +} + +openpal::RSlice OctetData::ToRSlice() const +{ + return buffer.ToRSlice(size); +} + +} + + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/PrefixedWriteIterator.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/PrefixedWriteIterator.h new file mode 100644 index 0000000..164f0f9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/PrefixedWriteIterator.h @@ -0,0 +1,104 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_PREFIXEDWRITEITERATOR_H +#define OPENDNP3_PREFIXEDWRITEITERATOR_H + +#include + +namespace opendnp3 +{ + +// A facade for writing APDUs to an external buffer +template +class PrefixedWriteIterator +{ +public: + + static PrefixedWriteIterator Null() + { + return PrefixedWriteIterator(); + } + + PrefixedWriteIterator() : + sizeOfTypePlusIndex(0), + count(0), + isValid(false), + pPosition(nullptr) + {} + + PrefixedWriteIterator(const openpal::Serializer& serializer_, openpal::WSlice& position) : + serializer(serializer_), + sizeOfTypePlusIndex(serializer.Size() + PrefixType::SIZE), + count(0), + isValid(position.Size() >= PrefixType::SIZE), + countPosition(position), + pPosition(&position) + { + if(isValid) + { + pPosition->Advance(PrefixType::SIZE); + } + } + + ~PrefixedWriteIterator() + { + if (isValid) + { + PrefixType::Write(countPosition, count); + } + } + + bool Write(const WriteType& value, typename PrefixType::Type index) + { + if (isValid && (pPosition->Size() >= sizeOfTypePlusIndex)) + { + PrefixType::WriteBuffer(*pPosition, index); + serializer.Write(value, *pPosition); + ++count; + return true; + } + else + { + return false; + } + } + + bool IsValid() const + { + return isValid; + } + +private: + + openpal::Serializer serializer; + uint32_t sizeOfTypePlusIndex; + + typename PrefixType::Type count; + + bool isValid; + + openpal::WSlice countPosition; // make a copy to record where we write the count + openpal::WSlice* pPosition; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.cpp new file mode 100644 index 0000000..a124216 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "QualityFlags.h" + +namespace opendnp3 +{ + +namespace flags +{ + +bool GetBinaryValue(Flags flags) +{ + return (flags.value & static_cast(BinaryQuality::STATE)) != 0; +} + +Flags GetBinaryFlags(Flags flags, bool value) +{ + return (value) ? (flags.value | static_cast(BinaryQuality::STATE)) : (flags.value & (~static_cast(BinaryQuality::STATE))); +} + + +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.h new file mode 100644 index 0000000..d06122a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/QualityFlags.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_QUALITYFLAGS_H +#define OPENDNP3_QUALITYFLAGS_H + +#include +#include "opendnp3/app/Flags.h" + +namespace opendnp3 +{ + +namespace flags +{ + +enum Quality : uint8_t +{ + ONLINE = 0x01, + RESTART = 0x02 +}; + +bool GetBinaryValue(Flags flags); + +Flags GetBinaryFlags(Flags flags, bool value); + +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/Range.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/Range.h new file mode 100644 index 0000000..5940c5a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/Range.h @@ -0,0 +1,129 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_RANGE_H +#define OPENDNP3_RANGE_H + +#include +#include +#include + +#include + +namespace opendnp3 +{ + +class Range +{ +public: + + static Range From(uint16_t start, uint16_t stop) + { + return Range(start, stop); + } + + static Range Invalid() + { + return Range(1, 0); + } + + Range() : start(1), stop(0) + {} + + uint32_t Count() const + { + return IsValid() ? (static_cast(stop) - static_cast(start) + 1) : 0; + } + + bool Advance() + { + if (this->IsValid()) + { + if (start < stop) + { + ++start; + } + else + { + // make the range invalid + start = 1; + stop = 0; + } + + return true; + } + else + { + return false; + } + } + + /// @return A new range with only values found in both ranges + Range Intersection(const Range& other) const + { + return Range( + openpal::Max(start, other.start), + openpal::Min(stop, other.stop) + ); + } + + /// @return A new range with min start and the max stop of both ranges + Range Union(const Range& other) const + { + return Range( + openpal::Min(start, other.start), + openpal::Max(stop, other.stop) + ); + } + + bool Equals(const Range& other) const + { + return (other.start == start) && (other.stop == stop); + } + + bool IsValid() const + { + return start <= stop; + } + + bool IsOneByte() const + { + return IsValid() && (start <= 255) && (stop <= 255); + } + + uint16_t start; + uint16_t stop; + +private: + + Range(uint16_t index_) : + start(index_), + stop(index_) + {} + + Range(uint16_t start_, uint16_t stop_) : + start(start_), + stop(stop_) + {} +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/RangeWriteIterator.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/RangeWriteIterator.h new file mode 100644 index 0000000..0af61cb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/RangeWriteIterator.h @@ -0,0 +1,101 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_RANGEWRITEITERATOR_H +#define OPENDNP3_RANGEWRITEITERATOR_H + +#include +#include + +namespace opendnp3 +{ + +// A facade for writing APDUs to an external buffer +template +class RangeWriteIterator +{ +public: + + static RangeWriteIterator Null() + { + return RangeWriteIterator(); + } + + RangeWriteIterator() : start(0), count(0), isValid(false), pPosition(nullptr) + {} + + RangeWriteIterator(typename IndexType::Type start_, const openpal::Serializer& serializer_, openpal::WSlice& position) : + start(start_), + serializer(serializer_), + count(0), + isValid(position.Size() >= 2 * IndexType::SIZE), + range(position), + pPosition(&position) + { + if (isValid) + { + openpal::Format::Write(range, start); + pPosition->Advance(2 * IndexType::SIZE); + } + } + + ~RangeWriteIterator() + { + if (isValid && count > 0) + { + auto stop = start + count - 1; + IndexType::Write(range, static_cast(stop)); + } + } + + bool Write(const WriteType& value) + { + if (isValid && (pPosition->Size() >= serializer.Size()) && (count <= IndexType::Max)) + { + serializer.Write(value, *pPosition); + ++count; + return true; + } + else + { + return false; + } + } + + bool IsValid() const + { + return isValid; + } + +private: + + typename IndexType::Type start; + openpal::Serializer serializer; + uint32_t count; + + bool isValid; + + openpal::WSlice range; // make a copy to record where we write the range + openpal::WSlice* pPosition; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/SecurityStat.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/SecurityStat.cpp new file mode 100644 index 0000000..63d9089 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/SecurityStat.cpp @@ -0,0 +1,64 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/app/SecurityStat.h" + +#include "QualityFlags.h" + +namespace opendnp3 +{ + +SecurityStat::SecurityStat() : + quality(flags::RESTART), + value( +{ + 0, 0 +}) +{} + +SecurityStat::SecurityStat(Value value_, uint8_t quality_, DNPTime time_) : + quality(quality_), + value(value_), + time(time_) +{ + +} + + +SecurityStat::SecurityStat(uint8_t quality_, uint16_t assocId, uint32_t count) : + quality(quality_), + value( +{ + assocId, count +}), +time(0) +{} + +SecurityStat::SecurityStat(uint8_t quality_, uint16_t assocId, uint32_t count, DNPTime time_) : + quality(quality_), + value( +{ + assocId, count +}), +time(time_) +{} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/SequenceInfo.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/SequenceInfo.h new file mode 100644 index 0000000..45817f9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/SequenceInfo.h @@ -0,0 +1,34 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SEQUENCEINFO_H +#define OPENDNP3_SEQUENCEINFO_H + +namespace opendnp3 +{ + +enum class SequenceInfo +{ + OTHER, PREVIOUS, CORRECT +}; + +} //end ns + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/TxBuffer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/TxBuffer.h new file mode 100644 index 0000000..a374fa1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/TxBuffer.h @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TXBUFFER_H +#define OPENDNP3_TXBUFFER_H + +#include +#include + +namespace opendnp3 +{ + +class TxBuffer +{ +public: + + TxBuffer(uint32_t maxTxSize) : buffer(maxTxSize) + {} + + APDUResponse Start() + { + APDUResponse response(buffer.GetWSlice()); + return response; + } + + void Record(const AppControlField& control, const openpal::RSlice& view) + { + this->control = control; + this->lastResponse = view; + } + + const openpal::RSlice& GetLastResponse() const + { + return lastResponse; + } + + const AppControlField& GetLastControl() const + { + return control; + } + +private: + + openpal::RSlice lastResponse; + AppControlField control; + + openpal::Buffer buffer; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversionTemplates.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversionTemplates.h new file mode 100644 index 0000000..e239efe --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversionTemplates.h @@ -0,0 +1,190 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_WRITECONVERSIONTEMPLATES_H +#define OPENDNP3_WRITECONVERSIONTEMPLATES_H + +#include + +#include "opendnp3/app/DownSampling.h" + +#include + +namespace opendnp3 +{ +template +struct ConvertQ : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.flags = src.flags.value; + return t; + } +}; + +template +struct ConvertQV : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.value = src.value; + t.flags = src.flags.value; + return t; + } +}; + +template +struct ConvertV : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.value = src.value; + return t; + } +}; + +template +struct ConvertVandTruncate : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.value = static_cast(src.value); + return t; + } +}; + +template +struct ConvertVRangeCheck : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + DownSampling::Apply(src.value, t.value); + return t; + } +}; + +template +struct ConvertQVRangeCheck : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + auto overrange = DownSampling::Apply(src.value, t.value); + t.flags = overrange ? Overrange : 0; + t.flags |= src.flags.value; + return t; + } +}; + +template +struct ConvertQVandTruncate : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.flags = src.flags.value; + t.value = static_cast(src.value); + return t; + } +}; + +template +struct ConvertQVT : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.flags = src.flags.value; + t.value = src.value; + t.time = src.time; + return t; + } +}; + +template +struct ConvertQVTandTruncate : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.flags = src.flags.value; + t.value = static_cast(src.value); + t.time = src.time; + return t; + } +}; + +template +struct ConvertQVTRangeCheck : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + auto overrange = DownSampling::Apply(src.value, t.value); + t.flags = overrange ? Overrange : 0; + t.flags |= src.flags.value; + t.time = src.time; + return t; + } +}; + +template +struct ConvertQT : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.flags = src.flags.value; + t.time = src.time; + return t; + } +}; + +template +struct ConvertQTDowncast : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.flags = src.flags.value; + t.time = static_cast(src.time); + return t; + } +}; + +template +struct ConvertQS : private openpal::StaticOnly +{ + static Target Apply(const Source& src) + { + Target t; + t.value = src.value; + t.status = CommandStatusToType(src.status); + return t; + } +}; +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversions.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversions.h new file mode 100644 index 0000000..5115b3a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/WriteConversions.h @@ -0,0 +1,293 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_WRITECONVERSIONS_H +#define OPENDNP3_WRITECONVERSIONS_H + +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/app/WriteConversionTemplates.h" + +#include "opendnp3/objects/Group1.h" +#include "opendnp3/objects/Group2.h" +#include "opendnp3/objects/Group3.h" +#include "opendnp3/objects/Group4.h" +#include "opendnp3/objects/Group10.h" +#include "opendnp3/objects/Group11.h" +#include "opendnp3/objects/Group12.h" +#include "opendnp3/objects/Group13.h" +#include "opendnp3/objects/Group20.h" +#include "opendnp3/objects/Group21.h" +#include "opendnp3/objects/Group22.h" +#include "opendnp3/objects/Group23.h" +#include "opendnp3/objects/Group30.h" +#include "opendnp3/objects/Group32.h" +#include "opendnp3/objects/Group40.h" +#include "opendnp3/objects/Group41.h" +#include "opendnp3/objects/Group42.h" +#include "opendnp3/objects/Group43.h" +#include "opendnp3/objects/Group50.h" +#include "opendnp3/objects/Group121.h" +#include "opendnp3/objects/Group122.h" + +namespace opendnp3 +{ + +// Group 1 +typedef ConvertQ ConvertGroup1Var2; + +// Group 2 +typedef ConvertQ ConvertGroup2Var1; +typedef ConvertQT ConvertGroup2Var2; +typedef ConvertQTDowncast ConvertGroup2Var3; + +// Group 3 +typedef ConvertQ ConvertGroup3Var2; + +// Group 3 +typedef ConvertQ ConvertGroup4Var1; +typedef ConvertQT ConvertGroup4Var2; +typedef ConvertQTDowncast ConvertGroup4Var3; + +// Group 10 +typedef ConvertQ ConvertGroup10Var2; + +// Group 11 +typedef ConvertQ ConvertGroup11Var1; +typedef ConvertQT ConvertGroup11Var2; + +// Group 12 +struct ConvertGroup12Var1 : private openpal::StaticOnly +{ + static Group12Var1 Apply(const ControlRelayOutputBlock& crob) + { + Group12Var1 ret; + ret.code = crob.rawCode; + ret.count = crob.count; + ret.onTime = crob.onTimeMS; + ret.offTime = crob.offTimeMS; + ret.status = CommandStatusToType(crob.status); + return ret; + } +}; + +// Group 13 +struct ConvertGroup13Var1 : private openpal::StaticOnly +{ + static Group13Var1 Apply(const BinaryCommandEvent& ev) + { + Group13Var1 ret; + ret.flags = ev.GetFlags().value; + return ret; + } +}; + +struct ConvertGroup13Var2 : private openpal::StaticOnly +{ + static Group13Var2 Apply(const BinaryCommandEvent& ev) + { + Group13Var2 ret; + ret.flags = ev.GetFlags().value; + ret.time = ev.time; + return ret; + } +}; + +// Group 20 +typedef ConvertQV ConvertGroup20Var1; +typedef ConvertQVandTruncate ConvertGroup20Var2; + +typedef ConvertV ConvertGroup20Var5; +typedef ConvertVandTruncate ConvertGroup20Var6; + +// Group 21 +typedef ConvertQV ConvertGroup21Var1; +typedef ConvertQVandTruncate ConvertGroup21Var2; + +typedef ConvertQVT ConvertGroup21Var5; +typedef ConvertQVTandTruncate ConvertGroup21Var6; + +typedef ConvertV ConvertGroup21Var9; +typedef ConvertVandTruncate ConvertGroup21Var10; + +// Group 22 +typedef ConvertQV ConvertGroup22Var1; +typedef ConvertQVandTruncate ConvertGroup22Var2; + +typedef ConvertQVT ConvertGroup22Var5; +typedef ConvertQVTandTruncate ConvertGroup22Var6; + +// Group 23 +typedef ConvertQV ConvertGroup23Var1; +typedef ConvertQVandTruncate ConvertGroup23Var2; +typedef ConvertQVT ConvertGroup23Var5; +typedef ConvertQVTandTruncate ConvertGroup23Var6; + +// Group 30 +typedef ConvertQVRangeCheck ConvertGroup30Var1; +typedef ConvertQVRangeCheck ConvertGroup30Var2; +typedef ConvertVRangeCheck ConvertGroup30Var3; +typedef ConvertVRangeCheck ConvertGroup30Var4; +typedef ConvertQVRangeCheck ConvertGroup30Var5; +typedef ConvertQV ConvertGroup30Var6; + +// Group 32 +typedef ConvertQVRangeCheck ConvertGroup32Var1; +typedef ConvertQVRangeCheck ConvertGroup32Var2; +typedef ConvertQVTRangeCheck ConvertGroup32Var3; +typedef ConvertQVTRangeCheck ConvertGroup32Var4; +typedef ConvertQVRangeCheck ConvertGroup32Var5; +typedef ConvertQV ConvertGroup32Var6; +typedef ConvertQVTRangeCheck ConvertGroup32Var7; +typedef ConvertQVT ConvertGroup32Var8; + +typedef ConvertQVRangeCheck ConvertGroup40Var1; +typedef ConvertQVRangeCheck ConvertGroup40Var2; +typedef ConvertQVRangeCheck ConvertGroup40Var3; +typedef ConvertQV ConvertGroup40Var4; + +// Group 41 +typedef ConvertQS ConvertGroup41Var1; +typedef ConvertQS ConvertGroup41Var2; +typedef ConvertQS ConvertGroup41Var3; +typedef ConvertQS ConvertGroup41Var4; + +// Group 42 +typedef ConvertQVRangeCheck ConvertGroup42Var1; +typedef ConvertQVRangeCheck ConvertGroup42Var2; +typedef ConvertQVTRangeCheck ConvertGroup42Var3; +typedef ConvertQVTRangeCheck ConvertGroup42Var4; +typedef ConvertQVRangeCheck ConvertGroup42Var5; +typedef ConvertQV ConvertGroup42Var6; +typedef ConvertQVTRangeCheck ConvertGroup42Var7; +typedef ConvertQVT ConvertGroup42Var8; + +// Group 43 +template +struct ConvertGroup43RangeCheck : private openpal::StaticOnly +{ + static Target Apply(const AnalogCommandEvent& src) + { + Target t; + DownSampling::Apply(src.value, t.value); + t.status = CommandStatusToType(src.status); + return t; + } +}; + +template +struct ConvertGroup43WithTimeRangeCheck : private openpal::StaticOnly +{ + static Target Apply(const AnalogCommandEvent& src) + { + Target t; + DownSampling::Apply(src.value, t.value); + t.status = CommandStatusToType(src.status); + t.time = src.time; + return t; + } +}; + +typedef ConvertGroup43RangeCheck ConvertGroup43Var1; +typedef ConvertGroup43RangeCheck ConvertGroup43Var2; +typedef ConvertGroup43WithTimeRangeCheck ConvertGroup43Var3; +typedef ConvertGroup43WithTimeRangeCheck ConvertGroup43Var4; +typedef ConvertGroup43RangeCheck ConvertGroup43Var5; + +struct ConvertGroup43Var6 : private openpal::StaticOnly +{ + static Group43Var6 Apply(const AnalogCommandEvent& src) + { + Group43Var6 t; + t.value = src.value; + t.status = CommandStatusToType(src.status); + return t; + } +}; + +typedef ConvertGroup43WithTimeRangeCheck ConvertGroup43Var7; + +struct ConvertGroup43Var8 : private openpal::StaticOnly +{ + static Group43Var8 Apply(const AnalogCommandEvent& src) + { + Group43Var8 t; + t.value = src.value; + t.status = CommandStatusToType(src.status); + t.time = src.time; + return t; + } +}; + +// Group 50 +struct ConvertGroup50Var4 : private openpal::StaticOnly +{ + static Group50Var4 Apply(const TimeAndInterval& value) + { + Group50Var4 ret; + ret.time = value.time; + ret.interval = value.interval; + ret.units = value.units; + return ret; + } +}; + +// Group 121 +struct ConvertGroup121Var1 : private openpal::StaticOnly +{ + static Group121Var1 Apply(const SecurityStat& value) + { + Group121Var1 ret; + ret.flags = value.quality; + ret.assocId = value.value.assocId; + ret.value = value.value.count; + return ret; + } +}; + +// Group 122 +struct ConvertGroup122Var1 : private openpal::StaticOnly +{ + static Group122Var1 Apply(const SecurityStat& value) + { + Group122Var1 ret; + ret.flags = value.quality; + ret.assocId = value.value.assocId; + ret.value = value.value.count; + return ret; + } +}; + +struct ConvertGroup122Var2 : private openpal::StaticOnly +{ + static Group122Var2 Apply(const SecurityStat& value) + { + Group122Var2 ret; + ret.flags = value.quality; + ret.assocId = value.value.assocId; + ret.value = value.value.count; + ret.time = value.time; + return ret; + } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.cpp new file mode 100644 index 0000000..bba2cc3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.cpp @@ -0,0 +1,66 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUHeaderParser.h" + +#include +#include +#include + +#include "opendnp3/LogLevels.h" +#include "opendnp3/app/APDUHeader.h" + +namespace opendnp3 +{ + +bool APDUHeaderParser::ParseRequest(const openpal::RSlice& apdu, APDUHeader& header, openpal::Logger* pLogger) +{ + if (apdu.Size() < APDU_REQUEST_HEADER_SIZE) + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Request fragment with insufficient size of %u bytes", apdu.Size()); + return false; + } + else + { + header.control = AppControlField(apdu[0]); + header.function = FunctionCodeFromType(apdu[1]); + return true; + } +} + +bool APDUHeaderParser::ParseResponse(const openpal::RSlice& apdu, APDUResponseHeader& header, openpal::Logger* pLogger) +{ + if (apdu.Size() < APDU_RESPONSE_HEADER_SIZE) + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Response fragment with insufficient size of %u bytes", apdu.Size()); + return false; + } + else + { + header.control = AppControlField(apdu[0]); + header.function = FunctionCodeFromType(apdu[1]); + header.IIN.LSB = apdu[2]; + header.IIN.MSB = apdu[3]; + return true; + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.h new file mode 100644 index 0000000..3615e40 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUHeaderParser.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDUHEADERPARSER_H +#define OPENDNP3_APDUHEADERPARSER_H + +#include +#include +#include + +#include "opendnp3/app/APDUHeader.h" + + +namespace opendnp3 +{ + +class APDUHeaderParser : private openpal::StaticOnly +{ + +public: + + static bool ParseRequest(const openpal::RSlice& apdu, APDUHeader& header, openpal::Logger* pLogger = nullptr); + + static bool ParseResponse(const openpal::RSlice& apdu, APDUResponseHeader& header, openpal::Logger* pLogger = nullptr); + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.cpp new file mode 100644 index 0000000..26f8f5e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.cpp @@ -0,0 +1,166 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUParser.h" + +#include "opendnp3/LogLevels.h" + +#include "opendnp3/gen/QualifierCode.h" +#include "opendnp3/app/GroupVariationRecord.h" +#include "opendnp3/app/MeasurementFactory.h" + +#include "opendnp3/app/parsing/ObjectHeaderParser.h" +#include "opendnp3/app/parsing/CountParser.h" +#include "opendnp3/app/parsing/RangeParser.h" +#include "opendnp3/app/parsing/CountIndexParser.h" +#include "opendnp3/app/parsing/FreeFormatParser.h" + +#include + + +using namespace openpal; + +namespace opendnp3 +{ + +ParseResult APDUParser::Parse(const openpal::RSlice& buffer, IAPDUHandler& handler, openpal::Logger& logger, ParserSettings settings) +{ + return Parse(buffer, handler, &logger, settings); +} + +ParseResult APDUParser::Parse(const openpal::RSlice& buffer, IAPDUHandler& handler, openpal::Logger* pLogger, ParserSettings settings) +{ + // do two state parsing process with logging and white-listing first but no handling on the first pass + auto result = ParseSinglePass(buffer, pLogger, nullptr, &handler, settings); + // if the first pass was successful, do a 2nd pass with the handler but no logging or white-list + return (result == ParseResult::OK) ? ParseSinglePass(buffer, nullptr, &handler, nullptr, settings) : result; +} + +ParseResult APDUParser::ParseAndLogAll(const openpal::RSlice& buffer, openpal::Logger* pLogger, ParserSettings settings) +{ + return ParseSinglePass(buffer, pLogger, nullptr, nullptr, settings); +} + +ParseResult APDUParser::ParseSinglePass(const openpal::RSlice& buffer, openpal::Logger* pLogger, IAPDUHandler* pHandler, IWhiteList* pWhiteList, const ParserSettings& settings) +{ + uint32_t count = 0; + RSlice copy(buffer); + while(copy.Size() > 0) + { + auto result = ParseHeader(copy, pLogger, count, settings, pHandler, pWhiteList); + ++count; + if (result != ParseResult::OK) + { + return result; + } + } + return ParseResult::OK; +} + +ParseResult APDUParser::ParseHeader(RSlice& buffer, openpal::Logger* pLogger, uint32_t count, const ParserSettings& settings, IAPDUHandler* pHandler, IWhiteList* pWhiteList) +{ + ObjectHeader header; + auto result = ObjectHeaderParser::ParseObjectHeader(header, buffer, pLogger); + if (result != ParseResult::OK) + { + return result; + } + + const auto GV = GroupVariationRecord::GetRecord(header.group, header.variation); + + if (GV.enumeration == GroupVariation::UNKNOWN) + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Unknown object %i / %i", GV.group, GV.variation); + return ParseResult::UNKNOWN_OBJECT; + } + + // if a white-list is defined and it doesn't validate, exit early + if (pWhiteList && !pWhiteList->IsAllowed(count, GV.enumeration, QualifierCodeFromType(header.qualifier))) + { + FORMAT_LOGGER_BLOCK( + pLogger, + flags::WARN, + "Header (%i) w/ Object (%i,%i) and qualifier (%i) failed whitelist", + count, + header.group, + header.variation, + header.qualifier + ); + + return ParseResult::NOT_ON_WHITELIST; + } + + + return APDUParser::ParseQualifier(buffer, pLogger, HeaderRecord(GV, header.qualifier, count), settings, pHandler); +} + +ParseResult APDUParser::ParseQualifier(RSlice& buffer, openpal::Logger* pLogger, const HeaderRecord& record, const ParserSettings& settings, IAPDUHandler* pHandler) +{ + switch (record.GetQualifierCode()) + { + case(QualifierCode::ALL_OBJECTS) : + return HandleAllObjectsHeader(pLogger, record, settings, pHandler); + + case(QualifierCode::UINT8_CNT) : + return CountParser::ParseHeader(buffer, NumParser::OneByte(), settings, record, pLogger, pHandler); + + case(QualifierCode::UINT16_CNT) : + return CountParser::ParseHeader(buffer, NumParser::TwoByte(), settings, record, pLogger, pHandler); + + case(QualifierCode::UINT8_START_STOP) : + return RangeParser::ParseHeader(buffer, NumParser::OneByte(), settings, record, pLogger, pHandler); + + case(QualifierCode::UINT16_START_STOP) : + return RangeParser::ParseHeader(buffer, NumParser::TwoByte(), settings, record, pLogger, pHandler); + + case(QualifierCode::UINT8_CNT_UINT8_INDEX) : + return CountIndexParser::ParseHeader(buffer, NumParser::OneByte(), settings, record, pLogger, pHandler); + + case(QualifierCode::UINT16_CNT_UINT16_INDEX) : + return CountIndexParser::ParseHeader(buffer, NumParser::TwoByte(), settings, record, pLogger, pHandler); + + case(QualifierCode::UINT16_FREE_FORMAT) : + return FreeFormatParser::ParseHeader(buffer, settings, record, pLogger, pHandler); + + default: + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Unknown qualifier %x", record.qualifier); + return ParseResult::UNKNOWN_QUALIFIER; + } +} + +ParseResult APDUParser::HandleAllObjectsHeader(openpal::Logger* pLogger, const HeaderRecord& record, const ParserSettings& settings, IAPDUHandler* pHandler) +{ + FORMAT_LOGGER_BLOCK(pLogger, settings.Filters(), + "%03u,%03u - %s - %s", + record.group, + record.variation, + GroupVariationToString(record.enumeration), + QualifierCodeToString(QualifierCode::ALL_OBJECTS)); + + if (pHandler) + { + pHandler->OnHeader(AllObjectsHeader(record)); + } + + return ParseResult::OK; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.h new file mode 100644 index 0000000..5e97b3a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/APDUParser.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_APDUPARSER_H +#define OPENDNP3_APDUPARSER_H + +#include +#include + +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/ParserSettings.h" +#include "opendnp3/app/parsing/NumParser.h" + +namespace opendnp3 +{ + +class APDUParser : private openpal::StaticOnly +{ +public: + + static ParseResult Parse(const openpal::RSlice& buffer, IAPDUHandler& handler, openpal::Logger& logger, ParserSettings settings = ParserSettings::Default()); + + static ParseResult Parse(const openpal::RSlice& buffer, IAPDUHandler& handler, openpal::Logger* pLogger, ParserSettings settings = ParserSettings::Default()); + + static ParseResult ParseAndLogAll(const openpal::RSlice& buffer, openpal::Logger* pLogger, ParserSettings settings = ParserSettings::Default()); + + static ParseResult ParseSinglePass(const openpal::RSlice& buffer, openpal::Logger* pLogger, IAPDUHandler* pHandler, IWhiteList* pWhiteList, const ParserSettings& settings); + +private: + + static bool AllowAll(uint32_t headerCount, GroupVariation gv, QualifierCode qc) + { + return true; + } + + static ParseResult ParseHeaders(const openpal::RSlice& buffer, openpal::Logger* pLogger, const ParserSettings& settings, IAPDUHandler* pHandler); + + static ParseResult ParseHeader(openpal::RSlice& buffer, openpal::Logger* pLogger, uint32_t count, const ParserSettings& settings, IAPDUHandler* pHandler, IWhiteList* pWhiteList); + + static ParseResult ParseQualifier(openpal::RSlice& buffer, openpal::Logger* pLogger, const HeaderRecord& record, const ParserSettings& settings, IAPDUHandler* pHandler); + + static ParseResult HandleAllObjectsHeader(openpal::Logger* pLogger, const HeaderRecord& record, const ParserSettings& settings, IAPDUHandler* pHandler); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.cpp new file mode 100644 index 0000000..bf30fcd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.cpp @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "BitReader.h" + +#include +#include + + +namespace opendnp3 +{ + +uint32_t NumBytesInBits(uint32_t numBits) +{ + uint32_t numBytes = numBits / 8; + return ((numBits % 8) == 0) ? numBytes : numBytes + 1; +} + +bool GetBit(const openpal::RSlice& buffer, uint32_t position) +{ + uint32_t byte = position / 8; + uint32_t bit = position % 8; + assert(byte < buffer.Size()); + return (buffer[byte] & (1 << bit)) != 0; +} + +uint32_t NumBytesInDoubleBits(uint32_t numBits) +{ + uint32_t numBytes = numBits / 4; + return ((numBits % 4) == 0) ? numBytes : numBytes + 1; +} + +DoubleBit GetDoubleBit(const openpal::RSlice& buffer, uint32_t index) +{ + uint32_t byteNumber = index / 4; + assert(byteNumber < buffer.Size()); + uint8_t byte = buffer[byteNumber]; + uint32_t bitshift = 2 * (index % 4); + return DoubleBitFromType((byte >> bitshift) & 0x03); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.h new file mode 100644 index 0000000..9ce03f8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BitReader.h @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_BITREADER_H +#define OPENDNP3_BITREADER_H + +#include + +#include "opendnp3/gen/DoubleBit.h" + +namespace opendnp3 +{ + +uint32_t NumBytesInBits(uint32_t numBits); +bool GetBit(const openpal::RSlice& buffer, uint32_t position); + +uint32_t NumBytesInDoubleBits(uint32_t numBits); +DoubleBit GetDoubleBit(const openpal::RSlice& buffer, uint32_t position); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BufferedCollection.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BufferedCollection.h new file mode 100644 index 0000000..b74f42f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/BufferedCollection.h @@ -0,0 +1,71 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_BUFFEREDCOLLECTION_H +#define OPENDNP3_BUFFEREDCOLLECTION_H + +#include "opendnp3/app/parsing/ICollection.h" + +namespace opendnp3 +{ + +template +class BufferedCollection : public ICollection +{ +public: + + BufferedCollection(const openpal::RSlice& buffer, size_t count, const ReadFunc& readFunc) : + buffer(buffer), + COUNT(count), + readFunc(readFunc) + {} + + virtual size_t Count() const override final + { + return COUNT; + } + + + virtual void Foreach(IVisitor& visitor) const final + { + openpal::RSlice copy(buffer); + + for (uint32_t pos = 0; pos < COUNT; ++pos) + { + visitor.OnValue(readFunc(copy, pos)); + } + } + +private: + + openpal::RSlice buffer; + const size_t COUNT; + ReadFunc readFunc; +}; + +template +BufferedCollection CreateBufferedCollection(const openpal::RSlice& buffer, uint32_t count, const ReadFunc& readFunc) +{ + return BufferedCollection(buffer, count, readFunc); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Collections.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Collections.h new file mode 100644 index 0000000..c56c1c6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Collections.h @@ -0,0 +1,101 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COLLECTIONS_H +#define OPENDNP3_COLLECTIONS_H + +#include "opendnp3/app/parsing/ICollection.h" + +namespace opendnp3 +{ + +/** +* A simple collection derived from an underlying array +*/ +template +class ArrayCollection : public ICollection +{ +public: + + ArrayCollection(const T* pArray_, size_t count) : pArray(pArray_), COUNT(count) + {} + + + virtual size_t Count() const override final + { + return COUNT; + } + + virtual void Foreach(IVisitor& visitor) const override final + { + for (uint32_t i = 0; i < COUNT; ++i) + { + visitor.OnValue(pArray[i]); + } + } + +private: + + const T* pArray; + const size_t COUNT; +}; + +template +class TransformedCollection : public ICollection < U > +{ +public: + + TransformedCollection(const ICollection& input, Transform transform) : + input(&input), + transform(transform) + {} + + virtual size_t Count() const override final + { + return input->Count(); + } + + virtual void Foreach(IVisitor& visitor) const override final + { + auto process = [this, &visitor](const T & elem) + { + visitor.OnValue(transform(elem)); + }; + input->ForeachItem(process); + } + +private: + + const ICollection* input; + Transform transform; + +}; + +template +TransformedCollection Map(const ICollection& input, Transform transform) +{ + return TransformedCollection(input, transform); +} + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.cpp new file mode 100644 index 0000000..d35435a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.cpp @@ -0,0 +1,261 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CountIndexParser.h" + +#include + +#include "opendnp3/objects/Group2.h" +#include "opendnp3/objects/Group4.h" +#include "opendnp3/objects/Group11.h" +#include "opendnp3/objects/Group12.h" +#include "opendnp3/objects/Group13.h" +#include "opendnp3/objects/Group22.h" +#include "opendnp3/objects/Group23.h" +#include "opendnp3/objects/Group32.h" +#include "opendnp3/objects/Group41.h" +#include "opendnp3/objects/Group42.h" +#include "opendnp3/objects/Group43.h" + +#include "opendnp3/app/parsing/BufferedCollection.h" + +using namespace openpal; + +namespace opendnp3 +{ + +CountIndexParser::CountIndexParser(uint16_t count_, uint32_t requiredSize_, const NumParser& numparser_, HandleFun handler_) : + count(count_), + requiredSize(requiredSize_), + numparser(numparser_), + handler(handler_) +{} + +ParseResult CountIndexParser::ParseHeader( + openpal::RSlice& buffer, + const NumParser& numparser, + const ParserSettings& settings, + const HeaderRecord& record, + openpal::Logger* pLogger, + IAPDUHandler* pHandler) +{ + uint16_t count; + auto res = numparser.ParseCount(buffer, count, pLogger); + if (res == ParseResult::OK) + { + FORMAT_LOGGER_BLOCK(pLogger, settings.Filters(), + "%03u,%03u %s, %s [%u]", + record.group, + record.variation, + GroupVariationToString(record.enumeration), + QualifierCodeToString(record.GetQualifierCode()), + count); + + return ParseCountOfObjects(buffer, record, numparser, count, pLogger, pHandler); + } + else + { + return res; + } +} + +ParseResult CountIndexParser::Process(const HeaderRecord& record, openpal::RSlice& buffer, IAPDUHandler* pHandler, openpal::Logger* pLogger) const +{ + if (buffer.Size() < requiredSize) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for specified objects"); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } + else + { + if (pHandler) + { + handler(record, count, numparser, buffer, *pHandler); + } + buffer.Advance(requiredSize); + return ParseResult::OK; + } +} + + +ParseResult CountIndexParser::ParseCountOfObjects(openpal::RSlice& buffer, const HeaderRecord& record, const NumParser& numparser, uint16_t count, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + switch (record.enumeration) + { + case(GroupVariation::Group2Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group2Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group2Var3) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group4Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group4Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group4Var3) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + + case(GroupVariation::Group11Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group11Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group12Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group13Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group13Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group22Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group22Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group22Var5) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group22Var6) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group23Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group23Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group23Var5) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group23Var6) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group32Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var3) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var4) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var5) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var6) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var7) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group32Var8) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group41Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group41Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group41Var3) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group41Var4) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group42Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var3) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var4) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var5) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var6) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var7) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group42Var8) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group43Var1) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var2) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var3) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var4) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var5) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var6) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var7) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group43Var8) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group50Var4) : + return CountIndexParser::From(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group111Var0) : + return ParseIndexPrefixedOctetData(buffer, record, numparser, count, pLogger, pHandler); + + case(GroupVariation::Group122Var1) : + return CountIndexParser::FromType(count, numparser).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group122Var2) : + return CountIndexParser::FromType(count, numparser).Process(record, buffer, pHandler, pLogger); + + default: + + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, + "Unsupported qualifier/object - %s - %i / %i", + QualifierCodeToString(record.GetQualifierCode()), record.group, record.variation); + + return ParseResult::INVALID_OBJECT_QUALIFIER; + } +} + +ParseResult CountIndexParser::ParseIndexPrefixedOctetData(openpal::RSlice& buffer, const HeaderRecord& record, const NumParser& numparser, uint32_t count, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + if (record.variation == 0) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Octet string variation 0 may only be used in requests"); + return ParseResult::INVALID_OBJECT; + } + + const uint32_t TOTAL_SIZE = count * (numparser.NumBytes() + record.variation); + + if (buffer.Size() < TOTAL_SIZE) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for specified bitfield objects"); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } + + if (pHandler) + { + auto read = [&numparser, record](RSlice & buffer, uint32_t pos) -> Indexed + { + auto index = numparser.ReadNum(buffer); + OctetString octets(buffer.Take(record.variation)); + buffer.Advance(record.variation); + return WithIndex(octets, index); + }; + + auto collection = CreateBufferedCollection>(buffer, count, read); + pHandler->OnHeader(PrefixHeader(record, count), collection); + } + + buffer.Advance(TOTAL_SIZE); + return ParseResult::OK; +} + +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.h new file mode 100644 index 0000000..3dd7c88 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountIndexParser.h @@ -0,0 +1,132 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COUNTINDEXPARSER_H +#define OPENDNP3_COUNTINDEXPARSER_H + +#include +#include + +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/NumParser.h" +#include "opendnp3/app/parsing/ParserSettings.h" + +#include "opendnp3/app/parsing/BufferedCollection.h" + +namespace opendnp3 +{ + +class CountIndexParser +{ + typedef void(*HandleFun)(const HeaderRecord& record, uint16_t count, const NumParser& numparser, const openpal::RSlice& buffer, IAPDUHandler& handler); + +public: + + static ParseResult ParseHeader( + openpal::RSlice& buffer, + const NumParser& numparser, + const ParserSettings& settings, + const HeaderRecord& record, + openpal::Logger* pLogger, + IAPDUHandler* pHandler + ); + +private: + + // Process the count handler against the buffer + ParseResult Process(const HeaderRecord& record, openpal::RSlice& buffer, IAPDUHandler* pHandler, openpal::Logger* pLogger) const; + + // Create a count handler from a fixed size descriptor + template + static CountIndexParser From(uint16_t count, const NumParser& numparser); + + // Create a count handler from a fixed size descriptor + template + static CountIndexParser FromType(uint16_t count, const NumParser& numparser); + + static ParseResult ParseCountOfObjects(openpal::RSlice& buffer, const HeaderRecord& record, const NumParser& numparser, uint16_t count, openpal::Logger* pLogger, IAPDUHandler* pHandler); + + static ParseResult ParseIndexPrefixedOctetData(openpal::RSlice& buffer, const HeaderRecord& record, const NumParser& numParser, uint32_t count, openpal::Logger* pLogger, IAPDUHandler* pHandler); + + template + static void InvokeCountOf(const HeaderRecord& record, uint16_t count, const NumParser& numparser, const openpal::RSlice& buffer, IAPDUHandler& handler); + + template + static void InvokeCountOfType(const HeaderRecord& record, uint16_t count, const NumParser& numparser, const openpal::RSlice& buffer, IAPDUHandler& handler); + + CountIndexParser(uint16_t count, uint32_t requiredSize, const NumParser& numparser, HandleFun handler); + + uint16_t count; + uint32_t requiredSize; + NumParser numparser; + HandleFun handler; + + CountIndexParser() = delete; +}; + +template +CountIndexParser CountIndexParser::From(uint16_t count, const NumParser& numparser) +{ + const uint32_t SIZE = static_cast(count) * (Descriptor::Size() + numparser.NumBytes()); + return CountIndexParser(count, SIZE, numparser, &InvokeCountOf); +} + +template +CountIndexParser CountIndexParser::FromType(uint16_t count, const NumParser& numparser) +{ + const uint32_t SIZE = static_cast(count) * (Type::Size() + numparser.NumBytes()); + return CountIndexParser(count, SIZE, numparser, &InvokeCountOfType); +} + +template +void CountIndexParser::InvokeCountOf(const HeaderRecord& record, uint16_t count, const NumParser& numparser, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + auto read = [&numparser](openpal::RSlice & buffer, uint32_t) -> Indexed + { + Indexed pair; + pair.index = numparser.ReadNum(buffer); + Descriptor::ReadTarget(buffer, pair.value); + return pair; + }; + + auto collection = CreateBufferedCollection>(buffer, count, read); + handler.OnHeader(PrefixHeader(record, count), collection); +} + +template +void CountIndexParser::InvokeCountOfType(const HeaderRecord& record, uint16_t count, const NumParser& numparser, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + auto read = [&numparser](openpal::RSlice & buffer, uint32_t) -> Indexed + { + Indexed pair; + pair.index = numparser.ReadNum(buffer); + Type::Read(buffer, pair.value); + return pair; + }; + + auto collection = CreateBufferedCollection>(buffer, count, read); + handler.OnHeader(PrefixHeader(record, count), collection); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.cpp new file mode 100644 index 0000000..14f8ac9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.cpp @@ -0,0 +1,127 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CountParser.h" + +#include "opendnp3/LogLevels.h" + +#include + +namespace opendnp3 +{ + +CountParser::CountParser(uint16_t count, uint32_t requiredSize, HandleFun handler) : + count(count), + requiredSize(requiredSize), + handler(handler) +{ + +} + +ParseResult CountParser::Process(const HeaderRecord& record, openpal::RSlice& buffer, IAPDUHandler* pHandler, openpal::Logger* pLogger) const +{ + if (buffer.Size() < requiredSize) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for specified objects"); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } + else + { + if (pHandler) + { + handler(record, count, buffer, *pHandler); + } + buffer.Advance(requiredSize); + return ParseResult::OK; + } +} + +ParseResult CountParser::ParseHeader(openpal::RSlice& buffer, const NumParser& numParser, const ParserSettings& settings, const HeaderRecord& record, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + uint16_t count; + auto result = numParser.ParseCount(buffer, count, pLogger); + if (result == ParseResult::OK) + { + FORMAT_LOGGER_BLOCK(pLogger, settings.Filters(), + "%03u,%03u %s, %s [%u]", + record.group, + record.variation, + GroupVariationToString(record.enumeration), + QualifierCodeToString(record.GetQualifierCode()), + count); + + if (settings.ExpectsContents()) + { + return ParseCountOfObjects(buffer, record, count, pLogger, pHandler); + } + else + { + if (pHandler) + { + pHandler->OnHeader(CountHeader(record, count)); + } + + return ParseResult::OK; + } + } + else + { + return result; + } +} + +ParseResult CountParser::ParseCountOfObjects(openpal::RSlice& buffer, const HeaderRecord& record, uint16_t count, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + switch (record.enumeration) + { + case(GroupVariation::Group50Var1) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group51Var1) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group51Var2) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group52Var1) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group52Var2) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group120Var3) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group120Var4) : + return CountParser::From(count).Process(record, buffer, pHandler, pLogger); + + default: + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Unsupported qualifier/object - %s - %i / %i", + QualifierCodeToString(record.GetQualifierCode()), + record.group, + record.variation); + + return ParseResult::INVALID_OBJECT_QUALIFIER; + } +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.h new file mode 100644 index 0000000..9fa814d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/CountParser.h @@ -0,0 +1,99 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COUNTPARSER_H +#define OPENDNP3_COUNTPARSER_H + +#include +#include + +#include "opendnp3/app/parsing/Functions.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/NumParser.h" +#include "opendnp3/app/parsing/ParserSettings.h" +#include "opendnp3/app/parsing/BufferedCollection.h" + +namespace opendnp3 +{ + +class CountParser +{ + typedef void (*HandleFun)(const HeaderRecord& record, uint16_t count, const openpal::RSlice& buffer, IAPDUHandler& handler); + +public: + + static ParseResult ParseHeader( + openpal::RSlice& buffer, + const NumParser& numparser, + const ParserSettings& settings, + const HeaderRecord& record, + openpal::Logger* pLogger, + IAPDUHandler* pHandler + ); + +private: + + // Process the count handler against the buffer + ParseResult Process(const HeaderRecord& record, openpal::RSlice& buffer, IAPDUHandler* pHandler, openpal::Logger* pLogger) const; + + // Create a count handler from a fixed size descriptor + template + static CountParser From(uint16_t count); + + static ParseResult ParseCountOfObjects(openpal::RSlice& buffer, const HeaderRecord& record, uint16_t count, openpal::Logger* pLogger, IAPDUHandler* pHandler); + + template + static void InvokeCountOf(const HeaderRecord& record, uint16_t count, const openpal::RSlice& buffer, IAPDUHandler& handler); + + CountParser(uint16_t count, uint32_t requiredSize, HandleFun handler); + + uint16_t count; + uint32_t requiredSize; + HandleFun handler; + + CountParser() = delete; +}; + +template +CountParser CountParser::From(uint16_t count) +{ + uint32_t size = static_cast(count) * Descriptor::Size(); + return CountParser(count, size, &InvokeCountOf); +} + +template +void CountParser::InvokeCountOf(const HeaderRecord& record, uint16_t count, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + auto read = [](openpal::RSlice & buffer, uint32_t) -> T + { + T value; + T::Read(buffer, value); + return value; + }; + + auto collection = CreateBufferedCollection(buffer, count, read); + handler.OnHeader(CountHeader(record, count), collection); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.cpp new file mode 100644 index 0000000..90185b3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.cpp @@ -0,0 +1,159 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "FreeFormatParser.h" + +#include "opendnp3/app/parsing/ObjectHeaderParser.h" +#include "opendnp3/app/GroupVariationRecord.h" +#include "opendnp3/LogLevels.h" + +#include +#include + + +using namespace openpal; + +namespace opendnp3 +{ +ParseResult FreeFormatParser::ParseHeader(openpal::RSlice& buffer, const ParserSettings& settings, const HeaderRecord& record, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + if (buffer.Size() < 3) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for free format count and size"); + return ParseResult::NOT_ENOUGH_DATA_FOR_HEADER; + } + + const uint8_t FREE_FORMAT_COUNT = UInt8::ReadBuffer(buffer); + const uint16_t FREE_FORMAT_SIZE = UInt16::ReadBuffer(buffer); + + FORMAT_LOGGER_BLOCK(pLogger, settings.Filters(), + "%03u,%03u %s, %s, count: %u size: %u", + record.group, + record.variation, + GroupVariationToString(record.enumeration), + QualifierCodeToString(record.GetQualifierCode()), + FREE_FORMAT_COUNT, + FREE_FORMAT_SIZE + ); + + if (FREE_FORMAT_COUNT != 1) + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Unsupported free-format count of %u", FREE_FORMAT_COUNT); + return ParseResult::UNREASONABLE_OBJECT_COUNT; + } + + if (buffer.Size() < FREE_FORMAT_SIZE) + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Insufficient data (%u) for free format object of size (%u)", buffer.Size(), FREE_FORMAT_SIZE); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } + + RSlice copy(buffer.Take(FREE_FORMAT_SIZE)); + buffer.Advance(FREE_FORMAT_SIZE); + + FreeFormatHeader header(record, FREE_FORMAT_COUNT); + + switch (record.enumeration) + { + case(GroupVariation::Group120Var1) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var2) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var5) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var6) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var7) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var9) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var8) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var10) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var11) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var12) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var13) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var14) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + case(GroupVariation::Group120Var15) : + return ParseFreeFormat(ParseAny, header, FREE_FORMAT_SIZE, copy, pHandler, pLogger); + + default: + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, + "Unsupported qualifier/object - %s - %i / %i", + QualifierCodeToString(record.GetQualifierCode()), record.group, record.variation + ); + + return ParseResult::INVALID_OBJECT_QUALIFIER; + } + +} + +ParseResult FreeFormatParser::ParseFreeFormat(FreeFormatHandler parser, const FreeFormatHeader& header, uint16_t size, openpal::RSlice& objects, IAPDUHandler* pHandler, openpal::Logger* pLogger) +{ + if (parser(header, objects, pHandler)) + { + return ParseResult::OK; + } + else + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Insufficient data for free-format object: (%i, %i)", header.group, header.variation); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.h new file mode 100644 index 0000000..6985b69 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/FreeFormatParser.h @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_FREEFORMATPARSER_H +#define OPENDNP3_FREEFORMATPARSER_H + +#include +#include +#include + +#include "opendnp3/app/parsing/ObjectHeaderParser.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/parsing/ParserSettings.h" + +namespace opendnp3 +{ + +/** + Parser for free format (0x5B) +*/ +class FreeFormatParser : private openpal::StaticOnly +{ +public: + + static ParseResult ParseHeader(openpal::RSlice& buffer, const ParserSettings& settings, const HeaderRecord& record, openpal::Logger* pLogger, IAPDUHandler* pHandler); + +private: + + typedef bool(&FreeFormatHandler)(const FreeFormatHeader& header, const openpal::RSlice& objects, IAPDUHandler* pHandler); + + static ParseResult ParseFreeFormat(FreeFormatHandler handler, const FreeFormatHeader& header, uint16_t size, openpal::RSlice& objects, IAPDUHandler* pHandler, openpal::Logger* pLogger); + + // Free format handlers + + template + static bool ParseAny(const FreeFormatHeader& header, const openpal::RSlice& object, IAPDUHandler* pHandler) + { + T value; + auto success = value.Read(object); + if (success && pHandler) + { + pHandler->OnHeader(header, value, object); + } + return success; + } +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Functions.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Functions.h new file mode 100644 index 0000000..1f9a98f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/Functions.h @@ -0,0 +1,56 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#ifndef OPENDNP3_FUNCTIONS_H +#define OPENDNP3_FUNCTIONS_H + +#include + +namespace opendnp3 +{ + +// a function that reads a type from a buffer and returns true if successful +template +using ReadFunction = bool(*)(openpal::RSlice& buffer, T& output); + +} + +#endif \ No newline at end of file diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.cpp new file mode 100644 index 0000000..5c292e0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.cpp @@ -0,0 +1,579 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "IAPDUHandler.h" + +using namespace openpal; + +namespace opendnp3 +{ + +IAPDUHandler::IAPDUHandler() : + numTotalHeaders(0), + numIgnoredHeaders(0) +{ + +} + +void IAPDUHandler::Reset() +{ + numTotalHeaders = 0; + numIgnoredHeaders = 0; + errors.Clear(); +} + +IINField IAPDUHandler::Errors() const +{ + return errors; +} + +void IAPDUHandler::OnHeader(const AllObjectsHeader& header) +{ + Record(header, this->ProcessHeader(header)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header) +{ + Record(header, this->ProcessHeader(header)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header) +{ + Record(header, this->ProcessHeader(header)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var7& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var8& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var9& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var10& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var11& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var12& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var13& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var14& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const FreeFormatHeader& header, const Group120Var15& value, const openpal::RSlice& object) +{ + Record(header, this->ProcessHeader(header, value, object)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const CountHeader& header, const ICollection& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const RangeHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +// --- index prefixes ---- + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +// --- controls ---- + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +void IAPDUHandler::OnHeader(const PrefixHeader& header, const ICollection>& values) +{ + Record(header, this->ProcessHeader(header, values)); +} + +IINField IAPDUHandler::ProcessHeader(const AllObjectsHeader& record) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var7& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var8& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var9& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var10& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var11& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var12& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var13& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var14& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const FreeFormatHeader& header, const Group120Var15& value, const openpal::RSlice& object) +{ + return ProcessUnsupportedHeader(); +} + +/// ---- counts ----- + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection&) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection&) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection&) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection&) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection&) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const CountHeader& header, const ICollection&) +{ + return ProcessUnsupportedHeader(); +} + +/// ---- ranges ----- + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +/// ---- index prefixes ----- + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +//// --- controls ---- + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +IINField IAPDUHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return ProcessUnsupportedHeader(); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.h new file mode 100644 index 0000000..7519082 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IAPDUHandler.h @@ -0,0 +1,236 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IAPDUHANDLER_H +#define OPENDNP3_IAPDUHANDLER_H + +#include "opendnp3/app/parsing/IWhiteList.h" + +#include "opendnp3/app/GroupVariationRecord.h" +#include "opendnp3/app/parsing/ICollection.h" + +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/app/IINValue.h" +#include "opendnp3/app/ControlRelayOutputBlock.h" +#include "opendnp3/app/AnalogOutput.h" +#include "opendnp3/app/BinaryCommandEvent.h" +#include "opendnp3/app/AnalogCommandEvent.h" +#include "opendnp3/app/Indexed.h" +#include "opendnp3/app/OctetString.h" +#include "opendnp3/app/Range.h" + +#include "opendnp3/gen/QualifierCode.h" + +#include "opendnp3/objects/Group50.h" +#include "opendnp3/objects/Group51.h" +#include "opendnp3/objects/Group52.h" + +#include "opendnp3/objects/Group120.h" +#include "opendnp3/objects/Group121.h" +#include "opendnp3/objects/Group122.h" +#include "opendnp3/app/IINField.h" + +namespace opendnp3 +{ + +/** + * Base class used to handle APDU object headers + */ +class IAPDUHandler : public IWhiteList +{ +public: + + IAPDUHandler(); + + // read any accumulated errors + IINField Errors() const; + + void OnHeader(const AllObjectsHeader& header); + void OnHeader(const RangeHeader& header); + void OnHeader(const CountHeader& header); + + void OnHeader(const FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var7& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var8& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var9& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var10& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var11& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var12& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var13& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var14& value, const openpal::RSlice& object); + void OnHeader(const FreeFormatHeader& header, const Group120Var15& value, const openpal::RSlice& object); + + void OnHeader(const CountHeader& header, const ICollection& values); + void OnHeader(const CountHeader& header, const ICollection& values); + void OnHeader(const CountHeader& header, const ICollection& values); + void OnHeader(const CountHeader& header, const ICollection& values); + void OnHeader(const CountHeader& header, const ICollection& values); + void OnHeader(const CountHeader& header, const ICollection& values); + void OnHeader(const CountHeader& header, const ICollection& values); + + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values) ; + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + void OnHeader(const RangeHeader& header, const ICollection>& values); + + // events + + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + + // commands + + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + void OnHeader(const PrefixHeader& header, const ICollection>& values); + +protected: + + void Reset(); + + uint32_t NumIgnoredHeaders() const + { + return numIgnoredHeaders; + } + + inline uint32_t GetCurrentHeader() + { + return numTotalHeaders; + } + + inline bool IsFirstHeader() + { + return numTotalHeaders == 0; + } + + + virtual IINField ProcessHeader(const AllObjectsHeader& record); + virtual IINField ProcessHeader(const RangeHeader& header); + virtual IINField ProcessHeader(const CountHeader& header); + + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var8& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var7& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var9& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var10& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var11& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var12& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var13& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var14& value, const openpal::RSlice& object); + virtual IINField ProcessHeader(const FreeFormatHeader& header, const Group120Var15& value, const openpal::RSlice& object); + + + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values); + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values); + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values); + +protected: + + // overridable to receive post processing events for every header + virtual void OnHeaderResult(const HeaderRecord& record, const IINField& result) {} + +private: + + inline void Record(const HeaderRecord& record, const IINField& result) + { + errors |= result; + ++numTotalHeaders; + this->OnHeaderResult(record, result); + } + + inline IINField ProcessUnsupportedHeader() + { + ++numIgnoredHeaders; + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } + + IINField errors; + uint32_t numTotalHeaders; + uint32_t numIgnoredHeaders; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IWhiteList.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IWhiteList.h new file mode 100644 index 0000000..9d4ddd2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/IWhiteList.h @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IWHITELIST_H +#define OPENDNP3_IWHITELIST_H + +#include "opendnp3/gen/GroupVariation.h" +#include "opendnp3/gen/QualifierCode.h" + +namespace opendnp3 +{ + +/** + * Whitelist interface for APDU object headers + */ +class IWhiteList +{ +public: + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) = 0; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.cpp new file mode 100644 index 0000000..a5f1a14 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.cpp @@ -0,0 +1,125 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "NumParser.h" + +#include +#include + +#include "opendnp3/LogLevels.h" + +using namespace openpal; + +namespace opendnp3 +{ + +NumParser::NumParser(ReadFun pReadFun, uint8_t size) : + pReadFun(pReadFun), + size(size) +{ + +} + +uint8_t NumParser::NumBytes() const +{ + return size; +} + +ParseResult NumParser::ParseCount(openpal::RSlice& buffer, uint16_t& count, openpal::Logger* pLogger) const +{ + if (this->Read(count, buffer)) + { + if (count == 0) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "count of 0"); + return ParseResult::COUNT_OF_ZERO; + } + else + { + return ParseResult::OK; + } + } + else + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for count"); + return ParseResult::NOT_ENOUGH_DATA_FOR_RANGE; + } +} + +ParseResult NumParser::ParseRange(openpal::RSlice& buffer, Range& range, openpal::Logger* pLogger) const +{ + if (buffer.Size() < (2 * static_cast(size))) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for start / stop"); + return ParseResult::NOT_ENOUGH_DATA_FOR_RANGE; + } + else + { + range.start = this->ReadNum(buffer); + range.stop = this->ReadNum(buffer); + + if (range.IsValid()) + { + return ParseResult::OK; + } + else + { + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "start (%u) > stop (%u)", range.start, range.stop); + return ParseResult::BAD_START_STOP; + } + } +} + +uint16_t NumParser::ReadNum(openpal::RSlice& buffer) const +{ + return pReadFun(buffer); +} + +bool NumParser::Read(uint16_t& num, openpal::RSlice& buffer) const +{ + if (buffer.Size() < size) + { + return false; + } + else + { + num = pReadFun(buffer); + return true; + } +} + +uint16_t NumParser::ReadByte(openpal::RSlice& buffer) +{ + return UInt8::ReadBuffer(buffer); +} + +NumParser NumParser::OneByte() +{ + return NumParser(&ReadByte, 1); +} + +NumParser NumParser::TwoByte() +{ + return NumParser(&UInt16::ReadBuffer, 2); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.h new file mode 100644 index 0000000..eaccbd9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/NumParser.h @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_NUMPARSER_H +#define OPENDNP3_NUMPARSER_H + +#include +#include + +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/Range.h" + +namespace opendnp3 +{ + +// A one or two byte unsigned integer parser +class NumParser +{ + // a function that consumes bytes from a buffer and returns a uint16_t count + typedef uint16_t(*ReadFun)(openpal::RSlice& buffer); + +public: + + uint8_t NumBytes() const; + + ParseResult ParseCount(openpal::RSlice& buffer, uint16_t& count, openpal::Logger* pLogger) const; + ParseResult ParseRange(openpal::RSlice& buffer, Range& range, openpal::Logger* pLogger) const; + + uint16_t ReadNum(openpal::RSlice& buffer) const; + + static NumParser OneByte(); + static NumParser TwoByte(); + +private: + + // read the number, consuming from the buffer + // return true if there is enough bytes, false otherwise + bool Read(uint16_t& num, openpal::RSlice& buffer) const; + + static uint16_t ReadByte(openpal::RSlice& buffer); + + NumParser(ReadFun pReadFun, uint8_t size); + + ReadFun pReadFun; + uint8_t size; + + NumParser() = delete; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.cpp new file mode 100644 index 0000000..de50359 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.cpp @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ObjectHeaderParser.h" + +#include "opendnp3/LogLevels.h" +#include "opendnp3/app/GroupVariationRecord.h" + +#include +#include + +using namespace openpal; + +namespace opendnp3 +{ + +ObjectHeader::ObjectHeader() : group(0), variation(0), qualifier(0) +{} + +ParseResult ObjectHeaderParser::ParseObjectHeader(ObjectHeader& header, RSlice& buffer, Logger* pLogger) +{ + if (buffer.Size() < 3) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for header"); + return ParseResult::NOT_ENOUGH_DATA_FOR_HEADER; + } + else + { + header.group = UInt8::ReadBuffer(buffer); + header.variation = UInt8::ReadBuffer(buffer); + header.qualifier = UInt8::ReadBuffer(buffer); + return ParseResult::OK; + } +} + +bool ObjectHeaderParser::ReadFirstGroupVariation(const openpal::RSlice& objects, GroupVariation& gv) +{ + RSlice copy(objects); + ObjectHeader oheader; + if (ObjectHeaderParser::ParseObjectHeader(oheader, copy, nullptr) != ParseResult::OK) + { + return false; + } + + gv = GroupVariationRecord::GetRecord(oheader.group, oheader.variation).enumeration; + + return true; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.h new file mode 100644 index 0000000..cdd77f6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ObjectHeaderParser.h @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OBJECTHEADERPARSER_H +#define OPENDNP3_OBJECTHEADERPARSER_H + +#include + +#include "opendnp3/app/parsing/ParseResult.h" +#include +#include + +#include + +namespace opendnp3 +{ + +class ObjectHeader +{ +public: + ObjectHeader(); + + uint8_t group; + uint8_t variation; + uint8_t qualifier; +}; + +class ObjectHeaderParser : private openpal::StaticOnly +{ +public: + + static ParseResult ParseObjectHeader(ObjectHeader& header, openpal::RSlice& buffer, openpal::Logger* pLogger); + + // Provides stateless inspection of the first object header, provided that it exists + // return false on failure (e.g. < 3 bytes) + static bool ReadFirstGroupVariation(const openpal::RSlice& objects, GroupVariation& gv); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParseResult.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParseResult.h new file mode 100644 index 0000000..8321249 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParseResult.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_PARSERESULT_H +#define OPENDNP3_PARSERESULT_H + +#include + +namespace opendnp3 +{ + +enum class ParseResult : uint8_t +{ + OK, + NOT_ON_WHITELIST, + NOT_ENOUGH_DATA_FOR_HEADER, + NOT_ENOUGH_DATA_FOR_RANGE, + NOT_ENOUGH_DATA_FOR_OBJECTS, + UNREASONABLE_OBJECT_COUNT, + UNKNOWN_OBJECT, + UNKNOWN_QUALIFIER, + INVALID_OBJECT_QUALIFIER, + INVALID_OBJECT, + BAD_START_STOP, + COUNT_OF_ZERO +}; + +inline bool IsSuccess(ParseResult result) +{ + return result == ParseResult::OK; +} +inline bool IsFailure(ParseResult result) +{ + return result != ParseResult::OK; +} + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParserSettings.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParserSettings.h new file mode 100644 index 0000000..00b7f69 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/ParserSettings.h @@ -0,0 +1,71 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_PARSERSETTINGS_H +#define OPENDNP3_PARSERSETTINGS_H + +#include "opendnp3/LogLevels.h" + +namespace opendnp3 +{ + +class ParserSettings +{ +public: + + static ParserSettings NoContents(int32_t filters = flags::APP_OBJECT_RX) + { + return ParserSettings(false, filters); + } + + static ParserSettings Default(int32_t filters = flags::APP_OBJECT_RX) + { + return ParserSettings(true, filters); + } + + static ParserSettings Create(bool expectContents = true, int32_t filters = flags::APP_OBJECT_RX) + { + return ParserSettings(expectContents, filters); + } + + inline bool ExpectsContents() const + { + return expectContents; + } + + inline int32_t Filters() const + { + return logFilters; + } + +private: + + ParserSettings(bool expectContents_ = true, int32_t logFilters_ = flags::APP_OBJECT_RX) : + expectContents(expectContents_), + logFilters(logFilters_) + {} + + + const bool expectContents; + const int32_t logFilters; +}; +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/PrefixFields.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/PrefixFields.h new file mode 100644 index 0000000..20bfd5b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/PrefixFields.h @@ -0,0 +1,142 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_PREFIXFIELDS_H +#define OPENDNP3_PREFIXFIELDS_H + +#include +#include + +namespace opendnp3 +{ + +class PrefixFields : private openpal::StaticOnly +{ +public: + + template + static bool Read(openpal::RSlice& input, Args& ... fields) + { + if (input.Size() < (sizeof...(Args)*openpal::UInt16::SIZE)) + { + // not enough in the buffer to even read the length prefixes + return false; + } + + uint16_t lengths[sizeof...(Args)]; + + for (size_t i = 0; i < sizeof...(Args); ++i) + { + lengths[i] = openpal::UInt16::ReadBuffer(input); + } + + uint32_t sum = 0; + + for (size_t i = 0; i < sizeof...(Args); ++i) + { + sum += lengths[i]; + } + + if (input.Size() < sum) + { + // not enough for the defined fields + return false; + } + + ReadFields(input, lengths, fields...); + + return true; + } + + template + static bool Write(openpal::WSlice& dest, const Args& ... fields) + { + const uint32_t TOTAL_SIZE = (sizeof...(Args) * openpal::UInt16::SIZE) + SumSizes(fields...); + + if (dest.Size() < TOTAL_SIZE) + { + return false; + } + + WriteLengths(dest, fields...); + WriteFields(dest, fields...); + + return true; + } + + template + static bool LengthFitsInUInt16(const openpal::RSlice& arg1, Args& ... fields) + { + return (arg1.Size() <= openpal::MaxValue()) && LengthFitsInUInt16(fields...); + } + +private: + + template + static uint32_t SumSizes(const openpal::RSlice& arg1, Args& ... fields) + { + return arg1.Size() + SumSizes(fields...); + } + + static bool LengthFitsInUInt16() + { + return true; + } + + static uint32_t SumSizes() + { + return 0; + } + + template + static void ReadFields(openpal::RSlice& input, uint16_t* pLength, openpal::RSlice& output, Args& ... fields) + { + output = input.Take(*pLength); + input.Advance(*pLength); + ReadFields(input, ++pLength, fields...); + } + + static void ReadFields(openpal::RSlice& input, uint16_t* pLength) {} + + template + static void WriteLengths(openpal::WSlice& dest, const openpal::RSlice& arg1, Args& ... fields) + { + openpal::UInt16::WriteBuffer(dest, static_cast(arg1.Size())); + WriteLengths(dest, fields...); + } + + static void WriteLengths(openpal::WSlice& dest) {} + + template + static void WriteFields(openpal::WSlice& dest, const openpal::RSlice& arg1, Args& ... fields) + { + arg1.CopyTo(dest); + WriteFields(dest, fields...); + } + + static void WriteFields(openpal::WSlice& dest) {} + + +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.cpp new file mode 100644 index 0000000..ef93fe5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.cpp @@ -0,0 +1,204 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "RangeParser.h" + +#include "opendnp3/objects/Group1.h" +#include "opendnp3/objects/Group3.h" +#include "opendnp3/objects/Group10.h" +#include "opendnp3/objects/Group20.h" +#include "opendnp3/objects/Group21.h" +#include "opendnp3/objects/Group30.h" +#include "opendnp3/objects/Group40.h" +#include "opendnp3/objects/Group50.h" + +#include "opendnp3/app/parsing/BufferedCollection.h" + +#include + +namespace opendnp3 +{ + +RangeParser::RangeParser(const Range& range_, uint32_t requiredSize_, HandleFun handler_) : + range(range_), + requiredSize(requiredSize_), + handler(handler_) +{ + +} + +ParseResult RangeParser::ParseHeader(openpal::RSlice& buffer, const NumParser& numparser, const ParserSettings& settings, const HeaderRecord& record, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + Range range; + auto res = numparser.ParseRange(buffer, range, pLogger); + if (res != ParseResult::OK) + { + return res; + } + + FORMAT_LOGGER_BLOCK(pLogger, settings.Filters(), + "%03u,%03u %s, %s [%u, %u]", + record.group, + record.variation, + GroupVariationToString(record.enumeration), + QualifierCodeToString(record.GetQualifierCode()), + range.start, + range.stop); + + if (settings.ExpectsContents()) + { + return ParseRangeOfObjects(buffer, record, range, pLogger, pHandler); + } + else + { + if (pHandler) + { + pHandler->OnHeader(RangeHeader(record, range)); + } + return ParseResult::OK; + } +} + +ParseResult RangeParser::Process(const HeaderRecord& record, openpal::RSlice& buffer, IAPDUHandler* pHandler, openpal::Logger* pLogger) const +{ + if (buffer.Size() < requiredSize) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for specified objects"); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } + else + { + if (pHandler) + { + handler(record, range, buffer, *pHandler); + } + buffer.Advance(requiredSize); + return ParseResult::OK; + } +} + +#define MACRO_PARSE_OBJECTS_WITH_RANGE(descriptor) \ + case(GroupVariation::descriptor): \ + return RangeParser::FromFixedSize(range).Process(record, buffer, pHandler, pLogger); + +ParseResult RangeParser::ParseRangeOfObjects(openpal::RSlice& buffer, const HeaderRecord& record, const Range& range, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + switch (record.enumeration) + { + case(GroupVariation::Group1Var1) : + return RangeParser::FromBitfieldType(range).Process(record, buffer, pHandler, pLogger); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group1Var2); + + case(GroupVariation::Group3Var1) : + return RangeParser::FromDoubleBitfieldType(range).Process(record, buffer, pHandler, pLogger); + case(GroupVariation::Group10Var1): + return RangeParser::FromBitfieldType(range).Process(record, buffer, pHandler, pLogger); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group3Var2); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group10Var2); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group20Var1); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group20Var2); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group20Var5); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group20Var6); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group21Var1); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group21Var2); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group21Var5); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group21Var6); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group21Var9); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group21Var10); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group30Var1); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group30Var2); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group30Var3); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group30Var4); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group30Var5); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group30Var6); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group40Var1); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group40Var2); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group40Var3); + MACRO_PARSE_OBJECTS_WITH_RANGE(Group40Var4); + + MACRO_PARSE_OBJECTS_WITH_RANGE(Group50Var4); + + case(GroupVariation::Group80Var1) : + return RangeParser::FromBitfieldType(range).Process(record, buffer, pHandler, pLogger); + + case(GroupVariation::Group110Var0) : + return ParseRangeOfOctetData(buffer, record, range, pLogger, pHandler); + + case(GroupVariation::Group121Var1) : + return RangeParser::FromFixedSizeType(range).Process(record, buffer, pHandler, pLogger); + + default: + FORMAT_LOGGER_BLOCK(pLogger, flags::WARN, "Unsupported qualifier/object - %s - %i / %i", + QualifierCodeToString(record.GetQualifierCode()), + record.group, + record.variation); + + return ParseResult::INVALID_OBJECT_QUALIFIER; + } +} + +ParseResult RangeParser::ParseRangeOfOctetData(openpal::RSlice& buffer, const HeaderRecord& record, const Range& range, openpal::Logger* pLogger, IAPDUHandler* pHandler) +{ + if (record.variation > 0) + { + const auto COUNT = range.Count(); + uint32_t size = record.variation * COUNT; + if (buffer.Size() < size) + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Not enough data for specified octet objects"); + return ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS; + } + else + { + if (pHandler) + { + auto read = [range, record](openpal::RSlice & buffer, uint32_t pos) -> Indexed + { + OctetString octets(buffer.Take(record.variation)); + buffer.Advance(record.variation); + return WithIndex(octets, range.start + pos); + }; + + auto collection = CreateBufferedCollection>(buffer, COUNT, read); + + pHandler->OnHeader(RangeHeader(record, range), collection); + } + + buffer.Advance(size); + return ParseResult::OK; + } + } + else + { + SIMPLE_LOGGER_BLOCK(pLogger, flags::WARN, "Octet string variation 0 may only be used in requests"); + return ParseResult::INVALID_OBJECT; + } +} + + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.h new file mode 100644 index 0000000..be42e2a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/app/parsing/RangeParser.h @@ -0,0 +1,199 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_RANGEPARSER_H +#define OPENDNP3_RANGEPARSER_H + +#include +#include + +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/NumParser.h" +#include "opendnp3/app/parsing/ParserSettings.h" +#include "opendnp3/app/parsing/BitReader.h" + +#include "opendnp3/app/Range.h" +#include "opendnp3/app/parsing/BufferedCollection.h" + + +namespace opendnp3 +{ + +class RangeParser +{ + typedef void (*HandleFun)(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler); + + + +public: + + static ParseResult ParseHeader( + openpal::RSlice& buffer, + const NumParser& numparser, + const ParserSettings& settings, + const HeaderRecord& record, + openpal::Logger* pLogger, + IAPDUHandler* pHandler + ); + +private: + + // Process the range against the buffer + ParseResult Process(const HeaderRecord& record, openpal::RSlice& buffer, IAPDUHandler* pHandler, openpal::Logger* pLogger) const; + + // Create a range parser from a fixed size descriptor + template + static RangeParser FromFixedSize(const Range& range); + + template + static RangeParser FromFixedSizeType(const Range& range); + + // Create a range parser from a bitfield and a function to map the bitfield to values + template + static RangeParser FromBitfieldType(const Range& range); + + template + static RangeParser FromDoubleBitfieldType(const Range& range); + + static ParseResult ParseRangeOfObjects(openpal::RSlice& buffer, const HeaderRecord& record, const Range& range, openpal::Logger* pLogger, IAPDUHandler* pHandler); + + static ParseResult ParseRangeOfOctetData(openpal::RSlice& buffer, const HeaderRecord& record, const Range& range, openpal::Logger* pLogger, IAPDUHandler* pHandler); + + template + static void InvokeRangeOf(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler); + + template + static void InvokeRangeOfType(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler); + + template + static void InvokeRangeBitfieldType(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler); + + template + static void InvokeRangeDoubleBitfieldType(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler); + + RangeParser(const Range& range, uint32_t requiredSize, HandleFun handler); + + Range range; + uint32_t requiredSize; + HandleFun handler; + + RangeParser() = delete; +}; + +template +RangeParser RangeParser::FromFixedSize(const Range& range) +{ + uint32_t size = range.Count() * Descriptor::Size(); + return RangeParser(range, size, &InvokeRangeOf); +} + +template +RangeParser RangeParser::FromFixedSizeType(const Range& range) +{ + uint32_t size = range.Count() * Type::Size(); + return RangeParser(range, size, &InvokeRangeOfType); +} + +template +void RangeParser::InvokeRangeOf(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + const auto COUNT = range.Count(); + + auto read = [range](openpal::RSlice & buffer, uint32_t pos) + { + typename Descriptor::Target target; + Descriptor::ReadTarget(buffer, target); + return WithIndex(target, range.start + pos); + }; + + auto collection = CreateBufferedCollection>(buffer, COUNT, read); + + handler.OnHeader(RangeHeader(record, range), collection); +} + +template +void RangeParser::InvokeRangeOfType(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + const auto COUNT = range.Count(); + + auto read = [range](openpal::RSlice & buffer, uint32_t pos) -> Indexed + { + Type target; + Type::Read(buffer, target); + return WithIndex(target, range.start + pos); + }; + + auto collection = CreateBufferedCollection>(buffer, COUNT, read); + + handler.OnHeader(RangeHeader(record, range), collection); +} + + +template +RangeParser RangeParser::FromBitfieldType(const Range& range) +{ + const uint32_t SIZE = NumBytesInBits(range.Count()); + return RangeParser(range, SIZE, &InvokeRangeBitfieldType); +} + +template +void RangeParser::InvokeRangeBitfieldType(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + const uint32_t COUNT = range.Count(); + + auto read = [range](openpal::RSlice & buffer, uint32_t pos) -> Indexed + { + Type value(GetBit(buffer, pos)); + return WithIndex(value, range.start + pos); + }; + + auto collection = CreateBufferedCollection>(buffer, COUNT, read); + + handler.OnHeader(RangeHeader(record, range), collection); +} + +template +RangeParser RangeParser::FromDoubleBitfieldType(const Range& range) +{ + uint32_t size = NumBytesInDoubleBits(range.Count()); + return RangeParser(range, size, &InvokeRangeDoubleBitfieldType); +} + +template +void RangeParser::InvokeRangeDoubleBitfieldType(const HeaderRecord& record, const Range& range, const openpal::RSlice& buffer, IAPDUHandler& handler) +{ + const uint32_t COUNT = range.Count(); + + auto read = [range](openpal::RSlice & buffer, uint32_t pos) -> Indexed + { + Type value(GetDoubleBit(buffer, pos)); + return WithIndex(value, range.start + pos); + }; + + auto collection = CreateBufferedCollection>(buffer, COUNT, read); + + handler.OnHeader(RangeHeader(record, range), collection); +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/Attributes.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/Attributes.cpp new file mode 100644 index 0000000..292cb37 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/Attributes.cpp @@ -0,0 +1,316 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/Attributes.h" + +namespace opendnp3 { + +bool HasAbsoluteTime(GroupVariation gv) +{ + switch(gv) + { + case(GroupVariation::Group2Var2): + return true; + case(GroupVariation::Group4Var2): + return true; + case(GroupVariation::Group11Var2): + return true; + case(GroupVariation::Group13Var2): + return true; + case(GroupVariation::Group21Var5): + return true; + case(GroupVariation::Group21Var6): + return true; + case(GroupVariation::Group22Var5): + return true; + case(GroupVariation::Group22Var6): + return true; + case(GroupVariation::Group23Var5): + return true; + case(GroupVariation::Group23Var6): + return true; + case(GroupVariation::Group32Var3): + return true; + case(GroupVariation::Group32Var4): + return true; + case(GroupVariation::Group32Var7): + return true; + case(GroupVariation::Group32Var8): + return true; + case(GroupVariation::Group42Var3): + return true; + case(GroupVariation::Group42Var4): + return true; + case(GroupVariation::Group42Var7): + return true; + case(GroupVariation::Group42Var8): + return true; + case(GroupVariation::Group43Var3): + return true; + case(GroupVariation::Group43Var4): + return true; + case(GroupVariation::Group43Var7): + return true; + case(GroupVariation::Group43Var8): + return true; + case(GroupVariation::Group50Var1): + return true; + case(GroupVariation::Group50Var4): + return true; + case(GroupVariation::Group51Var1): + return true; + case(GroupVariation::Group51Var2): + return true; + case(GroupVariation::Group122Var2): + return true; + default: + return false; + } +} +bool HasRelativeTime(GroupVariation gv) +{ + switch(gv) + { + case(GroupVariation::Group2Var3): + return true; + case(GroupVariation::Group4Var3): + return true; + case(GroupVariation::Group52Var1): + return true; + case(GroupVariation::Group52Var2): + return true; + default: + return false; + } +} +bool HasFlags(GroupVariation gv) +{ + switch(gv) + { + case(GroupVariation::Group1Var2): + return true; + case(GroupVariation::Group2Var1): + return true; + case(GroupVariation::Group2Var2): + return true; + case(GroupVariation::Group2Var3): + return true; + case(GroupVariation::Group3Var2): + return true; + case(GroupVariation::Group4Var1): + return true; + case(GroupVariation::Group4Var2): + return true; + case(GroupVariation::Group4Var3): + return true; + case(GroupVariation::Group10Var2): + return true; + case(GroupVariation::Group11Var1): + return true; + case(GroupVariation::Group11Var2): + return true; + case(GroupVariation::Group13Var1): + return true; + case(GroupVariation::Group13Var2): + return true; + case(GroupVariation::Group20Var1): + return true; + case(GroupVariation::Group20Var2): + return true; + case(GroupVariation::Group21Var1): + return true; + case(GroupVariation::Group21Var2): + return true; + case(GroupVariation::Group21Var5): + return true; + case(GroupVariation::Group21Var6): + return true; + case(GroupVariation::Group22Var1): + return true; + case(GroupVariation::Group22Var2): + return true; + case(GroupVariation::Group22Var5): + return true; + case(GroupVariation::Group22Var6): + return true; + case(GroupVariation::Group23Var1): + return true; + case(GroupVariation::Group23Var2): + return true; + case(GroupVariation::Group23Var5): + return true; + case(GroupVariation::Group23Var6): + return true; + case(GroupVariation::Group30Var1): + return true; + case(GroupVariation::Group30Var2): + return true; + case(GroupVariation::Group30Var5): + return true; + case(GroupVariation::Group30Var6): + return true; + case(GroupVariation::Group32Var1): + return true; + case(GroupVariation::Group32Var2): + return true; + case(GroupVariation::Group32Var3): + return true; + case(GroupVariation::Group32Var4): + return true; + case(GroupVariation::Group32Var5): + return true; + case(GroupVariation::Group32Var6): + return true; + case(GroupVariation::Group32Var7): + return true; + case(GroupVariation::Group32Var8): + return true; + case(GroupVariation::Group40Var1): + return true; + case(GroupVariation::Group40Var2): + return true; + case(GroupVariation::Group40Var3): + return true; + case(GroupVariation::Group40Var4): + return true; + case(GroupVariation::Group42Var1): + return true; + case(GroupVariation::Group42Var2): + return true; + case(GroupVariation::Group42Var3): + return true; + case(GroupVariation::Group42Var4): + return true; + case(GroupVariation::Group42Var5): + return true; + case(GroupVariation::Group42Var6): + return true; + case(GroupVariation::Group42Var7): + return true; + case(GroupVariation::Group42Var8): + return true; + case(GroupVariation::Group121Var1): + return true; + case(GroupVariation::Group122Var1): + return true; + case(GroupVariation::Group122Var2): + return true; + default: + return false; + } +} +bool IsEvent(GroupVariation gv) +{ + switch(gv) + { + case(GroupVariation::Group2Var1): + return true; + case(GroupVariation::Group2Var2): + return true; + case(GroupVariation::Group2Var3): + return true; + case(GroupVariation::Group4Var1): + return true; + case(GroupVariation::Group4Var2): + return true; + case(GroupVariation::Group4Var3): + return true; + case(GroupVariation::Group11Var1): + return true; + case(GroupVariation::Group11Var2): + return true; + case(GroupVariation::Group13Var1): + return true; + case(GroupVariation::Group13Var2): + return true; + case(GroupVariation::Group22Var1): + return true; + case(GroupVariation::Group22Var2): + return true; + case(GroupVariation::Group22Var5): + return true; + case(GroupVariation::Group22Var6): + return true; + case(GroupVariation::Group23Var1): + return true; + case(GroupVariation::Group23Var2): + return true; + case(GroupVariation::Group23Var5): + return true; + case(GroupVariation::Group23Var6): + return true; + case(GroupVariation::Group32Var1): + return true; + case(GroupVariation::Group32Var2): + return true; + case(GroupVariation::Group32Var3): + return true; + case(GroupVariation::Group32Var4): + return true; + case(GroupVariation::Group32Var5): + return true; + case(GroupVariation::Group32Var6): + return true; + case(GroupVariation::Group32Var7): + return true; + case(GroupVariation::Group32Var8): + return true; + case(GroupVariation::Group42Var1): + return true; + case(GroupVariation::Group42Var2): + return true; + case(GroupVariation::Group42Var3): + return true; + case(GroupVariation::Group42Var4): + return true; + case(GroupVariation::Group42Var5): + return true; + case(GroupVariation::Group42Var6): + return true; + case(GroupVariation::Group42Var7): + return true; + case(GroupVariation::Group42Var8): + return true; + case(GroupVariation::Group43Var1): + return true; + case(GroupVariation::Group43Var2): + return true; + case(GroupVariation::Group43Var3): + return true; + case(GroupVariation::Group43Var4): + return true; + case(GroupVariation::Group43Var5): + return true; + case(GroupVariation::Group43Var6): + return true; + case(GroupVariation::Group43Var7): + return true; + case(GroupVariation::Group43Var8): + return true; + case(GroupVariation::Group122Var1): + return true; + case(GroupVariation::Group122Var2): + return true; + default: + return false; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/AuthErrorCode.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/AuthErrorCode.cpp new file mode 100644 index 0000000..1ccc7e2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/AuthErrorCode.cpp @@ -0,0 +1,86 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/AuthErrorCode.h" + +namespace opendnp3 { + +uint8_t AuthErrorCodeToType(AuthErrorCode arg) +{ + return static_cast(arg); +} +AuthErrorCode AuthErrorCodeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return AuthErrorCode::AUTHENTICATION_FAILED; + case(0x4): + return AuthErrorCode::AGGRESSIVE_MODE_UNSUPPORTED; + case(0x5): + return AuthErrorCode::MAC_NOT_SUPPORTED; + case(0x6): + return AuthErrorCode::KEY_WRAP_NOT_SUPPORTED; + case(0x7): + return AuthErrorCode::AUTHORIZATION_FAILED; + case(0x8): + return AuthErrorCode::UPDATE_KEY_METHOD_NOT_PERMITTED; + case(0x9): + return AuthErrorCode::INVALID_SIGNATURE; + case(0xA): + return AuthErrorCode::INVALID_CERTIFICATION_DATA; + case(0xB): + return AuthErrorCode::UNKNOWN_USER; + case(0xC): + return AuthErrorCode::MAX_SESSION_KEY_STATUS_REQUESTS_EXCEEDED; + default: + return AuthErrorCode::UNKNOWN; + } +} +char const* AuthErrorCodeToString(AuthErrorCode arg) +{ + switch(arg) + { + case(AuthErrorCode::AUTHENTICATION_FAILED): + return "AUTHENTICATION_FAILED"; + case(AuthErrorCode::AGGRESSIVE_MODE_UNSUPPORTED): + return "AGGRESSIVE_MODE_UNSUPPORTED"; + case(AuthErrorCode::MAC_NOT_SUPPORTED): + return "MAC_NOT_SUPPORTED"; + case(AuthErrorCode::KEY_WRAP_NOT_SUPPORTED): + return "KEY_WRAP_NOT_SUPPORTED"; + case(AuthErrorCode::AUTHORIZATION_FAILED): + return "AUTHORIZATION_FAILED"; + case(AuthErrorCode::UPDATE_KEY_METHOD_NOT_PERMITTED): + return "UPDATE_KEY_METHOD_NOT_PERMITTED"; + case(AuthErrorCode::INVALID_SIGNATURE): + return "INVALID_SIGNATURE"; + case(AuthErrorCode::INVALID_CERTIFICATION_DATA): + return "INVALID_CERTIFICATION_DATA"; + case(AuthErrorCode::UNKNOWN_USER): + return "UNKNOWN_USER"; + case(AuthErrorCode::MAX_SESSION_KEY_STATUS_REQUESTS_EXCEEDED): + return "MAX_SESSION_KEY_STATUS_REQUESTS_EXCEEDED"; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CertificateType.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CertificateType.cpp new file mode 100644 index 0000000..89c787d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CertificateType.cpp @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/CertificateType.h" + +namespace opendnp3 { + +uint8_t CertificateTypeToType(CertificateType arg) +{ + return static_cast(arg); +} +CertificateType CertificateTypeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return CertificateType::ID_CERTIFICATE; + case(0x2): + return CertificateType::ATTRIBUTE_CERTIFICATE; + default: + return CertificateType::UNKNOWN; + } +} +char const* CertificateTypeToString(CertificateType arg) +{ + switch(arg) + { + case(CertificateType::ID_CERTIFICATE): + return "ID_CERTIFICATE"; + case(CertificateType::ATTRIBUTE_CERTIFICATE): + return "ATTRIBUTE_CERTIFICATE"; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChallengeReason.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChallengeReason.cpp new file mode 100644 index 0000000..edb8529 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChallengeReason.cpp @@ -0,0 +1,50 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/ChallengeReason.h" + +namespace opendnp3 { + +uint8_t ChallengeReasonToType(ChallengeReason arg) +{ + return static_cast(arg); +} +ChallengeReason ChallengeReasonFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return ChallengeReason::CRITICAL; + default: + return ChallengeReason::UNKNOWN; + } +} +char const* ChallengeReasonToString(ChallengeReason arg) +{ + switch(arg) + { + case(ChallengeReason::CRITICAL): + return "CRITICAL"; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChannelState.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChannelState.cpp new file mode 100644 index 0000000..765b2d5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ChannelState.cpp @@ -0,0 +1,40 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/ChannelState.h" + +namespace opendnp3 { + +char const* ChannelStateToString(ChannelState arg) +{ + switch(arg) + { + case(ChannelState::CLOSED): + return "CLOSED"; + case(ChannelState::OPENING): + return "OPENING"; + case(ChannelState::OPEN): + return "OPEN"; + default: + return "SHUTDOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandPointState.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandPointState.cpp new file mode 100644 index 0000000..ac1f863 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandPointState.cpp @@ -0,0 +1,46 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/CommandPointState.h" + +namespace opendnp3 { + +char const* CommandPointStateToString(CommandPointState arg) +{ + switch(arg) + { + case(CommandPointState::INIT): + return "INIT"; + case(CommandPointState::SELECT_SUCCESS): + return "SELECT_SUCCESS"; + case(CommandPointState::SELECT_MISMATCH): + return "SELECT_MISMATCH"; + case(CommandPointState::SELECT_FAIL): + return "SELECT_FAIL"; + case(CommandPointState::OPERATE_FAIL): + return "OPERATE_FAIL"; + case(CommandPointState::SUCCESS): + return "SUCCESS"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandStatus.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandStatus.cpp new file mode 100644 index 0000000..2f014fc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/CommandStatus.cpp @@ -0,0 +1,126 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/CommandStatus.h" + +namespace opendnp3 { + +uint8_t CommandStatusToType(CommandStatus arg) +{ + return static_cast(arg); +} +CommandStatus CommandStatusFromType(uint8_t arg) +{ + switch(arg) + { + case(0): + return CommandStatus::SUCCESS; + case(1): + return CommandStatus::TIMEOUT; + case(2): + return CommandStatus::NO_SELECT; + case(3): + return CommandStatus::FORMAT_ERROR; + case(4): + return CommandStatus::NOT_SUPPORTED; + case(5): + return CommandStatus::ALREADY_ACTIVE; + case(6): + return CommandStatus::HARDWARE_ERROR; + case(7): + return CommandStatus::LOCAL; + case(8): + return CommandStatus::TOO_MANY_OPS; + case(9): + return CommandStatus::NOT_AUTHORIZED; + case(10): + return CommandStatus::AUTOMATION_INHIBIT; + case(11): + return CommandStatus::PROCESSING_LIMITED; + case(12): + return CommandStatus::OUT_OF_RANGE; + case(13): + return CommandStatus::DOWNSTREAM_LOCAL; + case(14): + return CommandStatus::ALREADY_COMPLETE; + case(15): + return CommandStatus::BLOCKED; + case(16): + return CommandStatus::CANCELLED; + case(17): + return CommandStatus::BLOCKED_OTHER_MASTER; + case(18): + return CommandStatus::DOWNSTREAM_FAIL; + case(126): + return CommandStatus::NON_PARTICIPATING; + default: + return CommandStatus::UNDEFINED; + } +} +char const* CommandStatusToString(CommandStatus arg) +{ + switch(arg) + { + case(CommandStatus::SUCCESS): + return "SUCCESS"; + case(CommandStatus::TIMEOUT): + return "TIMEOUT"; + case(CommandStatus::NO_SELECT): + return "NO_SELECT"; + case(CommandStatus::FORMAT_ERROR): + return "FORMAT_ERROR"; + case(CommandStatus::NOT_SUPPORTED): + return "NOT_SUPPORTED"; + case(CommandStatus::ALREADY_ACTIVE): + return "ALREADY_ACTIVE"; + case(CommandStatus::HARDWARE_ERROR): + return "HARDWARE_ERROR"; + case(CommandStatus::LOCAL): + return "LOCAL"; + case(CommandStatus::TOO_MANY_OPS): + return "TOO_MANY_OPS"; + case(CommandStatus::NOT_AUTHORIZED): + return "NOT_AUTHORIZED"; + case(CommandStatus::AUTOMATION_INHIBIT): + return "AUTOMATION_INHIBIT"; + case(CommandStatus::PROCESSING_LIMITED): + return "PROCESSING_LIMITED"; + case(CommandStatus::OUT_OF_RANGE): + return "OUT_OF_RANGE"; + case(CommandStatus::DOWNSTREAM_LOCAL): + return "DOWNSTREAM_LOCAL"; + case(CommandStatus::ALREADY_COMPLETE): + return "ALREADY_COMPLETE"; + case(CommandStatus::BLOCKED): + return "BLOCKED"; + case(CommandStatus::CANCELLED): + return "CANCELLED"; + case(CommandStatus::BLOCKED_OTHER_MASTER): + return "BLOCKED_OTHER_MASTER"; + case(CommandStatus::DOWNSTREAM_FAIL): + return "DOWNSTREAM_FAIL"; + case(CommandStatus::NON_PARTICIPATING): + return "NON_PARTICIPATING"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ControlCode.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ControlCode.cpp new file mode 100644 index 0000000..4ac279f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/ControlCode.cpp @@ -0,0 +1,102 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/ControlCode.h" + +namespace opendnp3 { + +uint8_t ControlCodeToType(ControlCode arg) +{ + return static_cast(arg); +} +ControlCode ControlCodeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x0): + return ControlCode::NUL; + case(0x20): + return ControlCode::NUL_CANCEL; + case(0x1): + return ControlCode::PULSE_ON; + case(0x21): + return ControlCode::PULSE_ON_CANCEL; + case(0x2): + return ControlCode::PULSE_OFF; + case(0x22): + return ControlCode::PULSE_OFF_CANCEL; + case(0x3): + return ControlCode::LATCH_ON; + case(0x23): + return ControlCode::LATCH_ON_CANCEL; + case(0x4): + return ControlCode::LATCH_OFF; + case(0x24): + return ControlCode::LATCH_OFF_CANCEL; + case(0x41): + return ControlCode::CLOSE_PULSE_ON; + case(0x61): + return ControlCode::CLOSE_PULSE_ON_CANCEL; + case(0x81): + return ControlCode::TRIP_PULSE_ON; + case(0xA1): + return ControlCode::TRIP_PULSE_ON_CANCEL; + default: + return ControlCode::UNDEFINED; + } +} +char const* ControlCodeToString(ControlCode arg) +{ + switch(arg) + { + case(ControlCode::NUL): + return "NUL"; + case(ControlCode::NUL_CANCEL): + return "NUL_CANCEL"; + case(ControlCode::PULSE_ON): + return "PULSE_ON"; + case(ControlCode::PULSE_ON_CANCEL): + return "PULSE_ON_CANCEL"; + case(ControlCode::PULSE_OFF): + return "PULSE_OFF"; + case(ControlCode::PULSE_OFF_CANCEL): + return "PULSE_OFF_CANCEL"; + case(ControlCode::LATCH_ON): + return "LATCH_ON"; + case(ControlCode::LATCH_ON_CANCEL): + return "LATCH_ON_CANCEL"; + case(ControlCode::LATCH_OFF): + return "LATCH_OFF"; + case(ControlCode::LATCH_OFF_CANCEL): + return "LATCH_OFF_CANCEL"; + case(ControlCode::CLOSE_PULSE_ON): + return "CLOSE_PULSE_ON"; + case(ControlCode::CLOSE_PULSE_ON_CANCEL): + return "CLOSE_PULSE_ON_CANCEL"; + case(ControlCode::TRIP_PULSE_ON): + return "TRIP_PULSE_ON"; + case(ControlCode::TRIP_PULSE_ON_CANCEL): + return "TRIP_PULSE_ON_CANCEL"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/DoubleBit.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/DoubleBit.cpp new file mode 100644 index 0000000..57f26df --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/DoubleBit.cpp @@ -0,0 +1,58 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/DoubleBit.h" + +namespace opendnp3 { + +uint8_t DoubleBitToType(DoubleBit arg) +{ + return static_cast(arg); +} +DoubleBit DoubleBitFromType(uint8_t arg) +{ + switch(arg) + { + case(0x0): + return DoubleBit::INTERMEDIATE; + case(0x1): + return DoubleBit::DETERMINED_OFF; + case(0x2): + return DoubleBit::DETERMINED_ON; + default: + return DoubleBit::INDETERMINATE; + } +} +char const* DoubleBitToString(DoubleBit arg) +{ + switch(arg) + { + case(DoubleBit::INTERMEDIATE): + return "INTERMEDIATE"; + case(DoubleBit::DETERMINED_OFF): + return "DETERMINED_OFF"; + case(DoubleBit::DETERMINED_ON): + return "DETERMINED_ON"; + default: + return "INDETERMINATE"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlagsType.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlagsType.cpp new file mode 100644 index 0000000..82d4445 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlagsType.cpp @@ -0,0 +1,70 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/FlagsType.h" + +namespace opendnp3 { + +uint8_t FlagsTypeToType(FlagsType arg) +{ + return static_cast(arg); +} +FlagsType FlagsTypeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return FlagsType::DoubleBinaryInput; + case(0x2): + return FlagsType::Counter; + case(0x3): + return FlagsType::FrozenCounter; + case(0x4): + return FlagsType::AnalogInput; + case(0x5): + return FlagsType::BinaryOutputStatus; + case(0x6): + return FlagsType::AnalogOutputStatus; + default: + return FlagsType::BinaryInput; + } +} +char const* FlagsTypeToString(FlagsType arg) +{ + switch(arg) + { + case(FlagsType::DoubleBinaryInput): + return "DoubleBinaryInput"; + case(FlagsType::Counter): + return "Counter"; + case(FlagsType::FrozenCounter): + return "FrozenCounter"; + case(FlagsType::AnalogInput): + return "AnalogInput"; + case(FlagsType::BinaryOutputStatus): + return "BinaryOutputStatus"; + case(FlagsType::AnalogOutputStatus): + return "AnalogOutputStatus"; + default: + return "BinaryInput"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlowControl.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlowControl.cpp new file mode 100644 index 0000000..3427a2f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FlowControl.cpp @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/FlowControl.h" + +namespace opendnp3 { + +uint8_t FlowControlToType(FlowControl arg) +{ + return static_cast(arg); +} +FlowControl FlowControlFromType(uint8_t arg) +{ + switch(arg) + { + case(1): + return FlowControl::Hardware; + case(2): + return FlowControl::XONXOFF; + default: + return FlowControl::None; + } +} +char const* FlowControlToString(FlowControl arg) +{ + switch(arg) + { + case(FlowControl::Hardware): + return "Hardware"; + case(FlowControl::XONXOFF): + return "XONXOFF"; + default: + return "None"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FunctionCode.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FunctionCode.cpp new file mode 100644 index 0000000..a88ad84 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/FunctionCode.cpp @@ -0,0 +1,190 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/FunctionCode.h" + +namespace opendnp3 { + +uint8_t FunctionCodeToType(FunctionCode arg) +{ + return static_cast(arg); +} +FunctionCode FunctionCodeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x0): + return FunctionCode::CONFIRM; + case(0x1): + return FunctionCode::READ; + case(0x2): + return FunctionCode::WRITE; + case(0x3): + return FunctionCode::SELECT; + case(0x4): + return FunctionCode::OPERATE; + case(0x5): + return FunctionCode::DIRECT_OPERATE; + case(0x6): + return FunctionCode::DIRECT_OPERATE_NR; + case(0x7): + return FunctionCode::IMMED_FREEZE; + case(0x8): + return FunctionCode::IMMED_FREEZE_NR; + case(0x9): + return FunctionCode::FREEZE_CLEAR; + case(0xA): + return FunctionCode::FREEZE_CLEAR_NR; + case(0xB): + return FunctionCode::FREEZE_AT_TIME; + case(0xC): + return FunctionCode::FREEZE_AT_TIME_NR; + case(0xD): + return FunctionCode::COLD_RESTART; + case(0xE): + return FunctionCode::WARM_RESTART; + case(0xF): + return FunctionCode::INITIALIZE_DATA; + case(0x10): + return FunctionCode::INITIALIZE_APPLICATION; + case(0x11): + return FunctionCode::START_APPLICATION; + case(0x12): + return FunctionCode::STOP_APPLICATION; + case(0x13): + return FunctionCode::SAVE_CONFIGURATION; + case(0x14): + return FunctionCode::ENABLE_UNSOLICITED; + case(0x15): + return FunctionCode::DISABLE_UNSOLICITED; + case(0x16): + return FunctionCode::ASSIGN_CLASS; + case(0x17): + return FunctionCode::DELAY_MEASURE; + case(0x18): + return FunctionCode::RECORD_CURRENT_TIME; + case(0x19): + return FunctionCode::OPEN_FILE; + case(0x1A): + return FunctionCode::CLOSE_FILE; + case(0x1B): + return FunctionCode::DELETE_FILE; + case(0x1C): + return FunctionCode::GET_FILE_INFO; + case(0x1D): + return FunctionCode::AUTHENTICATE_FILE; + case(0x1E): + return FunctionCode::ABORT_FILE; + case(0x20): + return FunctionCode::AUTH_REQUEST; + case(0x21): + return FunctionCode::AUTH_REQUEST_NO_ACK; + case(0x81): + return FunctionCode::RESPONSE; + case(0x82): + return FunctionCode::UNSOLICITED_RESPONSE; + case(0x83): + return FunctionCode::AUTH_RESPONSE; + default: + return FunctionCode::UNKNOWN; + } +} +char const* FunctionCodeToString(FunctionCode arg) +{ + switch(arg) + { + case(FunctionCode::CONFIRM): + return "CONFIRM"; + case(FunctionCode::READ): + return "READ"; + case(FunctionCode::WRITE): + return "WRITE"; + case(FunctionCode::SELECT): + return "SELECT"; + case(FunctionCode::OPERATE): + return "OPERATE"; + case(FunctionCode::DIRECT_OPERATE): + return "DIRECT_OPERATE"; + case(FunctionCode::DIRECT_OPERATE_NR): + return "DIRECT_OPERATE_NR"; + case(FunctionCode::IMMED_FREEZE): + return "IMMED_FREEZE"; + case(FunctionCode::IMMED_FREEZE_NR): + return "IMMED_FREEZE_NR"; + case(FunctionCode::FREEZE_CLEAR): + return "FREEZE_CLEAR"; + case(FunctionCode::FREEZE_CLEAR_NR): + return "FREEZE_CLEAR_NR"; + case(FunctionCode::FREEZE_AT_TIME): + return "FREEZE_AT_TIME"; + case(FunctionCode::FREEZE_AT_TIME_NR): + return "FREEZE_AT_TIME_NR"; + case(FunctionCode::COLD_RESTART): + return "COLD_RESTART"; + case(FunctionCode::WARM_RESTART): + return "WARM_RESTART"; + case(FunctionCode::INITIALIZE_DATA): + return "INITIALIZE_DATA"; + case(FunctionCode::INITIALIZE_APPLICATION): + return "INITIALIZE_APPLICATION"; + case(FunctionCode::START_APPLICATION): + return "START_APPLICATION"; + case(FunctionCode::STOP_APPLICATION): + return "STOP_APPLICATION"; + case(FunctionCode::SAVE_CONFIGURATION): + return "SAVE_CONFIGURATION"; + case(FunctionCode::ENABLE_UNSOLICITED): + return "ENABLE_UNSOLICITED"; + case(FunctionCode::DISABLE_UNSOLICITED): + return "DISABLE_UNSOLICITED"; + case(FunctionCode::ASSIGN_CLASS): + return "ASSIGN_CLASS"; + case(FunctionCode::DELAY_MEASURE): + return "DELAY_MEASURE"; + case(FunctionCode::RECORD_CURRENT_TIME): + return "RECORD_CURRENT_TIME"; + case(FunctionCode::OPEN_FILE): + return "OPEN_FILE"; + case(FunctionCode::CLOSE_FILE): + return "CLOSE_FILE"; + case(FunctionCode::DELETE_FILE): + return "DELETE_FILE"; + case(FunctionCode::GET_FILE_INFO): + return "GET_FILE_INFO"; + case(FunctionCode::AUTHENTICATE_FILE): + return "AUTHENTICATE_FILE"; + case(FunctionCode::ABORT_FILE): + return "ABORT_FILE"; + case(FunctionCode::AUTH_REQUEST): + return "AUTH_REQUEST"; + case(FunctionCode::AUTH_REQUEST_NO_ACK): + return "AUTH_REQUEST_NO_ACK"; + case(FunctionCode::RESPONSE): + return "RESPONSE"; + case(FunctionCode::UNSOLICITED_RESPONSE): + return "UNSOLICITED_RESPONSE"; + case(FunctionCode::AUTH_RESPONSE): + return "AUTH_RESPONSE"; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/GroupVariation.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/GroupVariation.cpp new file mode 100644 index 0000000..3855587 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/GroupVariation.cpp @@ -0,0 +1,574 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/GroupVariation.h" + +namespace opendnp3 { + +uint16_t GroupVariationToType(GroupVariation arg) +{ + return static_cast(arg); +} +GroupVariation GroupVariationFromType(uint16_t arg) +{ + switch(arg) + { + case(0x100): + return GroupVariation::Group1Var0; + case(0x101): + return GroupVariation::Group1Var1; + case(0x102): + return GroupVariation::Group1Var2; + case(0x200): + return GroupVariation::Group2Var0; + case(0x201): + return GroupVariation::Group2Var1; + case(0x202): + return GroupVariation::Group2Var2; + case(0x203): + return GroupVariation::Group2Var3; + case(0x300): + return GroupVariation::Group3Var0; + case(0x301): + return GroupVariation::Group3Var1; + case(0x302): + return GroupVariation::Group3Var2; + case(0x400): + return GroupVariation::Group4Var0; + case(0x401): + return GroupVariation::Group4Var1; + case(0x402): + return GroupVariation::Group4Var2; + case(0x403): + return GroupVariation::Group4Var3; + case(0xA00): + return GroupVariation::Group10Var0; + case(0xA01): + return GroupVariation::Group10Var1; + case(0xA02): + return GroupVariation::Group10Var2; + case(0xB00): + return GroupVariation::Group11Var0; + case(0xB01): + return GroupVariation::Group11Var1; + case(0xB02): + return GroupVariation::Group11Var2; + case(0xC00): + return GroupVariation::Group12Var0; + case(0xC01): + return GroupVariation::Group12Var1; + case(0xD01): + return GroupVariation::Group13Var1; + case(0xD02): + return GroupVariation::Group13Var2; + case(0x1400): + return GroupVariation::Group20Var0; + case(0x1401): + return GroupVariation::Group20Var1; + case(0x1402): + return GroupVariation::Group20Var2; + case(0x1405): + return GroupVariation::Group20Var5; + case(0x1406): + return GroupVariation::Group20Var6; + case(0x1500): + return GroupVariation::Group21Var0; + case(0x1501): + return GroupVariation::Group21Var1; + case(0x1502): + return GroupVariation::Group21Var2; + case(0x1505): + return GroupVariation::Group21Var5; + case(0x1506): + return GroupVariation::Group21Var6; + case(0x1509): + return GroupVariation::Group21Var9; + case(0x150A): + return GroupVariation::Group21Var10; + case(0x1600): + return GroupVariation::Group22Var0; + case(0x1601): + return GroupVariation::Group22Var1; + case(0x1602): + return GroupVariation::Group22Var2; + case(0x1605): + return GroupVariation::Group22Var5; + case(0x1606): + return GroupVariation::Group22Var6; + case(0x1700): + return GroupVariation::Group23Var0; + case(0x1701): + return GroupVariation::Group23Var1; + case(0x1702): + return GroupVariation::Group23Var2; + case(0x1705): + return GroupVariation::Group23Var5; + case(0x1706): + return GroupVariation::Group23Var6; + case(0x1E00): + return GroupVariation::Group30Var0; + case(0x1E01): + return GroupVariation::Group30Var1; + case(0x1E02): + return GroupVariation::Group30Var2; + case(0x1E03): + return GroupVariation::Group30Var3; + case(0x1E04): + return GroupVariation::Group30Var4; + case(0x1E05): + return GroupVariation::Group30Var5; + case(0x1E06): + return GroupVariation::Group30Var6; + case(0x2000): + return GroupVariation::Group32Var0; + case(0x2001): + return GroupVariation::Group32Var1; + case(0x2002): + return GroupVariation::Group32Var2; + case(0x2003): + return GroupVariation::Group32Var3; + case(0x2004): + return GroupVariation::Group32Var4; + case(0x2005): + return GroupVariation::Group32Var5; + case(0x2006): + return GroupVariation::Group32Var6; + case(0x2007): + return GroupVariation::Group32Var7; + case(0x2008): + return GroupVariation::Group32Var8; + case(0x2800): + return GroupVariation::Group40Var0; + case(0x2801): + return GroupVariation::Group40Var1; + case(0x2802): + return GroupVariation::Group40Var2; + case(0x2803): + return GroupVariation::Group40Var3; + case(0x2804): + return GroupVariation::Group40Var4; + case(0x2900): + return GroupVariation::Group41Var0; + case(0x2901): + return GroupVariation::Group41Var1; + case(0x2902): + return GroupVariation::Group41Var2; + case(0x2903): + return GroupVariation::Group41Var3; + case(0x2904): + return GroupVariation::Group41Var4; + case(0x2A00): + return GroupVariation::Group42Var0; + case(0x2A01): + return GroupVariation::Group42Var1; + case(0x2A02): + return GroupVariation::Group42Var2; + case(0x2A03): + return GroupVariation::Group42Var3; + case(0x2A04): + return GroupVariation::Group42Var4; + case(0x2A05): + return GroupVariation::Group42Var5; + case(0x2A06): + return GroupVariation::Group42Var6; + case(0x2A07): + return GroupVariation::Group42Var7; + case(0x2A08): + return GroupVariation::Group42Var8; + case(0x2B01): + return GroupVariation::Group43Var1; + case(0x2B02): + return GroupVariation::Group43Var2; + case(0x2B03): + return GroupVariation::Group43Var3; + case(0x2B04): + return GroupVariation::Group43Var4; + case(0x2B05): + return GroupVariation::Group43Var5; + case(0x2B06): + return GroupVariation::Group43Var6; + case(0x2B07): + return GroupVariation::Group43Var7; + case(0x2B08): + return GroupVariation::Group43Var8; + case(0x3201): + return GroupVariation::Group50Var1; + case(0x3204): + return GroupVariation::Group50Var4; + case(0x3301): + return GroupVariation::Group51Var1; + case(0x3302): + return GroupVariation::Group51Var2; + case(0x3401): + return GroupVariation::Group52Var1; + case(0x3402): + return GroupVariation::Group52Var2; + case(0x3C01): + return GroupVariation::Group60Var1; + case(0x3C02): + return GroupVariation::Group60Var2; + case(0x3C03): + return GroupVariation::Group60Var3; + case(0x3C04): + return GroupVariation::Group60Var4; + case(0x4601): + return GroupVariation::Group70Var1; + case(0x4602): + return GroupVariation::Group70Var2; + case(0x4603): + return GroupVariation::Group70Var3; + case(0x4604): + return GroupVariation::Group70Var4; + case(0x4605): + return GroupVariation::Group70Var5; + case(0x4606): + return GroupVariation::Group70Var6; + case(0x4607): + return GroupVariation::Group70Var7; + case(0x4608): + return GroupVariation::Group70Var8; + case(0x5001): + return GroupVariation::Group80Var1; + case(0x6E00): + return GroupVariation::Group110Var0; + case(0x6F00): + return GroupVariation::Group111Var0; + case(0x7000): + return GroupVariation::Group112Var0; + case(0x7100): + return GroupVariation::Group113Var0; + case(0x7801): + return GroupVariation::Group120Var1; + case(0x7802): + return GroupVariation::Group120Var2; + case(0x7803): + return GroupVariation::Group120Var3; + case(0x7804): + return GroupVariation::Group120Var4; + case(0x7805): + return GroupVariation::Group120Var5; + case(0x7806): + return GroupVariation::Group120Var6; + case(0x7807): + return GroupVariation::Group120Var7; + case(0x7808): + return GroupVariation::Group120Var8; + case(0x7809): + return GroupVariation::Group120Var9; + case(0x780A): + return GroupVariation::Group120Var10; + case(0x780B): + return GroupVariation::Group120Var11; + case(0x780C): + return GroupVariation::Group120Var12; + case(0x780D): + return GroupVariation::Group120Var13; + case(0x780E): + return GroupVariation::Group120Var14; + case(0x780F): + return GroupVariation::Group120Var15; + case(0x7900): + return GroupVariation::Group121Var0; + case(0x7901): + return GroupVariation::Group121Var1; + case(0x7A00): + return GroupVariation::Group122Var0; + case(0x7A01): + return GroupVariation::Group122Var1; + case(0x7A02): + return GroupVariation::Group122Var2; + default: + return GroupVariation::UNKNOWN; + } +} +char const* GroupVariationToString(GroupVariation arg) +{ + switch(arg) + { + case(GroupVariation::Group1Var0): + return "Binary Input - Any Variation"; + case(GroupVariation::Group1Var1): + return "Binary Input - Packed Format"; + case(GroupVariation::Group1Var2): + return "Binary Input - With Flags"; + case(GroupVariation::Group2Var0): + return "Binary Input Event - Any Variation"; + case(GroupVariation::Group2Var1): + return "Binary Input Event - Without Time"; + case(GroupVariation::Group2Var2): + return "Binary Input Event - With Absolute Time"; + case(GroupVariation::Group2Var3): + return "Binary Input Event - With Relative Time"; + case(GroupVariation::Group3Var0): + return "Double-bit Binary Input - Any Variation"; + case(GroupVariation::Group3Var1): + return "Double-bit Binary Input - Packed Format"; + case(GroupVariation::Group3Var2): + return "Double-bit Binary Input - With Flags"; + case(GroupVariation::Group4Var0): + return "Double-bit Binary Input Event - Any Variation"; + case(GroupVariation::Group4Var1): + return "Double-bit Binary Input Event - Without Time"; + case(GroupVariation::Group4Var2): + return "Double-bit Binary Input Event - With Absolute Time"; + case(GroupVariation::Group4Var3): + return "Double-bit Binary Input Event - With Relative Time"; + case(GroupVariation::Group10Var0): + return "Binary Output - Any Variation"; + case(GroupVariation::Group10Var1): + return "Binary Output - Packed Format"; + case(GroupVariation::Group10Var2): + return "Binary Output - Output Status With Flags"; + case(GroupVariation::Group11Var0): + return "Binary Output Event - Any Variation"; + case(GroupVariation::Group11Var1): + return "Binary Output Event - Output Status Without Time"; + case(GroupVariation::Group11Var2): + return "Binary Output Event - Output Status With Time"; + case(GroupVariation::Group12Var0): + return "Binary Command - Any Variation"; + case(GroupVariation::Group12Var1): + return "Binary Command - CROB"; + case(GroupVariation::Group13Var1): + return "Binary Command Event - Without Time"; + case(GroupVariation::Group13Var2): + return "Binary Command Event - With Time"; + case(GroupVariation::Group20Var0): + return "Counter - Any Variation"; + case(GroupVariation::Group20Var1): + return "Counter - 32-bit With Flag"; + case(GroupVariation::Group20Var2): + return "Counter - 16-bit With Flag"; + case(GroupVariation::Group20Var5): + return "Counter - 32-bit Without Flag"; + case(GroupVariation::Group20Var6): + return "Counter - 16-bit Without Flag"; + case(GroupVariation::Group21Var0): + return "Frozen Counter - Any Variation"; + case(GroupVariation::Group21Var1): + return "Frozen Counter - 32-bit With Flag"; + case(GroupVariation::Group21Var2): + return "Frozen Counter - 16-bit With Flag"; + case(GroupVariation::Group21Var5): + return "Frozen Counter - 32-bit With Flag and Time"; + case(GroupVariation::Group21Var6): + return "Frozen Counter - 16-bit With Flag and Time"; + case(GroupVariation::Group21Var9): + return "Frozen Counter - 32-bit Without Flag"; + case(GroupVariation::Group21Var10): + return "Frozen Counter - 16-bit Without Flag"; + case(GroupVariation::Group22Var0): + return "Counter Event - Any Variation"; + case(GroupVariation::Group22Var1): + return "Counter Event - 32-bit With Flag"; + case(GroupVariation::Group22Var2): + return "Counter Event - 16-bit With Flag"; + case(GroupVariation::Group22Var5): + return "Counter Event - 32-bit With Flag and Time"; + case(GroupVariation::Group22Var6): + return "Counter Event - 16-bit With Flag and Time"; + case(GroupVariation::Group23Var0): + return "Frozen Counter Event - Any Variation"; + case(GroupVariation::Group23Var1): + return "Frozen Counter Event - 32-bit With Flag"; + case(GroupVariation::Group23Var2): + return "Frozen Counter Event - 16-bit With Flag"; + case(GroupVariation::Group23Var5): + return "Frozen Counter Event - 32-bit With Flag and Time"; + case(GroupVariation::Group23Var6): + return "Frozen Counter Event - 16-bit With Flag and Time"; + case(GroupVariation::Group30Var0): + return "Analog Input - Any Variation"; + case(GroupVariation::Group30Var1): + return "Analog Input - 32-bit With Flag"; + case(GroupVariation::Group30Var2): + return "Analog Input - 16-bit With Flag"; + case(GroupVariation::Group30Var3): + return "Analog Input - 32-bit Without Flag"; + case(GroupVariation::Group30Var4): + return "Analog Input - 16-bit Without Flag"; + case(GroupVariation::Group30Var5): + return "Analog Input - Single-precision With Flag"; + case(GroupVariation::Group30Var6): + return "Analog Input - Double-precision With Flag"; + case(GroupVariation::Group32Var0): + return "Analog Input Event - Any Variation"; + case(GroupVariation::Group32Var1): + return "Analog Input Event - 32-bit With Flag"; + case(GroupVariation::Group32Var2): + return "Analog Input Event - 16-bit With Flag"; + case(GroupVariation::Group32Var3): + return "Analog Input Event - 32-bit With Flag and Time"; + case(GroupVariation::Group32Var4): + return "Analog Input Event - 16-bit With Flag and Time"; + case(GroupVariation::Group32Var5): + return "Analog Input Event - Single-precision With Flag"; + case(GroupVariation::Group32Var6): + return "Analog Input Event - Double-precision With Flag"; + case(GroupVariation::Group32Var7): + return "Analog Input Event - Single-precision With Flag and Time"; + case(GroupVariation::Group32Var8): + return "Analog Input Event - Double-precision With Flag and Time"; + case(GroupVariation::Group40Var0): + return "Analog Output Status - Any Variation"; + case(GroupVariation::Group40Var1): + return "Analog Output Status - 32-bit With Flag"; + case(GroupVariation::Group40Var2): + return "Analog Output Status - 16-bit With Flag"; + case(GroupVariation::Group40Var3): + return "Analog Output Status - Single-precision With Flag"; + case(GroupVariation::Group40Var4): + return "Analog Output Status - Double-precision With Flag"; + case(GroupVariation::Group41Var0): + return "Analog Output - Any Variation"; + case(GroupVariation::Group41Var1): + return "Analog Output - 32-bit With Flag"; + case(GroupVariation::Group41Var2): + return "Analog Output - 16-bit With Flag"; + case(GroupVariation::Group41Var3): + return "Analog Output - Single-precision"; + case(GroupVariation::Group41Var4): + return "Analog Output - Double-precision"; + case(GroupVariation::Group42Var0): + return "Analog Output Event - Any Variation"; + case(GroupVariation::Group42Var1): + return "Analog Output Event - 32-bit With Flag"; + case(GroupVariation::Group42Var2): + return "Analog Output Event - 16-bit With Flag"; + case(GroupVariation::Group42Var3): + return "Analog Output Event - 32-bit With Flag and Time"; + case(GroupVariation::Group42Var4): + return "Analog Output Event - 16-bit With Flag and Time"; + case(GroupVariation::Group42Var5): + return "Analog Output Event - Single-precision With Flag"; + case(GroupVariation::Group42Var6): + return "Analog Output Event - Double-precision With Flag"; + case(GroupVariation::Group42Var7): + return "Analog Output Event - Single-precision With Flag and Time"; + case(GroupVariation::Group42Var8): + return "Analog Output Event - Double-precision With Flag and Time"; + case(GroupVariation::Group43Var1): + return "Analog Command Event - 32-bit"; + case(GroupVariation::Group43Var2): + return "Analog Command Event - 16-bit"; + case(GroupVariation::Group43Var3): + return "Analog Command Event - 32-bit With Time"; + case(GroupVariation::Group43Var4): + return "Analog Command Event - 16-bit With Time"; + case(GroupVariation::Group43Var5): + return "Analog Command Event - Single-precision"; + case(GroupVariation::Group43Var6): + return "Analog Command Event - Double-precision"; + case(GroupVariation::Group43Var7): + return "Analog Command Event - Single-precision With Time"; + case(GroupVariation::Group43Var8): + return "Analog Command Event - Double-precision With Time"; + case(GroupVariation::Group50Var1): + return "Time and Date - Absolute Time"; + case(GroupVariation::Group50Var4): + return "Time and Date - Indexed absolute time and long interval"; + case(GroupVariation::Group51Var1): + return "Time and Date CTO - Absolute time, synchronized"; + case(GroupVariation::Group51Var2): + return "Time and Date CTO - Absolute time, unsynchronized"; + case(GroupVariation::Group52Var1): + return "Time Delay - Coarse"; + case(GroupVariation::Group52Var2): + return "Time Delay - Fine"; + case(GroupVariation::Group60Var1): + return "Class Data - Class 0"; + case(GroupVariation::Group60Var2): + return "Class Data - Class 1"; + case(GroupVariation::Group60Var3): + return "Class Data - Class 2"; + case(GroupVariation::Group60Var4): + return "Class Data - Class 3"; + case(GroupVariation::Group70Var1): + return "File-control - File identifier"; + case(GroupVariation::Group70Var2): + return "File-control - Authentication"; + case(GroupVariation::Group70Var3): + return "File-control - File command"; + case(GroupVariation::Group70Var4): + return "File-control - File command status"; + case(GroupVariation::Group70Var5): + return "File-control - File transport"; + case(GroupVariation::Group70Var6): + return "File-control - File transport status"; + case(GroupVariation::Group70Var7): + return "File-control - File descriptor"; + case(GroupVariation::Group70Var8): + return "File-control - File specification string"; + case(GroupVariation::Group80Var1): + return "Internal Indications - Packed Format"; + case(GroupVariation::Group110Var0): + return "Octet String - Sized by variation"; + case(GroupVariation::Group111Var0): + return "Octet String Event - Sized by variation"; + case(GroupVariation::Group112Var0): + return "Virtual Terminal Output Block - Sized by variation"; + case(GroupVariation::Group113Var0): + return "Virtual Terminal Event Data - Sized by variation"; + case(GroupVariation::Group120Var1): + return "Authentication - Challenge"; + case(GroupVariation::Group120Var2): + return "Authentication - Reply"; + case(GroupVariation::Group120Var3): + return "Authentication - Aggressive Mode Request"; + case(GroupVariation::Group120Var4): + return "Authentication - Session Key Status Request"; + case(GroupVariation::Group120Var5): + return "Authentication - Session Key Status"; + case(GroupVariation::Group120Var6): + return "Authentication - Session Key Change"; + case(GroupVariation::Group120Var7): + return "Authentication - Error"; + case(GroupVariation::Group120Var8): + return "Authentication - User Certificate"; + case(GroupVariation::Group120Var9): + return "Authentication - HMAC"; + case(GroupVariation::Group120Var10): + return "Authentication - User Status Change"; + case(GroupVariation::Group120Var11): + return "Authentication - Update Key Change Request"; + case(GroupVariation::Group120Var12): + return "Authentication - Update Key Change Reply"; + case(GroupVariation::Group120Var13): + return "Authentication - Update Key Change"; + case(GroupVariation::Group120Var14): + return "Authentication - Update Key Change Signature"; + case(GroupVariation::Group120Var15): + return "Authentication - Update Key Change Confirmation"; + case(GroupVariation::Group121Var0): + return "Security statistic - Any Variation"; + case(GroupVariation::Group121Var1): + return "Security statistic - 32-bit With Flag"; + case(GroupVariation::Group122Var0): + return "Security Statistic event - Any Variation"; + case(GroupVariation::Group122Var1): + return "Security Statistic event - 32-bit With Flag"; + case(GroupVariation::Group122Var2): + return "Security Statistic event - 32-bit With Flag and Time"; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/HMACType.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/HMACType.cpp new file mode 100644 index 0000000..9c28384 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/HMACType.cpp @@ -0,0 +1,70 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/HMACType.h" + +namespace opendnp3 { + +uint8_t HMACTypeToType(HMACType arg) +{ + return static_cast(arg); +} +HMACType HMACTypeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x0): + return HMACType::NO_MAC_VALUE; + case(0x2): + return HMACType::HMAC_SHA1_TRUNC_10; + case(0x3): + return HMACType::HMAC_SHA256_TRUNC_8; + case(0x4): + return HMACType::HMAC_SHA256_TRUNC_16; + case(0x5): + return HMACType::HMAC_SHA1_TRUNC_8; + case(0x6): + return HMACType::AES_GMAC; + default: + return HMACType::UNKNOWN; + } +} +char const* HMACTypeToString(HMACType arg) +{ + switch(arg) + { + case(HMACType::NO_MAC_VALUE): + return "NO_MAC_VALUE"; + case(HMACType::HMAC_SHA1_TRUNC_10): + return "HMAC_SHA1_TRUNC_10"; + case(HMACType::HMAC_SHA256_TRUNC_8): + return "HMAC_SHA256_TRUNC_8"; + case(HMACType::HMAC_SHA256_TRUNC_16): + return "HMAC_SHA256_TRUNC_16"; + case(HMACType::HMAC_SHA1_TRUNC_8): + return "HMAC_SHA1_TRUNC_8"; + case(HMACType::AES_GMAC): + return "AES_GMAC"; + default: + return "UNKNOWN"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/IntervalUnits.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/IntervalUnits.cpp new file mode 100644 index 0000000..15ce7e5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/IntervalUnits.cpp @@ -0,0 +1,90 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/IntervalUnits.h" + +namespace opendnp3 { + +uint8_t IntervalUnitsToType(IntervalUnits arg) +{ + return static_cast(arg); +} +IntervalUnits IntervalUnitsFromType(uint8_t arg) +{ + switch(arg) + { + case(0x0): + return IntervalUnits::NoRepeat; + case(0x1): + return IntervalUnits::Milliseconds; + case(0x2): + return IntervalUnits::Seconds; + case(0x3): + return IntervalUnits::Minutes; + case(0x4): + return IntervalUnits::Hours; + case(0x5): + return IntervalUnits::Days; + case(0x6): + return IntervalUnits::Weeks; + case(0x7): + return IntervalUnits::Months7; + case(0x8): + return IntervalUnits::Months8; + case(0x9): + return IntervalUnits::Months9; + case(0xA): + return IntervalUnits::Seasons; + default: + return IntervalUnits::Undefined; + } +} +char const* IntervalUnitsToString(IntervalUnits arg) +{ + switch(arg) + { + case(IntervalUnits::NoRepeat): + return "NoRepeat"; + case(IntervalUnits::Milliseconds): + return "Milliseconds"; + case(IntervalUnits::Seconds): + return "Seconds"; + case(IntervalUnits::Minutes): + return "Minutes"; + case(IntervalUnits::Hours): + return "Hours"; + case(IntervalUnits::Days): + return "Days"; + case(IntervalUnits::Weeks): + return "Weeks"; + case(IntervalUnits::Months7): + return "Months7"; + case(IntervalUnits::Months8): + return "Months8"; + case(IntervalUnits::Months9): + return "Months9"; + case(IntervalUnits::Seasons): + return "Seasons"; + default: + return "Undefined"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyChangeMethod.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyChangeMethod.cpp new file mode 100644 index 0000000..245f725 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyChangeMethod.cpp @@ -0,0 +1,78 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/KeyChangeMethod.h" + +namespace opendnp3 { + +uint8_t KeyChangeMethodToType(KeyChangeMethod arg) +{ + return static_cast(arg); +} +KeyChangeMethod KeyChangeMethodFromType(uint8_t arg) +{ + switch(arg) + { + case(0x3): + return KeyChangeMethod::AES_128_SHA1_HMAC; + case(0x4): + return KeyChangeMethod::AES_256_SHA256_HMAC; + case(0x5): + return KeyChangeMethod::AES_256_AES_GMAC; + case(0x43): + return KeyChangeMethod::RSA_1024_DSA_SHA1_HMAC_SHA1; + case(0x44): + return KeyChangeMethod::RSA_2048_DSA_SHA256_HMAC_SHA256; + case(0x45): + return KeyChangeMethod::RSA_3072_DSA_SHA256_HMAC_SHA256; + case(0x46): + return KeyChangeMethod::RSA_2048_DSA_SHA256_AES_GMAC; + case(0x47): + return KeyChangeMethod::RSA_3072_DSA_SHA256_AES_GMAC; + default: + return KeyChangeMethod::UNDEFINED; + } +} +char const* KeyChangeMethodToString(KeyChangeMethod arg) +{ + switch(arg) + { + case(KeyChangeMethod::AES_128_SHA1_HMAC): + return "AES_128_SHA1_HMAC"; + case(KeyChangeMethod::AES_256_SHA256_HMAC): + return "AES_256_SHA256_HMAC"; + case(KeyChangeMethod::AES_256_AES_GMAC): + return "AES_256_AES_GMAC"; + case(KeyChangeMethod::RSA_1024_DSA_SHA1_HMAC_SHA1): + return "RSA_1024_DSA_SHA1_HMAC_SHA1"; + case(KeyChangeMethod::RSA_2048_DSA_SHA256_HMAC_SHA256): + return "RSA_2048_DSA_SHA256_HMAC_SHA256"; + case(KeyChangeMethod::RSA_3072_DSA_SHA256_HMAC_SHA256): + return "RSA_3072_DSA_SHA256_HMAC_SHA256"; + case(KeyChangeMethod::RSA_2048_DSA_SHA256_AES_GMAC): + return "RSA_2048_DSA_SHA256_AES_GMAC"; + case(KeyChangeMethod::RSA_3072_DSA_SHA256_AES_GMAC): + return "RSA_3072_DSA_SHA256_AES_GMAC"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyStatus.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyStatus.cpp new file mode 100644 index 0000000..95a7052 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyStatus.cpp @@ -0,0 +1,62 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/KeyStatus.h" + +namespace opendnp3 { + +uint8_t KeyStatusToType(KeyStatus arg) +{ + return static_cast(arg); +} +KeyStatus KeyStatusFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return KeyStatus::OK; + case(0x2): + return KeyStatus::NOT_INIT; + case(0x3): + return KeyStatus::COMM_FAIL; + case(0x4): + return KeyStatus::AUTH_FAIL; + default: + return KeyStatus::UNDEFINED; + } +} +char const* KeyStatusToString(KeyStatus arg) +{ + switch(arg) + { + case(KeyStatus::OK): + return "OK"; + case(KeyStatus::NOT_INIT): + return "NOT_INIT"; + case(KeyStatus::COMM_FAIL): + return "COMM_FAIL"; + case(KeyStatus::AUTH_FAIL): + return "AUTH_FAIL"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyWrapAlgorithm.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyWrapAlgorithm.cpp new file mode 100644 index 0000000..c2f3314 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/KeyWrapAlgorithm.cpp @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/KeyWrapAlgorithm.h" + +namespace opendnp3 { + +uint8_t KeyWrapAlgorithmToType(KeyWrapAlgorithm arg) +{ + return static_cast(arg); +} +KeyWrapAlgorithm KeyWrapAlgorithmFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return KeyWrapAlgorithm::AES_128; + case(0x2): + return KeyWrapAlgorithm::AES_256; + default: + return KeyWrapAlgorithm::UNDEFINED; + } +} +char const* KeyWrapAlgorithmToString(KeyWrapAlgorithm arg) +{ + switch(arg) + { + case(KeyWrapAlgorithm::AES_128): + return "AES_128"; + case(KeyWrapAlgorithm::AES_256): + return "AES_256"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkFunction.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkFunction.cpp new file mode 100644 index 0000000..0afae93 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkFunction.cpp @@ -0,0 +1,82 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/LinkFunction.h" + +namespace opendnp3 { + +uint8_t LinkFunctionToType(LinkFunction arg) +{ + return static_cast(arg); +} +LinkFunction LinkFunctionFromType(uint8_t arg) +{ + switch(arg) + { + case(0x40): + return LinkFunction::PRI_RESET_LINK_STATES; + case(0x42): + return LinkFunction::PRI_TEST_LINK_STATES; + case(0x43): + return LinkFunction::PRI_CONFIRMED_USER_DATA; + case(0x44): + return LinkFunction::PRI_UNCONFIRMED_USER_DATA; + case(0x49): + return LinkFunction::PRI_REQUEST_LINK_STATUS; + case(0x0): + return LinkFunction::SEC_ACK; + case(0x1): + return LinkFunction::SEC_NACK; + case(0xB): + return LinkFunction::SEC_LINK_STATUS; + case(0xF): + return LinkFunction::SEC_NOT_SUPPORTED; + default: + return LinkFunction::INVALID; + } +} +char const* LinkFunctionToString(LinkFunction arg) +{ + switch(arg) + { + case(LinkFunction::PRI_RESET_LINK_STATES): + return "PRI_RESET_LINK_STATES"; + case(LinkFunction::PRI_TEST_LINK_STATES): + return "PRI_TEST_LINK_STATES"; + case(LinkFunction::PRI_CONFIRMED_USER_DATA): + return "PRI_CONFIRMED_USER_DATA"; + case(LinkFunction::PRI_UNCONFIRMED_USER_DATA): + return "PRI_UNCONFIRMED_USER_DATA"; + case(LinkFunction::PRI_REQUEST_LINK_STATUS): + return "PRI_REQUEST_LINK_STATUS"; + case(LinkFunction::SEC_ACK): + return "SEC_ACK"; + case(LinkFunction::SEC_NACK): + return "SEC_NACK"; + case(LinkFunction::SEC_LINK_STATUS): + return "SEC_LINK_STATUS"; + case(LinkFunction::SEC_NOT_SUPPORTED): + return "SEC_NOT_SUPPORTED"; + default: + return "INVALID"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkStatus.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkStatus.cpp new file mode 100644 index 0000000..3410729 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/LinkStatus.cpp @@ -0,0 +1,38 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/LinkStatus.h" + +namespace opendnp3 { + +char const* LinkStatusToString(LinkStatus arg) +{ + switch(arg) + { + case(LinkStatus::UNRESET): + return "UNRESET"; + case(LinkStatus::RESET): + return "RESET"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/MasterTaskType.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/MasterTaskType.cpp new file mode 100644 index 0000000..338450e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/MasterTaskType.cpp @@ -0,0 +1,52 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/MasterTaskType.h" + +namespace opendnp3 { + +char const* MasterTaskTypeToString(MasterTaskType arg) +{ + switch(arg) + { + case(MasterTaskType::CLEAR_RESTART): + return "CLEAR_RESTART"; + case(MasterTaskType::DISABLE_UNSOLICITED): + return "DISABLE_UNSOLICITED"; + case(MasterTaskType::ASSIGN_CLASS): + return "ASSIGN_CLASS"; + case(MasterTaskType::STARTUP_INTEGRITY_POLL): + return "STARTUP_INTEGRITY_POLL"; + case(MasterTaskType::SERIAL_TIME_SYNC): + return "SERIAL_TIME_SYNC"; + case(MasterTaskType::ENABLE_UNSOLICITED): + return "ENABLE_UNSOLICITED"; + case(MasterTaskType::AUTO_EVENT_SCAN): + return "AUTO_EVENT_SCAN"; + case(MasterTaskType::USER_TASK): + return "USER_TASK"; + case(MasterTaskType::SET_SESSION_KEYS): + return "SET_SESSION_KEYS"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/Parity.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/Parity.cpp new file mode 100644 index 0000000..978e0bf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/Parity.cpp @@ -0,0 +1,54 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/Parity.h" + +namespace opendnp3 { + +uint8_t ParityToType(Parity arg) +{ + return static_cast(arg); +} +Parity ParityFromType(uint8_t arg) +{ + switch(arg) + { + case(1): + return Parity::Even; + case(2): + return Parity::Odd; + default: + return Parity::None; + } +} +char const* ParityToString(Parity arg) +{ + switch(arg) + { + case(Parity::Even): + return "Even"; + case(Parity::Odd): + return "Odd"; + default: + return "None"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/QualifierCode.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/QualifierCode.cpp new file mode 100644 index 0000000..bec28b9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/QualifierCode.cpp @@ -0,0 +1,78 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/QualifierCode.h" + +namespace opendnp3 { + +uint8_t QualifierCodeToType(QualifierCode arg) +{ + return static_cast(arg); +} +QualifierCode QualifierCodeFromType(uint8_t arg) +{ + switch(arg) + { + case(0x0): + return QualifierCode::UINT8_START_STOP; + case(0x1): + return QualifierCode::UINT16_START_STOP; + case(0x6): + return QualifierCode::ALL_OBJECTS; + case(0x7): + return QualifierCode::UINT8_CNT; + case(0x8): + return QualifierCode::UINT16_CNT; + case(0x17): + return QualifierCode::UINT8_CNT_UINT8_INDEX; + case(0x28): + return QualifierCode::UINT16_CNT_UINT16_INDEX; + case(0x5B): + return QualifierCode::UINT16_FREE_FORMAT; + default: + return QualifierCode::UNDEFINED; + } +} +char const* QualifierCodeToString(QualifierCode arg) +{ + switch(arg) + { + case(QualifierCode::UINT8_START_STOP): + return "8-bit start stop"; + case(QualifierCode::UINT16_START_STOP): + return "16-bit start stop"; + case(QualifierCode::ALL_OBJECTS): + return "all objects"; + case(QualifierCode::UINT8_CNT): + return "8-bit count"; + case(QualifierCode::UINT16_CNT): + return "16-bit count"; + case(QualifierCode::UINT8_CNT_UINT8_INDEX): + return "8-bit count and prefix"; + case(QualifierCode::UINT16_CNT_UINT16_INDEX): + return "16-bit count and prefix"; + case(QualifierCode::UINT16_FREE_FORMAT): + return "16-bit free format"; + default: + return "unknown"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/StopBits.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/StopBits.cpp new file mode 100644 index 0000000..18ccf10 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/StopBits.cpp @@ -0,0 +1,58 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/StopBits.h" + +namespace opendnp3 { + +uint8_t StopBitsToType(StopBits arg) +{ + return static_cast(arg); +} +StopBits StopBitsFromType(uint8_t arg) +{ + switch(arg) + { + case(1): + return StopBits::One; + case(2): + return StopBits::OnePointFive; + case(3): + return StopBits::Two; + default: + return StopBits::None; + } +} +char const* StopBitsToString(StopBits arg) +{ + switch(arg) + { + case(StopBits::One): + return "One"; + case(StopBits::OnePointFive): + return "OnePointFive"; + case(StopBits::Two): + return "Two"; + default: + return "None"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/TaskCompletion.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/TaskCompletion.cpp new file mode 100644 index 0000000..c71c40e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/TaskCompletion.cpp @@ -0,0 +1,50 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/TaskCompletion.h" + +namespace opendnp3 { + +char const* TaskCompletionToString(TaskCompletion arg) +{ + switch(arg) + { + case(TaskCompletion::SUCCESS): + return "SUCCESS"; + case(TaskCompletion::FAILURE_BAD_RESPONSE): + return "FAILURE_BAD_RESPONSE"; + case(TaskCompletion::FAILURE_RESPONSE_TIMEOUT): + return "FAILURE_RESPONSE_TIMEOUT"; + case(TaskCompletion::FAILURE_START_TIMEOUT): + return "FAILURE_START_TIMEOUT"; + case(TaskCompletion::FAILURE_NO_USER): + return "FAILURE_NO_USER"; + case(TaskCompletion::FAILURE_INTERNAL_ERROR): + return "FAILURE_INTERNAL_ERROR"; + case(TaskCompletion::FAILURE_BAD_AUTHENTICATION): + return "FAILURE_BAD_AUTHENTICATION"; + case(TaskCompletion::FAILURE_NOT_AUTHORIZED): + return "FAILURE_NOT_AUTHORIZED"; + default: + return "FAILURE_NO_COMMS"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserOperation.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserOperation.cpp new file mode 100644 index 0000000..1917ca0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserOperation.cpp @@ -0,0 +1,58 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/UserOperation.h" + +namespace opendnp3 { + +uint8_t UserOperationToType(UserOperation arg) +{ + return static_cast(arg); +} +UserOperation UserOperationFromType(uint8_t arg) +{ + switch(arg) + { + case(0x1): + return UserOperation::OP_ADD; + case(0x2): + return UserOperation::OP_DELETE; + case(0x3): + return UserOperation::OP_CHANGE; + default: + return UserOperation::OP_UNDEFINED; + } +} +char const* UserOperationToString(UserOperation arg) +{ + switch(arg) + { + case(UserOperation::OP_ADD): + return "OP_ADD"; + case(UserOperation::OP_DELETE): + return "OP_DELETE"; + case(UserOperation::OP_CHANGE): + return "OP_CHANGE"; + default: + return "OP_UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserRole.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserRole.cpp new file mode 100644 index 0000000..4d8f14c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/gen/UserRole.cpp @@ -0,0 +1,78 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "opendnp3/gen/UserRole.h" + +namespace opendnp3 { + +uint16_t UserRoleToType(UserRole arg) +{ + return static_cast(arg); +} +UserRole UserRoleFromType(uint16_t arg) +{ + switch(arg) + { + case(0): + return UserRole::VIEWER; + case(1): + return UserRole::OPERATOR; + case(2): + return UserRole::ENGINEER; + case(3): + return UserRole::INSTALLER; + case(4): + return UserRole::SECADM; + case(5): + return UserRole::SECAUD; + case(6): + return UserRole::RBACMNT; + case(32768): + return UserRole::SINGLE_USER; + default: + return UserRole::UNDEFINED; + } +} +char const* UserRoleToString(UserRole arg) +{ + switch(arg) + { + case(UserRole::VIEWER): + return "VIEWER"; + case(UserRole::OPERATOR): + return "OPERATOR"; + case(UserRole::ENGINEER): + return "ENGINEER"; + case(UserRole::INSTALLER): + return "INSTALLER"; + case(UserRole::SECADM): + return "SECADM"; + case(UserRole::SECAUD): + return "SECAUD"; + case(UserRole::RBACMNT): + return "RBACMNT"; + case(UserRole::SINGLE_USER): + return "SINGLE_USER"; + default: + return "UNDEFINED"; + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.cpp new file mode 100644 index 0000000..519147b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.cpp @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CRC.h" + +#include + +namespace opendnp3 +{ + +uint16_t CRC::crcTable[256] = +{ + 0x0000, 0x365E, 0x6CBC, 0x5AE2, 0xD978, 0xEF26, 0xB5C4, 0x839A, + 0xFF89, 0xC9D7, 0x9335, 0xA56B, 0x26F1, 0x10AF, 0x4A4D, 0x7C13, + 0xB26B, 0x8435, 0xDED7, 0xE889, 0x6B13, 0x5D4D, 0x07AF, 0x31F1, + 0x4DE2, 0x7BBC, 0x215E, 0x1700, 0x949A, 0xA2C4, 0xF826, 0xCE78, + 0x29AF, 0x1FF1, 0x4513, 0x734D, 0xF0D7, 0xC689, 0x9C6B, 0xAA35, + 0xD626, 0xE078, 0xBA9A, 0x8CC4, 0x0F5E, 0x3900, 0x63E2, 0x55BC, + 0x9BC4, 0xAD9A, 0xF778, 0xC126, 0x42BC, 0x74E2, 0x2E00, 0x185E, + 0x644D, 0x5213, 0x08F1, 0x3EAF, 0xBD35, 0x8B6B, 0xD189, 0xE7D7, + 0x535E, 0x6500, 0x3FE2, 0x09BC, 0x8A26, 0xBC78, 0xE69A, 0xD0C4, + 0xACD7, 0x9A89, 0xC06B, 0xF635, 0x75AF, 0x43F1, 0x1913, 0x2F4D, + 0xE135, 0xD76B, 0x8D89, 0xBBD7, 0x384D, 0x0E13, 0x54F1, 0x62AF, + 0x1EBC, 0x28E2, 0x7200, 0x445E, 0xC7C4, 0xF19A, 0xAB78, 0x9D26, + 0x7AF1, 0x4CAF, 0x164D, 0x2013, 0xA389, 0x95D7, 0xCF35, 0xF96B, + 0x8578, 0xB326, 0xE9C4, 0xDF9A, 0x5C00, 0x6A5E, 0x30BC, 0x06E2, + 0xC89A, 0xFEC4, 0xA426, 0x9278, 0x11E2, 0x27BC, 0x7D5E, 0x4B00, + 0x3713, 0x014D, 0x5BAF, 0x6DF1, 0xEE6B, 0xD835, 0x82D7, 0xB489, + 0xA6BC, 0x90E2, 0xCA00, 0xFC5E, 0x7FC4, 0x499A, 0x1378, 0x2526, + 0x5935, 0x6F6B, 0x3589, 0x03D7, 0x804D, 0xB613, 0xECF1, 0xDAAF, + 0x14D7, 0x2289, 0x786B, 0x4E35, 0xCDAF, 0xFBF1, 0xA113, 0x974D, + 0xEB5E, 0xDD00, 0x87E2, 0xB1BC, 0x3226, 0x0478, 0x5E9A, 0x68C4, + 0x8F13, 0xB94D, 0xE3AF, 0xD5F1, 0x566B, 0x6035, 0x3AD7, 0x0C89, + 0x709A, 0x46C4, 0x1C26, 0x2A78, 0xA9E2, 0x9FBC, 0xC55E, 0xF300, + 0x3D78, 0x0B26, 0x51C4, 0x679A, 0xE400, 0xD25E, 0x88BC, 0xBEE2, + 0xC2F1, 0xF4AF, 0xAE4D, 0x9813, 0x1B89, 0x2DD7, 0x7735, 0x416B, + 0xF5E2, 0xC3BC, 0x995E, 0xAF00, 0x2C9A, 0x1AC4, 0x4026, 0x7678, + 0x0A6B, 0x3C35, 0x66D7, 0x5089, 0xD313, 0xE54D, 0xBFAF, 0x89F1, + 0x4789, 0x71D7, 0x2B35, 0x1D6B, 0x9EF1, 0xA8AF, 0xF24D, 0xC413, + 0xB800, 0x8E5E, 0xD4BC, 0xE2E2, 0x6178, 0x5726, 0x0DC4, 0x3B9A, + 0xDC4D, 0xEA13, 0xB0F1, 0x86AF, 0x0535, 0x336B, 0x6989, 0x5FD7, + 0x23C4, 0x159A, 0x4F78, 0x7926, 0xFABC, 0xCCE2, 0x9600, 0xA05E, + 0x6E26, 0x5878, 0x029A, 0x34C4, 0xB75E, 0x8100, 0xDBE2, 0xEDBC, + 0x91AF, 0xA7F1, 0xFD13, 0xCB4D, 0x48D7, 0x7E89, 0x246B, 0x1235 +}; + +uint16_t CRC::CalcCrc(const uint8_t* input, uint32_t length) +{ + uint16_t CRC = 0; + + for (uint32_t i = 0; i < length; ++i) + { + uint8_t index = (CRC ^ input[i]) & 0xFF; + CRC = crcTable[index] ^ (CRC >> 8); + } + + return ~CRC; +} + +uint16_t CRC::CalcCrc(const openpal::RSlice& view) +{ + return CalcCrc(view, view.Size()); +} + +void CRC::AddCrc(uint8_t* input, uint32_t length) +{ + uint16_t crc = CRC::CalcCrc(input, length); + openpal::UInt16::Write(input + length, crc); +} + +bool CRC::IsCorrectCRC(const uint8_t* input, uint32_t length) +{ + return CRC::CalcCrc(input, length) == openpal::UInt16::Read(input + length); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.h new file mode 100644 index 0000000..b0eae22 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/CRC.h @@ -0,0 +1,51 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CRC_H +#define OPENDNP3_CRC_H + +#include + +#include + +namespace opendnp3 +{ + +class CRC +{ +public: + + static uint16_t CalcCrc(const uint8_t* input, uint32_t length); + + static uint16_t CalcCrc(const openpal::RSlice& view); + + static void AddCrc(uint8_t* input, uint32_t length); + + static bool IsCorrectCRC(const uint8_t* input, uint32_t length); + +private: + + static uint16_t crcTable[256]; //Precomputed CRC lookup table + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/IFrameSink.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/IFrameSink.h new file mode 100644 index 0000000..7ce1a9a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/IFrameSink.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IFRAMESINK_H +#define OPENDNP3_IFRAMESINK_H + +#include + +#include "opendnp3/link/LinkHeaderFields.h" + +#include + +namespace opendnp3 +{ + +// @section DESCRIPTION Interface that receives parsed FT3 frame information +class IFrameSink +{ +public: + + virtual ~IFrameSink() {} + + virtual bool OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) = 0; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkLayer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkLayer.h new file mode 100644 index 0000000..1092e82 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkLayer.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ILINKLAYER_H +#define OPENDNP3_ILINKLAYER_H + +#include "opendnp3/link/ITransportSegment.h" + +#include "opendnp3/LayerInterfaces.h" + +#include + +namespace opendnp3 +{ + +class ILinkLayer +{ + +public: + + virtual ~ILinkLayer() {} + + /// Transmit a buffer that can be iterated over in no greater than 250 byte segments + virtual bool Send(ITransportSegment& segment) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkSession.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkSession.h new file mode 100644 index 0000000..e2bf6d0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkSession.h @@ -0,0 +1,43 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ILINKSESSION_H +#define OPENDNP3_ILINKSESSION_H + +#include "IFrameSink.h" + +namespace opendnp3 +{ + +// @section DESCRIPTION Interface from the link router to the link layer +class ILinkSession : public IFrameSink +{ +public: + + virtual ~ILinkSession() {} + + virtual bool OnTransmitResult(bool success) = 0; + virtual bool OnLowerLayerUp() = 0; + virtual bool OnLowerLayerDown() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkTx.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkTx.h new file mode 100644 index 0000000..723ffda --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ILinkTx.h @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ILINKTX_H +#define OPENDNP3_ILINKTX_H + +#include + +#include "opendnp3/link/ILinkSession.h" + +namespace opendnp3 +{ + +/** +* Interface the link layer uses to transmit data +*/ +class ILinkTx +{ +public: + + virtual ~ILinkTx() {} + + /** + * Begin transmission of a frame. Callback happens OFF the call stack (via executor) + */ + virtual void BeginTransmit(const openpal::RSlice& buffer, ILinkSession& context) = 0; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/ITransportSegment.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ITransportSegment.h new file mode 100644 index 0000000..350f1ec --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ITransportSegment.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ITRANSPORTSEGMENT_H +#define OPENDNP3_ITRANSPORTSEGMENT_H + +#include + +namespace opendnp3 +{ + +class ITransportSegment +{ + +public: + + virtual ~ITransportSegment() {} + + virtual bool HasValue() const = 0; + + // Read the current segment with a specified max size + virtual openpal::RSlice GetSegment() = 0; + + // move to the next segment, true if more segments available + virtual bool Advance() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.cpp new file mode 100644 index 0000000..7260f36 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.cpp @@ -0,0 +1,431 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkContext.h" + +#include "opendnp3/link/PriLinkLayerStates.h" +#include "opendnp3/link/SecLinkLayerStates.h" +#include "opendnp3/link/LinkFrame.h" +#include "opendnp3/link/ILinkTx.h" + +#include "openpal/util/Limits.h" + +using namespace openpal; + +namespace opendnp3 +{ + +LinkContext::LinkContext( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& upper, + const std::shared_ptr& listener, + ILinkSession& session, + const LinkConfig& config) + : + logger(logger), + config(config), + pSegments(nullptr), + txMode(LinkTransmitMode::Idle), + numRetryRemaining(0), + executor(executor), + rspTimeoutTimer(*executor), + keepAliveTimer(*executor), + nextReadFCB(false), + nextWriteFCB(false), + isOnline(false), + isRemoteReset(false), + keepAliveTimeout(false), + lastMessageTimestamp(executor->GetTime()), + pPriState(&PLLS_Idle::Instance()), + pSecState(&SLLS_NotReset::Instance()), + listener(listener), + upper(upper), + pSession(&session) +{} + +bool LinkContext::OnLowerLayerUp() +{ + if (this->isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer already online"); + return false; + } + + const auto now = this->executor->GetTime(); + + this->isOnline = true; + + this->lastMessageTimestamp = now; // no reason to trigger a keep-alive until we've actually expired + + this->StartKeepAliveTimer(now.Add(config.KeepAliveTimeout)); + + listener->OnStateChange(opendnp3::LinkStatus::UNRESET); + upper->OnLowerLayerUp(); + + return true; +} + +bool LinkContext::OnLowerLayerDown() +{ + if (!isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer is not online"); + return false; + } + + isOnline = false; + keepAliveTimeout = false; + isRemoteReset = false; + pSegments = nullptr; + txMode = LinkTransmitMode::Idle; + pendingPriTx.Clear(); + pendingSecTx.Clear(); + + rspTimeoutTimer.Cancel(); + keepAliveTimer.Cancel(); + + pPriState = &PLLS_Idle::Instance(); + pSecState = &SLLS_NotReset::Instance(); + + listener->OnStateChange(opendnp3::LinkStatus::UNRESET); + upper->OnLowerLayerDown(); + + return true; +} + +bool LinkContext::SetTxSegment(ITransportSegment& segments) +{ + if (!this->isOnline) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, "Layer is not online"); + return false; + } + + if (this->pSegments) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, "Already transmitting a segment"); + return false; + } + + this->pSegments = &segments; + return true; +} + +bool LinkContext::OnTransmitResult(bool success) +{ + if (this->txMode == LinkTransmitMode::Idle) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, "Unknown transmission callback"); + return false; + } + + auto isPrimary = (this->txMode == LinkTransmitMode::Primary); + this->txMode = LinkTransmitMode::Idle; + + // before we dispatch the transmit result, give any pending transmissions access first + this->TryPendingTx(this->pendingSecTx, false); + this->TryPendingTx(this->pendingPriTx, true); + + // now dispatch the completion event to the correct state handler + if (isPrimary) + { + this->pPriState = &this->pPriState->OnTransmitResult(*this, success); + } + else + { + this->pSecState = &this->pSecState->OnTransmitResult(*this, success); + } + + return true; +} + +openpal::RSlice LinkContext::FormatPrimaryBufferWithConfirmed(const openpal::RSlice& tpdu, bool FCB) +{ + auto dest = this->priTxBuffer.GetWSlice(); + auto output = LinkFrame::FormatConfirmedUserData(dest, config.IsMaster, FCB, config.RemoteAddr, config.LocalAddr, tpdu, tpdu.Size(), &logger); + FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, output, 10, 18); + return output; +} + +RSlice LinkContext::FormatPrimaryBufferWithUnconfirmed(const openpal::RSlice& tpdu) +{ + auto dest = this->priTxBuffer.GetWSlice(); + auto output = LinkFrame::FormatUnconfirmedUserData(dest, config.IsMaster, config.RemoteAddr, config.LocalAddr, tpdu, tpdu.Size(), &logger); + FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, output, 10, 18); + return output; +} + +void LinkContext::QueueTransmit(const RSlice& buffer, bool primary) +{ + if (txMode == LinkTransmitMode::Idle) + { + txMode = primary ? LinkTransmitMode::Primary : LinkTransmitMode::Secondary; + linktx->BeginTransmit(buffer, *pSession); + } + else + { + if (primary) + { + pendingPriTx.Set(buffer); + } + else + { + pendingSecTx.Set(buffer); + } + } +} + +void LinkContext::QueueAck() +{ + auto dest = secTxBuffer.GetWSlice(); + auto buffer = LinkFrame::FormatAck(dest, config.IsMaster, false, config.RemoteAddr, config.LocalAddr, &logger); + FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, buffer, 10, 18); + this->QueueTransmit(buffer, false); +} + +void LinkContext::QueueLinkStatus() +{ + auto dest = secTxBuffer.GetWSlice(); + auto buffer = LinkFrame::FormatLinkStatus(dest, config.IsMaster, false, config.RemoteAddr, config.LocalAddr, &logger); + FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, buffer, 10, 18); + this->QueueTransmit(buffer, false); +} + +void LinkContext::QueueResetLinks() +{ + auto dest = priTxBuffer.GetWSlice(); + auto buffer = LinkFrame::FormatResetLinkStates(dest, config.IsMaster, config.RemoteAddr, config.LocalAddr, &logger); + FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, buffer, 10, 18); + this->QueueTransmit(buffer, true); +} + +void LinkContext::QueueRequestLinkStatus() +{ + auto dest = priTxBuffer.GetWSlice(); + auto buffer = LinkFrame::FormatRequestLinkStatus(dest, config.IsMaster, config.RemoteAddr, config.LocalAddr, &logger); + FORMAT_HEX_BLOCK(logger, flags::LINK_TX_HEX, buffer, 10, 18); + this->QueueTransmit(buffer, true); +} + +void LinkContext::ResetRetry() +{ + this->numRetryRemaining = config.NumRetry; +} + +bool LinkContext::Retry() +{ + if (numRetryRemaining > 0) + { + --numRetryRemaining; + return true; + } + else + { + return false; + } +} + +void LinkContext::PushDataUp(const openpal::RSlice& data) +{ + upper->OnReceive(data); +} + +void LinkContext::CompleteSendOperation(bool success) +{ + this->pSegments = nullptr; + + auto callback = [upper = upper, success]() + { + upper->OnSendResult(success); + }; + + this->executor->Post(callback); + +} + +void LinkContext::TryStartTransmission() +{ + if (this->keepAliveTimeout) + { + this->pPriState = &pPriState->TrySendRequestLinkStatus(*this); + } + + if (this->pSegments) + { + this->pPriState = (this->config.UseConfirms) ? &pPriState->TrySendConfirmed(*this, *pSegments) : &pPriState->TrySendUnconfirmed(*this, *pSegments); + } +} + +void LinkContext::OnKeepAliveTimeout() +{ + const auto now = this->executor->GetTime(); + + auto elapsed = now.milliseconds - this->lastMessageTimestamp.milliseconds; + + if (elapsed >= this->config.KeepAliveTimeout.GetMilliseconds()) + { + this->lastMessageTimestamp = now; + this->keepAliveTimeout = true; + } + + this->StartKeepAliveTimer(now.Add(config.KeepAliveTimeout)); + + this->TryStartTransmission(); +} + +void LinkContext::OnResponseTimeout() +{ + this->pPriState = &(this->pPriState->OnTimeout(*this)); + + this->TryStartTransmission(); +} + +void LinkContext::StartResponseTimer() +{ + rspTimeoutTimer.Start( + TimeDuration(config.Timeout), + [this]() + { + this->OnResponseTimeout(); + } + ); +} + +void LinkContext::StartKeepAliveTimer(const MonotonicTimestamp& expiration) +{ + auto callback = [this]() + { + this->OnKeepAliveTimeout(); + }; + + this->keepAliveTimer.Start(expiration, callback); +} + +void LinkContext::CancelTimer() +{ + rspTimeoutTimer.Cancel(); +} + +void LinkContext::FailKeepAlive(bool timeout) +{ + if (timeout) + { + this->listener->OnKeepAliveFailure(); + } +} + +void LinkContext::CompleteKeepAlive() +{ + this->listener->OnKeepAliveSuccess(); +} + +bool LinkContext::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + if (!isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer is not online"); + return false; + } + + if (!this->Validate(header.isFromMaster, header.src, header.dest)) + { + return false; + } + + // reset the keep-alive timestamp + this->lastMessageTimestamp = this->executor->GetTime(); + + switch (header.func) + { + case(LinkFunction::SEC_ACK) : + pPriState = &pPriState->OnAck(*this, header.fcvdfc); + return true; + case(LinkFunction::SEC_NACK) : + pPriState = &pPriState->OnNack(*this, header.fcvdfc); + return true; + case(LinkFunction::SEC_LINK_STATUS) : + pPriState = &pPriState->OnLinkStatus(*this, header.fcvdfc); + return true; + case(LinkFunction::SEC_NOT_SUPPORTED) : + pPriState = &pPriState->OnNotSupported(*this, header.fcvdfc); + return true; + case(LinkFunction::PRI_TEST_LINK_STATES) : + pSecState = &pSecState->OnTestLinkStatus(*this, header.fcb); + return true; + case(LinkFunction::PRI_RESET_LINK_STATES) : + pSecState = &pSecState->OnResetLinkStates(*this); + return true; + case(LinkFunction::PRI_REQUEST_LINK_STATUS) : + pSecState = &pSecState->OnRequestLinkStatus(*this); + return true; + case(LinkFunction::PRI_CONFIRMED_USER_DATA) : + pSecState = &pSecState->OnConfirmedUserData(*this, header.fcb, userdata); + return true; + case(LinkFunction::PRI_UNCONFIRMED_USER_DATA) : + this->PushDataUp(userdata); + return true; + default: + return false; + } +} + +bool LinkContext::Validate(bool isMaster, uint16_t src, uint16_t dest) +{ + if (isMaster == config.IsMaster) + { + ++statistics.numBadMasterBit; + SIMPLE_LOG_BLOCK(logger, flags::WARN, (isMaster ? "Master frame received for master" : "Outstation frame received for outstation")); + return false; + } + + if (dest != config.LocalAddr) + { + ++statistics.numUnknownDestination; + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Frame for unknown destintation"); + return false; + } + + if (src != config.RemoteAddr) + { + ++statistics.numUnknownSource; + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Frame from unknwon source"); + return false; + } + + return true; +} + + +bool LinkContext::TryPendingTx(openpal::Settable& pending, bool primary) +{ + if (this->txMode == LinkTransmitMode::Idle && pending.IsSet()) + { + this->linktx->BeginTransmit(pending.Get(), *pSession); + pending.Clear(); + this->txMode = primary ? LinkTransmitMode::Primary : LinkTransmitMode::Secondary; + return true; + } + + return false; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.h new file mode 100644 index 0000000..6a4252c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkContext.h @@ -0,0 +1,155 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINK_CONTEXT_H +#define OPENDNP3_LINK_CONTEXT_H + +#include +#include +#include +#include +#include + +#include "opendnp3/gen/LinkStatus.h" +#include "opendnp3/link/ILinkLayer.h" +#include "opendnp3/link/ILinkSession.h" +#include "opendnp3/link/LinkLayerConstants.h" +#include "opendnp3/link/LinkConfig.h" +#include "opendnp3/link/ILinkListener.h" +#include "opendnp3/link/ILinkTx.h" +#include "opendnp3/StackStatistics.h" + +namespace opendnp3 +{ + +class PriStateBase; +class SecStateBase; + +enum class LinkTransmitMode : uint8_t +{ + Idle, + Primary, + Secondary +}; + +// @section desc Implements the contextual state of DNP3 Data Link Layer +class LinkContext +{ + + +public: + + LinkContext(const openpal::Logger& logger, const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr&, ILinkSession& session, const LinkConfig&); + + + /// ---- helpers for dealing with the FCB bits ---- + + void ResetReadFCB() + { + nextReadFCB = true; + } + void ResetWriteFCB() + { + nextWriteFCB = true; + } + void ToggleReadFCB() + { + nextReadFCB = !nextReadFCB; + } + void ToggleWriteFCB() + { + nextWriteFCB = !nextWriteFCB; + } + + /// --- helpers for dealing with layer state transitations --- + bool OnLowerLayerUp(); + bool OnLowerLayerDown(); + bool OnTransmitResult(bool success); + bool SetTxSegment(ITransportSegment& segments); + + /// --- helpers for formatting user data messages --- + openpal::RSlice FormatPrimaryBufferWithUnconfirmed(const openpal::RSlice& tpdu); + openpal::RSlice FormatPrimaryBufferWithConfirmed(const openpal::RSlice& tpdu, bool FCB); + + /// --- Helpers for queueing frames --- + void QueueAck(); + void QueueLinkStatus(); + void QueueResetLinks(); + void QueueRequestLinkStatus(); + void QueueTransmit(const openpal::RSlice& buffer, bool primary); + + /// --- public members ---- + + void ResetRetry(); + bool Retry(); + void PushDataUp(const openpal::RSlice& data); + void CompleteSendOperation(bool success); + void TryStartTransmission(); + void OnKeepAliveTimeout(); + void OnResponseTimeout(); + void StartResponseTimer(); + void StartKeepAliveTimer(const openpal::MonotonicTimestamp& expiration); + void CancelTimer(); + void FailKeepAlive(bool timeout); + void CompleteKeepAlive(); + bool OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata); + bool Validate(bool isMaster, uint16_t src, uint16_t dest); + bool TryPendingTx(openpal::Settable& pending, bool primary); + + // buffers used for primary and secondary requests + openpal::StaticBuffer priTxBuffer; + openpal::StaticBuffer secTxBuffer; + + openpal::Settable pendingPriTx; + openpal::Settable pendingSecTx; + + openpal::Logger logger; + const LinkConfig config; + ITransportSegment* pSegments; + LinkTransmitMode txMode; + uint32_t numRetryRemaining; + + const std::shared_ptr executor; + + openpal::TimerRef rspTimeoutTimer; + openpal::TimerRef keepAliveTimer; + bool nextReadFCB; + bool nextWriteFCB; + bool isOnline; + bool isRemoteReset; + bool keepAliveTimeout; + openpal::MonotonicTimestamp lastMessageTimestamp; + StackStatistics::Link statistics; + + ILinkTx* linktx = nullptr; + + PriStateBase* pPriState; + SecStateBase* pSecState; + + const std::shared_ptr listener; + const std::shared_ptr upper; + + ILinkSession* pSession; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.cpp new file mode 100644 index 0000000..8182f22 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.cpp @@ -0,0 +1,200 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkFrame.h" + +#include "opendnp3/link/CRC.h" +#include "opendnp3/link/LinkHeader.h" +#include "opendnp3/LogLevels.h" + +#include +#include +#include + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +void LinkFrame::ReadUserData(const uint8_t* pSrc, uint8_t* pDest, uint32_t length_) +{ + uint32_t length = length_; + uint8_t const* pRead = pSrc; + uint8_t* pWrite = pDest; + + while (length > 0) + { + uint32_t max = LPDU_DATA_BLOCK_SIZE; + uint32_t num = (length <= max) ? length : max; + uint32_t num_with_crc = num + 2; + memmove(pWrite, pRead, num); + pRead += num_with_crc; + pWrite += num; + length -= num; + } +} + + +bool LinkFrame::ValidateBodyCRC(const uint8_t* pBody, uint32_t length) +{ + while(length > 0) + { + uint32_t max = LPDU_DATA_BLOCK_SIZE; + uint32_t num = (length <= max) ? length : max; + + if (CRC::IsCorrectCRC(pBody, num)) + { + pBody += (num + 2); + length -= num; + } + else + { + return false; + } + } + return true; +} + +uint32_t LinkFrame::CalcFrameSize(uint8_t dataLength) +{ + return LPDU_HEADER_SIZE + CalcUserDataSize(dataLength); +} + +uint32_t LinkFrame::CalcUserDataSize(uint8_t dataLength) +{ + if (dataLength > 0) + { + uint32_t mod16 = dataLength % LPDU_DATA_BLOCK_SIZE; + uint32_t size = (dataLength / LPDU_DATA_BLOCK_SIZE) * LPDU_DATA_PLUS_CRC_SIZE; //complete blocks + return (mod16 > 0) ? (size + mod16 + LPDU_CRC_SIZE) : size; //possible partial block + } + else + { + return 0; + } +} + +//////////////////////////////////////////////// +// +// Outgoing frame formatting functions for Sec to Pri transactions +// +//////////////////////////////////////////////// + +RSlice LinkFrame::FormatAck(WSlice& buffer, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, false, aIsRcvBuffFull, LinkFunction::SEC_ACK, aDest, aSrc, pLogger); +} + +RSlice LinkFrame::FormatNack(WSlice& buffer, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, false, aIsRcvBuffFull, LinkFunction::SEC_NACK, aDest, aSrc, pLogger); +} + +RSlice LinkFrame::FormatLinkStatus(WSlice& buffer, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, false, aIsRcvBuffFull, LinkFunction::SEC_LINK_STATUS, aDest, aSrc, pLogger); +} + +RSlice LinkFrame::FormatNotSupported(WSlice& buffer, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, false, aIsRcvBuffFull, LinkFunction::SEC_NOT_SUPPORTED, aDest, aSrc, pLogger); +} + +//////////////////////////////////////////////// +// +// Outgoing frame formatting functions for Pri to Sec transactions +// +//////////////////////////////////////////////// + +RSlice LinkFrame::FormatResetLinkStates(WSlice& buffer, bool aIsMaster, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, false, false, LinkFunction::PRI_RESET_LINK_STATES, aDest, aSrc, pLogger); +} + +RSlice LinkFrame::FormatRequestLinkStatus(WSlice& buffer, bool aIsMaster, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, false, false, LinkFunction::PRI_REQUEST_LINK_STATUS, aDest, aSrc, pLogger); +} + +RSlice LinkFrame::FormatTestLinkStatus(WSlice& buffer, bool aIsMaster, bool aFcb, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + return FormatHeader(buffer, 0, aIsMaster, aFcb, true, LinkFunction::PRI_TEST_LINK_STATES, aDest, aSrc, pLogger); +} + +RSlice LinkFrame::FormatConfirmedUserData(WSlice& buffer, bool aIsMaster, bool aFcb, uint16_t aDest, uint16_t aSrc, const uint8_t* apData, uint8_t dataLength, openpal::Logger* pLogger) +{ + assert(dataLength > 0); + assert(dataLength <= LPDU_MAX_USER_DATA_SIZE); + auto userDataSize = CalcUserDataSize(dataLength); + auto ret = buffer.ToRSlice().Take(userDataSize + LPDU_HEADER_SIZE); + FormatHeader(buffer, dataLength, aIsMaster, aFcb, true, LinkFunction::PRI_CONFIRMED_USER_DATA, aDest, aSrc, pLogger); + WriteUserData(apData, buffer, dataLength); + buffer.Advance(userDataSize); + return ret; +} + +RSlice LinkFrame::FormatUnconfirmedUserData(WSlice& buffer, bool aIsMaster, uint16_t aDest, uint16_t aSrc, const uint8_t* apData, uint8_t dataLength, openpal::Logger* pLogger) +{ + assert(dataLength > 0); + assert(dataLength <= LPDU_MAX_USER_DATA_SIZE); + auto userDataSize = CalcUserDataSize(dataLength); + auto ret = buffer.ToRSlice().Take(userDataSize + LPDU_HEADER_SIZE); + FormatHeader(buffer, dataLength, aIsMaster, false, false, LinkFunction::PRI_UNCONFIRMED_USER_DATA, aDest, aSrc, pLogger); + WriteUserData(apData, buffer, dataLength); + buffer.Advance(userDataSize); + return ret; +} + +RSlice LinkFrame::FormatHeader(WSlice& buffer, uint8_t aDataLength, bool aIsMaster, bool aFcb, bool aFcvDfc, LinkFunction aFuncCode, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger) +{ + assert(buffer.Size() >= LPDU_HEADER_SIZE); + LinkHeader header(aDataLength + LPDU_MIN_LENGTH, aSrc, aDest, aIsMaster, aFcvDfc, aFcb, aFuncCode); + + FORMAT_LOGGER_BLOCK(pLogger, flags::LINK_TX, + "Function: %s Dest: %u Source: %u Length: %u", + LinkFunctionToString(aFuncCode), + aDest, + aSrc, + aDataLength); + + header.Write(buffer); + auto ret = buffer.ToRSlice().Take(10); + buffer.Advance(10); + return ret; +} + +void LinkFrame::WriteUserData(const uint8_t* pSrc, uint8_t* pDest, uint8_t length) +{ + while (length > 0) + { + uint8_t max = LPDU_DATA_BLOCK_SIZE; + uint8_t num = length > max ? max : length; + memcpy(pDest, pSrc, num); + CRC::AddCrc(pDest, num); + pSrc += num; + pDest += (num + 2); + length -= num; + } +} + +} //end namespace + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.h new file mode 100644 index 0000000..940be86 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkFrame.h @@ -0,0 +1,99 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKFRAME_H +#define OPENDNP3_LINKFRAME_H + +#include "opendnp3/gen/FunctionCode.h" +#include "opendnp3/gen/LinkFunction.h" + +#include +#include +#include +#include + +namespace opendnp3 +{ + +class LinkFrame : private openpal::StaticOnly +{ + +public: + + //////////////////////////////////////////////// + // Functions for formatting outgoing Sec to Pri frames + //////////////////////////////////////////////// + + static openpal::RSlice FormatAck(openpal::WSlice& output, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + static openpal::RSlice FormatNack(openpal::WSlice& output, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + static openpal::RSlice FormatLinkStatus(openpal::WSlice& output, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + static openpal::RSlice FormatNotSupported(openpal::WSlice& output, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + + //////////////////////////////////////////////// + // Functions for formatting outgoing Pri to Sec frames + //////////////////////////////////////////////// + + static openpal::RSlice FormatTestLinkStatus(openpal::WSlice& output, bool aIsMaster, bool aFcb, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + static openpal::RSlice FormatResetLinkStates(openpal::WSlice& output, bool aIsMaster, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + static openpal::RSlice FormatRequestLinkStatus(openpal::WSlice& output, bool aIsMaster, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + static openpal::RSlice FormatConfirmedUserData(openpal::WSlice& output, bool aIsMaster, bool aFcb, uint16_t aDest, uint16_t aSrc, const uint8_t* apData, uint8_t aDataLength, openpal::Logger* pLogger); + static openpal::RSlice FormatUnconfirmedUserData(openpal::WSlice& output, bool aIsMaster, uint16_t aDest, uint16_t aSrc, const uint8_t* apData, uint8_t aDataLength, openpal::Logger* pLogger); + + //////////////////////////////////////////////// + // Reusable static formatting functions to any buffer + //////////////////////////////////////////////// + + /** Reads data from src to dest removing 2 byte CRC checks every 16 data bytes + @param apSrc Source buffer with crc checks. Must begin at data, not header + @param apDest Destination buffer to which the data is extracted + @param aLength Length of user data to read to the dest buffer. The source buffer must be larger b/c of crc bytes. + */ + static void ReadUserData(const uint8_t* apSrc, uint8_t* apDest, uint32_t aLength); + + /** Validates FT3 user data integriry + @param apBody Beginning of the FT3 user data + @param aLength Number of user bytes to verify, not user + crc. + @return True if the body CRC is correct */ + static bool ValidateBodyCRC(const uint8_t* apBody, uint32_t aLength); + + // @return Total frame size based on user data length + static uint32_t CalcFrameSize(uint8_t dataLength); + +private: + + static uint32_t CalcUserDataSize(uint8_t dataLength); + + + /** Writes data from src to dest interlacing 2 byte CRC checks every 16 data bytes + @param apSrc Source buffer full of user data + @param apDest Destination buffer where the data + CRC is written + @param length Number of user data bytes + */ + static void WriteUserData(const uint8_t* pSrc, uint8_t* pDest, uint8_t length); + + /** Write 10 header bytes to to buffer including 0x0564, all fields, and CRC */ + static openpal::RSlice FormatHeader(openpal::WSlice& output, uint8_t aDataLength, bool aIsMaster, bool aFcb, bool aFcvDfc, LinkFunction aCode, uint16_t aDest, uint16_t aSrc, openpal::Logger* pLogger); + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.cpp new file mode 100644 index 0000000..0aa8564 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.cpp @@ -0,0 +1,95 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkHeader.h" + +#include "CRC.h" + +#include + +using namespace std; + +namespace opendnp3 +{ + +LinkHeader::LinkHeader() : length(5), src(0), dest(0), ctrl(0) +{ + +} + +LinkHeader::LinkHeader(uint8_t aLen, uint16_t aSrc, uint16_t aDest, bool aFromMaster, bool aFcvDfc, bool aFcb, LinkFunction aCode) +{ + this->Set(aLen, aSrc, aDest, aFromMaster, aFcvDfc, aFcb, aCode); +} + +void LinkHeader::Set(uint8_t aLen, uint16_t aSrc, uint16_t aDest, bool aFromMaster, bool aFcvDfc, bool aFcb, LinkFunction aCode) +{ + length = aLen; + src = aSrc; + dest = aDest; + ctrl = ControlByte(aFromMaster, aFcb, aFcvDfc, aCode); +} + +void LinkHeader::ChangeFCB(bool aFCB) +{ + if(aFCB) + { + ctrl |= MASK_FCB; + } + else + { + ctrl &= ~MASK_FCB; + } +} + +uint8_t LinkHeader::ControlByte(bool aIsMaster, bool aFcb, bool aFcvDfc, LinkFunction aFunc) +{ + uint8_t ret = LinkFunctionToType(aFunc); + + if(aIsMaster) ret |= MASK_DIR; + if(aFcb) ret |= MASK_FCB; + if(aFcvDfc) ret |= MASK_FCV; + + return ret; +} + +void LinkHeader::Read(const uint8_t* apBuff) +{ + length = apBuff[LI_LENGTH]; + dest = openpal::UInt16::Read(apBuff + LI_DESTINATION); + src = openpal::UInt16::Read(apBuff + LI_SOURCE); + ctrl = apBuff[LI_CONTROL]; +} + +void LinkHeader::Write(uint8_t* apBuff) const +{ + apBuff[LI_START_05] = 0x05; + apBuff[LI_START_64] = 0x64; + + apBuff[LI_LENGTH] = length; + openpal::UInt16::Write(apBuff + LI_DESTINATION, dest); + openpal::UInt16::Write(apBuff + LI_SOURCE, src); + apBuff[LI_CONTROL] = ctrl; + + CRC::AddCrc(apBuff, LI_CRC); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.h new file mode 100644 index 0000000..16e8736 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeader.h @@ -0,0 +1,114 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKHEADER_H +#define OPENDNP3_LINKHEADER_H + +#include "LinkLayerConstants.h" + +#include "opendnp3/gen/LinkFunction.h" + +namespace opendnp3 +{ + +// Class for dealing with all aspects of FT3 Frame headers +struct LinkHeader +{ + LinkHeader(); + + LinkHeader(uint8_t len, uint16_t src, uint16_t dest, bool isFromMaster, bool fcvdfc, bool fcb, LinkFunction func); + + // Setter + + void Set(uint8_t len, uint16_t src, uint16_t dest, bool isFromMaster, bool fcvdfc, bool fcb, LinkFunction func); + + void ChangeFCB(bool aFCB); + + uint8_t GetControl() const + { + return ctrl; + } + + // Getters + uint8_t GetLength() const + { + return length; + } + uint16_t GetDest() const + { + return dest; + } + uint16_t GetSrc() const + { + return src; + } + bool IsFromMaster() const + { + return (ctrl & MASK_DIR) != 0; + } + bool IsPriToSec() const + { + return (ctrl & MASK_PRM) != 0; + } + bool IsFcbSet() const + { + return (ctrl & MASK_FCB) != 0; + } + bool IsFcvDfcSet() const + { + return (ctrl & MASK_FCV) != 0; + } + uint8_t GetFuncByte() const + { + return ctrl & MASK_FUNC; + } + LinkFunction GetFuncEnum() const + { + return LinkFunctionFromType(ctrl & MASK_FUNC_OR_PRM); + } + + bool ValidLength() + { + return length > 4; + } + + /** Reads the header, setting all the fields. Does NOT validate 0x0564 or CRC + @param apBuff Buffer of at least 10 bytes */ + void Read(const uint8_t* data); + + /** Writes header to buffer including, 0x0564 and CRC + @param apBuff Buffer of at least 10 bytes */ + void Write(uint8_t* dest) const; + + static uint8_t ControlByte(bool isMaster, bool fcb, bool fcvdfc, LinkFunction func); + +private: + + // Fields read directly from the header + uint8_t length; // Length of field, range [5,255] valid + uint16_t src; // Where the frame originated + uint16_t dest; // Where the frame is going + uint8_t ctrl; // Control octet, individual fields accessed using accessors below +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeaderFields.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeaderFields.cpp new file mode 100644 index 0000000..a493ef0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkHeaderFields.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/link/LinkHeaderFields.h" + +namespace opendnp3 +{ +LinkHeaderFields::LinkHeaderFields() : + func(LinkFunction::INVALID), + isFromMaster(false), + fcb(false), + fcvdfc(false), + dest(0), + src(0) +{} + +LinkHeaderFields::LinkHeaderFields(LinkFunction func_, bool isMaster_, bool fcb_, bool fcvdfc_, uint16_t dest_, uint16_t src_) : + func(func_), + isFromMaster(isMaster_), + fcb(fcb_), + fcvdfc(fcvdfc_), + dest(dest_), + src(src_) +{} +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.cpp new file mode 100644 index 0000000..2af180b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.cpp @@ -0,0 +1,102 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkLayer.h" + +using namespace openpal; + +namespace opendnp3 +{ + +LinkLayer::LinkLayer(const openpal::Logger& logger, const std::shared_ptr& executor, const std::shared_ptr& upper, const std::shared_ptr& listener, const LinkConfig& config) : + ctx(logger, executor, upper, listener, *this, config) +{} + +const StackStatistics::Link& LinkLayer::GetStatistics() const +{ + return this->ctx.statistics; +} + +void LinkLayer::SetRouter(ILinkTx& router) +{ + assert(ctx.linktx == nullptr); + ctx.linktx = &router; +} + +//////////////////////////////// +// ILowerLayer +//////////////////////////////// + +bool LinkLayer::Send(ITransportSegment& segments) +{ + if (!ctx.isOnline) return false; + + if (ctx.SetTxSegment(segments)) + { + ctx.TryStartTransmission(); + } + + return true; +} + +//////////////////////////////// +// ILinkSession +//////////////////////////////// + +bool LinkLayer::OnLowerLayerUp() +{ + return ctx.OnLowerLayerUp(); +} + +bool LinkLayer::OnLowerLayerDown() +{ + return ctx.OnLowerLayerDown(); +} + +bool LinkLayer::OnTransmitResult(bool success) +{ + auto ret = ctx.OnTransmitResult(success); + + if (ret) + { + ctx.TryStartTransmission(); + } + + return true; +} + +//////////////////////////////// +// IFrameSink +//////////////////////////////// + +bool LinkLayer::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + auto ret = this->ctx.OnFrame(header, userdata); + + if (ret) + { + this->ctx.TryStartTransmission(); + } + + return ret; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.h new file mode 100644 index 0000000..cda5536 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayer.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKLAYER_H +#define OPENDNP3_LINKLAYER_H + +#include "LinkContext.h" + +namespace opendnp3 +{ + +// @section desc Implements the contextual state of DNP3 Data Link Layer +class LinkLayer final : public ILinkLayer, public ILinkSession +{ + +public: + + LinkLayer(const openpal::Logger& logger, const std::shared_ptr&, const std::shared_ptr& upper, const std::shared_ptr&, const LinkConfig&); + + void SetRouter(ILinkTx&); + + // ---- Events from below: ILinkSession / IFrameSink ---- + + virtual bool OnLowerLayerUp() override; + virtual bool OnLowerLayerDown() override; + virtual bool OnTransmitResult(bool success) override; + virtual bool OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) override; + + // ---- Events from above: ILinkLayer ---- + + virtual bool Send(ITransportSegment& segments) override; + + const StackStatistics::Link& GetStatistics() const; + +private: + + // The full state + LinkContext ctx; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerConstants.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerConstants.h new file mode 100644 index 0000000..aebd7b5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerConstants.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKLAYERCONSTANTS_H +#define OPENDNP3_LINKLAYERCONSTANTS_H + +#include + +namespace opendnp3 +{ + +const uint8_t LPDU_MIN_LENGTH = 5; +const uint8_t LPDU_MAX_LENGTH = 255; +const uint8_t LPDU_HEADER_SIZE = 10; +const uint8_t LPDU_DATA_BLOCK_SIZE = 16; +const uint8_t LPDU_CRC_SIZE = 2; +const uint8_t LPDU_DATA_PLUS_CRC_SIZE = 18; +const uint8_t LPDU_MAX_USER_DATA_SIZE = 250; +const uint16_t LPDU_MAX_FRAME_SIZE = 292; //10(header) + 250 (user data) + 32 (block CRC's) = 292 frame bytes + + +/// Indices for use with buffers containing link headers +enum LinkHeaderIndex : uint8_t +{ + LI_START_05 = 0, + LI_START_64 = 1, + LI_LENGTH = 2, + LI_CONTROL = 3, + LI_DESTINATION = 4, + LI_SOURCE = 6, + LI_CRC = 8 +}; + +/// Masks for use with the CONTROL byte +enum ControlMask : uint8_t +{ + MASK_DIR = 0x80, + MASK_PRM = 0x40, + MASK_FCB = 0x20, + MASK_FCV = 0x10, + MASK_FUNC = 0x0F, + MASK_FUNC_OR_PRM = MASK_PRM | MASK_FUNC +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.cpp new file mode 100644 index 0000000..3f39777 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.cpp @@ -0,0 +1,342 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkLayerParser.h" + +#include "opendnp3/link/CRC.h" +#include "opendnp3/link/IFrameSink.h" + +#include "opendnp3/LogLevels.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +LinkLayerParser::LinkLayerParser(const Logger& logger) : + logger(logger), + state(State::FindSync), + frameSize(0), + buffer(rxBuffer, LPDU_MAX_FRAME_SIZE) +{ + +} + +void LinkLayerParser::Reset() +{ + state = State::FindSync; + frameSize = 0; + buffer.Reset(); +} + +WSlice LinkLayerParser::WriteBuff() const +{ + return WSlice(buffer.WriteBuff(), buffer.NumWriteBytes()); +} + +void LinkLayerParser::OnRead(uint32_t numBytes, IFrameSink& sink) +{ + buffer.AdvanceWrite(numBytes); + + while (ParseUntilComplete() == State::Complete) + { + ++statistics.numLinkFrameRx; + this->PushFrame(sink); + state = State::FindSync; + } + + buffer.Shift(); +} + +LinkLayerParser::State LinkLayerParser::ParseUntilComplete() +{ + auto lastState = this->state; + // continue as long as we're making progress, i.e. a state change + while ((this->state = ParseOneStep()) != lastState) + { + lastState = state; + } + return state; +} + +LinkLayerParser::State LinkLayerParser::ParseOneStep() +{ + switch (state) + { + case(State::FindSync) : + return ParseSync(); + case(State::ReadHeader) : + return ParseHeader(); + case(State::ReadBody) : + return ParseBody(); + default: + return state; + } +} + +LinkLayerParser::State LinkLayerParser::ParseSync() +{ + if (this->buffer.NumBytesRead() >= 10)// && buffer.Sync()) + { + uint32_t skipCount = 0; + const auto synced = buffer.Sync(skipCount); + if (skipCount > 0) + { + FORMAT_LOG_BLOCK(logger, flags::WARN, "Skipped %u bytes seaching for start bytes", skipCount); + } + + return synced ? State::ReadHeader : State::FindSync; + } + else + { + return State::FindSync; + } +} + +LinkLayerParser::State LinkLayerParser::ParseHeader() +{ + if (this->buffer.NumBytesRead() >= 10) + { + if (this->ReadHeader()) + { + return State::ReadBody; + } + else + { + this->FailFrame(); + return State::FindSync; + } + } + else + { + return State::ReadHeader; + } +} + +LinkLayerParser::State LinkLayerParser::ParseBody() +{ + if (buffer.NumBytesRead() < this->frameSize) + { + return State::ReadBody; + } + else + { + if(this->ValidateBody()) + { + this->TransferUserData(); + return State::Complete; + } + else + { + this->FailFrame(); + return State::FindSync; + } + } +} + + + +void LinkLayerParser::PushFrame(IFrameSink& sink) +{ + LinkHeaderFields fields( + header.GetFuncEnum(), + header.IsFromMaster(), + header.IsFcbSet(), + header.IsFcvDfcSet(), + header.GetDest(), + header.GetSrc() + ); + + sink.OnFrame(fields, userData); + + buffer.AdvanceRead(frameSize); +} + +void LinkLayerParser::TransferUserData() +{ + uint32_t len = header.GetLength() - LPDU_MIN_LENGTH; + LinkFrame::ReadUserData(buffer.ReadBuffer() + LPDU_HEADER_SIZE, rxBuffer, len); + userData = RSlice(rxBuffer, len); +} + +bool LinkLayerParser::ReadHeader() +{ + header.Read(buffer.ReadBuffer()); + if (CRC::IsCorrectCRC(buffer.ReadBuffer(), LI_CRC)) + { + if (ValidateHeaderParameters()) + { + return true; + } + else + { + return false; + } + } + else + { + ++statistics.numHeaderCrcError; + SIMPLE_LOG_BLOCK(logger, flags::WARN, "CRC failure in header"); + return false; + } +} + +bool LinkLayerParser::ValidateBody() +{ + uint32_t len = header.GetLength() - LPDU_MIN_LENGTH; + if (LinkFrame::ValidateBodyCRC(buffer.ReadBuffer() + LPDU_HEADER_SIZE, len)) + { + FORMAT_LOG_BLOCK(logger, flags::LINK_RX, + "Function: %s Dest: %u Source: %u Length: %u", + LinkFunctionToString(header.GetFuncEnum()), + header.GetDest(), + header.GetSrc(), + header.GetLength()); + + FORMAT_HEX_BLOCK(logger, flags::LINK_RX_HEX, buffer.ReadBuffer().Take(frameSize), 10, 18); + + return true; + } + else + { + ++this->statistics.numBodyCrcError; + SIMPLE_LOG_BLOCK(logger, flags::ERR, "CRC failure in body"); + return false; + } +} + +bool LinkLayerParser::ValidateHeaderParameters() +{ + if(!header.ValidLength()) + { + ++statistics.numBadLength; + FORMAT_LOG_BLOCK(logger, flags::ERR, "LENGTH out of range [5,255]: %i", header.GetLength()); + return false; + } + + //Now make sure that the function code is known and that the FCV is appropriate + if (!this->ValidateFunctionCode()) + { + return false; + } + + uint8_t user_data_length = header.GetLength() - LPDU_MIN_LENGTH; + frameSize = LinkFrame::CalcFrameSize(user_data_length); + LinkFunction func = header.GetFuncEnum(); + + const bool has_payload = user_data_length > 0; + const bool should_have_payload = (func == LinkFunction::PRI_CONFIRMED_USER_DATA || func == LinkFunction::PRI_UNCONFIRMED_USER_DATA); + + // make sure that the presence/absence of user data matches the function code + if(should_have_payload && !has_payload) + { + ++statistics.numBadLength; + FORMAT_LOG_BLOCK(logger, flags::ERR, "User data with no payload. FUNCTION: %s", LinkFunctionToString(func)); + return false; + } + + if (!should_have_payload && has_payload) + { + ++statistics.numBadLength; + FORMAT_LOG_BLOCK(logger, flags::ERR, "Unexpected LENGTH in frame: %i with FUNCTION: %s", user_data_length, LinkFunctionToString(func)); + return false; + } + + // calculate the total frame size + frameSize = LinkFrame::CalcFrameSize(user_data_length); + + return true; +} + +void LinkLayerParser::FailFrame() +{ + // All you have to do is advance the reader by one, when the resync happens the data will disappear + buffer.AdvanceRead(1); +} + +bool LinkLayerParser::ValidateFunctionCode() +{ + //Now make sure that the function code is known and that the FCV is appropriate + if(header.IsPriToSec()) + { + bool fcv_set = false; + + switch(header.GetFuncEnum()) + { + case(LinkFunction::PRI_CONFIRMED_USER_DATA): + case(LinkFunction::PRI_TEST_LINK_STATES): + fcv_set = true; + break; + case(LinkFunction::PRI_REQUEST_LINK_STATUS): + case(LinkFunction::PRI_RESET_LINK_STATES): + case(LinkFunction::PRI_UNCONFIRMED_USER_DATA): + break; + default: + { + ++statistics.numBadFunctionCode; + FORMAT_LOG_BLOCK(logger, flags::WARN, "Unknown PriToSec FUNCTION: %s", LinkFunctionToString(header.GetFuncEnum())); + return false; + } + } + + //now check the fcv + if(fcv_set != header.IsFcvDfcSet()) + { + ++statistics.numBadFCV; + FORMAT_LOG_BLOCK(logger, flags::WARN, "Bad FCV for FUNCTION: %s", LinkFunctionToString(header.GetFuncEnum())); + return false; + } + + //if fcv isn't expected to be set, fcb can be either 1 or 0, doesn't matter + + } + else // SecToPri - just validate the function codes and that FCB is 0 + { + switch(header.GetFuncEnum()) + { + case(LinkFunction::SEC_ACK): + case(LinkFunction::SEC_NACK): + case(LinkFunction::SEC_LINK_STATUS): + case(LinkFunction::SEC_NOT_SUPPORTED): + break; + default: + { + ++statistics.numBadFunctionCode; + FORMAT_LOG_BLOCK(logger, flags::ERR, "Unknown SecToPri FUNCTION: %s", LinkFunctionToString(header.GetFuncEnum())); + return false; + } + } + + //now check the fcb, it should always be zero + if(header.IsFcbSet()) + { + ++statistics.numBadFCB; + FORMAT_LOG_BLOCK(logger, flags::ERR, "FCB set for SecToPri FUNCTION: %s", LinkFunctionToString(header.GetFuncEnum())); + return false; + } + } + + return true; //valid! +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.h new file mode 100644 index 0000000..7cda662 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/LinkLayerParser.h @@ -0,0 +1,107 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINKLAYERPARSER_H +#define OPENDNP3_LINKLAYERPARSER_H + + +#include +#include + +#include "opendnp3/link/ShiftableBuffer.h" +#include "opendnp3/link/LinkFrame.h" +#include "opendnp3/link/LinkHeader.h" +#include "opendnp3/link/LinkStatistics.h" +#include "opendnp3/link/IFrameSink.h" + +namespace opendnp3 +{ + +/// Parses FT3 frames +class LinkLayerParser +{ + enum class State + { + FindSync, + ReadHeader, + ReadBody, + Complete + }; + +public: + + /// @param logger_ Logger that the receiver is to use. + /// @param pSink_ Completely parsed frames are sent to this interface + LinkLayerParser(const openpal::Logger& logger); + + /// Called when valid data has been written to the current buffer write position + /// Parses the new data and calls the specified frame sink + /// @param numBytes Number of bytes written + void OnRead(uint32_t numBytes, IFrameSink& sink); + + /// @return Buffer that can currently be used for writing + openpal::WSlice WriteBuff() const; + + /// Resets the state of parser + void Reset(); + + const LinkStatistics::Parser& Statistics() const + { + return this->statistics; + } + +private: + + State ParseUntilComplete(); + State ParseOneStep(); + State ParseSync(); + State ParseHeader(); + State ParseBody(); + + void PushFrame(IFrameSink& sink); + + bool ReadHeader(); + bool ValidateBody(); + bool ValidateHeaderParameters(); + bool ValidateFunctionCode(); + void FailFrame(); + + void TransferUserData(); + + openpal::Logger logger; + LinkStatistics::Parser statistics; + + LinkHeader header; + + State state; + uint32_t frameSize; + openpal::RSlice userData; + + // buffer where received data is written + uint8_t rxBuffer[LPDU_MAX_FRAME_SIZE]; + + // facade over the rxBuffer that provides ability to "shift" as data is read + ShiftableBuffer buffer; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.cpp new file mode 100644 index 0000000..173793c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.cpp @@ -0,0 +1,359 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "PriLinkLayerStates.h" + +#include + +#include "opendnp3/link/LinkLayer.h" +#include "opendnp3/LogLevels.h" + +using namespace openpal; + +namespace opendnp3 +{ + +//////////////////////////////////////// +// PriStateBase +//////////////////////////////////////// + +PriStateBase& PriStateBase::OnAck(LinkContext& ctx, bool rxBuffFull) +{ + ++ctx.statistics.numUnexpectedFrame; + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Frame context not understood"); + return *this; +} + +PriStateBase& PriStateBase::OnNack(LinkContext& ctx, bool rxBuffFull) +{ + ++ctx.statistics.numUnexpectedFrame; + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Frame context not understood"); + return *this; +} + +PriStateBase& PriStateBase::OnLinkStatus(LinkContext& ctx, bool rxBuffFull) +{ + ++ctx.statistics.numUnexpectedFrame; + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Frame context not understood"); + return *this; +} + +PriStateBase& PriStateBase::OnNotSupported(LinkContext& ctx, bool rxBuffFull) +{ + ++ctx.statistics.numUnexpectedFrame; + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Frame context not understood"); + return *this; +} + +PriStateBase& PriStateBase::OnTransmitResult(LinkContext& ctx, bool success) +{ + FORMAT_LOG_BLOCK(ctx.logger, flags::ERR, "Invalid action for state: %s", this->Name()); + return *this; +} + +PriStateBase& PriStateBase::OnTimeout(LinkContext& ctx) +{ + FORMAT_LOG_BLOCK(ctx.logger, flags::ERR, "Invalid action for state: %s", this->Name()); + return *this; +} + +PriStateBase& PriStateBase::TrySendConfirmed(LinkContext& ctx, ITransportSegment&) +{ + return *this; +} + +PriStateBase& PriStateBase::TrySendUnconfirmed(LinkContext& ctx, ITransportSegment&) +{ + return *this; +} + +PriStateBase& PriStateBase::TrySendRequestLinkStatus(LinkContext&) +{ + return *this; +} + +//////////////////////////////////////////////////////// +// Class PLLS_SecNotResetIdle +//////////////////////////////////////////////////////// + +PLLS_Idle PLLS_Idle::instance; + +PriStateBase& PLLS_Idle::TrySendUnconfirmed(LinkContext& ctx, ITransportSegment& segments) +{ + auto first = segments.GetSegment(); + auto output = ctx.FormatPrimaryBufferWithUnconfirmed(first); + ctx.QueueTransmit(output, true); + return PLLS_SendUnconfirmedTransmitWait::Instance(); +} + +PriStateBase& PLLS_Idle::TrySendConfirmed(LinkContext& ctx, ITransportSegment& segments) +{ + if (ctx.isRemoteReset) + { + ctx.ResetRetry(); + auto buffer = ctx.FormatPrimaryBufferWithConfirmed(segments.GetSegment(), ctx.nextWriteFCB); + ctx.QueueTransmit(buffer, true); + return PLLS_ConfUserDataTransmitWait::Instance(); + } + else + { + ctx.ResetRetry(); + ctx.QueueResetLinks(); + return PLLS_LinkResetTransmitWait::Instance(); + } +} + +PriStateBase& PLLS_Idle::TrySendRequestLinkStatus(LinkContext& ctx) +{ + ctx.keepAliveTimeout = false; + ctx.QueueRequestLinkStatus(); + ctx.listener->OnKeepAliveInitiated(); + return PLLS_RequestLinkStatusTransmitWait::Instance(); +} + +//////////////////////////////////////////////////////// +// Class SendUnconfirmedTransmitWait +//////////////////////////////////////////////////////// + +PLLS_SendUnconfirmedTransmitWait PLLS_SendUnconfirmedTransmitWait::instance; + +PriStateBase& PLLS_SendUnconfirmedTransmitWait::OnTransmitResult(LinkContext& ctx, bool success) +{ + if (ctx.pSegments->Advance()) + { + auto output = ctx.FormatPrimaryBufferWithUnconfirmed(ctx.pSegments->GetSegment()); + ctx.QueueTransmit(output, true); + return *this; + } + else // we're done + { + ctx.CompleteSendOperation(success); + return PLLS_Idle::Instance(); + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Wait for the link layer to transmit the reset links +///////////////////////////////////////////////////////////////////////////// + +PLLS_LinkResetTransmitWait PLLS_LinkResetTransmitWait::instance; + +PriStateBase& PLLS_LinkResetTransmitWait::OnTransmitResult(LinkContext& ctx, bool success) +{ + if (success) + { + // now we're waiting for an ACK + ctx.StartResponseTimer(); + return PLLS_ResetLinkWait::Instance(); + } + else + { + ctx.CompleteSendOperation(success); + return PLLS_Idle::Instance(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// Wait for the link layer to transmit confirmed user data +///////////////////////////////////////////////////////////////////////////// + +PLLS_ConfUserDataTransmitWait PLLS_ConfUserDataTransmitWait::instance; + +PriStateBase& PLLS_ConfUserDataTransmitWait::OnTransmitResult(LinkContext& ctx, bool success) +{ + if (success) + { + // now we're waiting on an ACK + ctx.StartResponseTimer(); + return PLLS_ConfDataWait::Instance(); + } + else + { + ctx.CompleteSendOperation(false); + return PLLS_Idle::Instance(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// Wait for the link layer to transmit the request link status +///////////////////////////////////////////////////////////////////////////// + +PLLS_RequestLinkStatusTransmitWait PLLS_RequestLinkStatusTransmitWait::instance; + +PriStateBase& PLLS_RequestLinkStatusTransmitWait::OnTransmitResult(LinkContext& ctx, bool success) +{ + if (success) + { + // now we're waiting on a LINK_STATUS + ctx.StartResponseTimer(); + return PLLS_RequestLinkStatusWait::Instance(); + } + else + { + ctx.FailKeepAlive(false); + return PLLS_Idle::Instance(); + } +} + + +//////////////////////////////////////////////////////// +// Class PLLS_ResetLinkWait +//////////////////////////////////////////////////////// + +PLLS_ResetLinkWait PLLS_ResetLinkWait::instance; + +PriStateBase& PLLS_ResetLinkWait::OnAck(LinkContext& ctx, bool rxBuffFull) +{ + ctx.isRemoteReset = true; + ctx.ResetWriteFCB(); + ctx.CancelTimer(); + auto buffer = ctx.FormatPrimaryBufferWithConfirmed(ctx.pSegments->GetSegment(), ctx.nextWriteFCB); + ctx.QueueTransmit(buffer, true); + ctx.listener->OnStateChange(opendnp3::LinkStatus::RESET); + return PLLS_ConfUserDataTransmitWait::Instance(); +} + +PriStateBase& PLLS_ResetLinkWait::OnTimeout(LinkContext& ctx) +{ + if(ctx.Retry()) + { + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "Link reset timeout, retrying %i remaining", ctx.numRetryRemaining); + ctx.QueueResetLinks(); + return PLLS_LinkResetTransmitWait::Instance(); + } + else + { + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Link reset final timeout, no retries remain"); + ctx.CompleteSendOperation(false); + return PLLS_Idle::Instance(); + } +} + +PriStateBase& PLLS_ResetLinkWait::Failure(LinkContext& ctx) +{ + ctx.CancelTimer(); + ctx.CompleteSendOperation(false); + return PLLS_Idle::Instance(); +} + +//////////////////////////////////////////////////////// +// Class PLLS_ConfDataWait +//////////////////////////////////////////////////////// + +PLLS_ConfDataWait PLLS_ConfDataWait::instance; + +PriStateBase& PLLS_ConfDataWait::OnAck(LinkContext& ctx, bool rxBuffFull) +{ + ctx.ToggleWriteFCB(); + ctx.CancelTimer(); + + if (ctx.pSegments->Advance()) + { + auto buffer = ctx.FormatPrimaryBufferWithConfirmed(ctx.pSegments->GetSegment(), ctx.nextWriteFCB); + ctx.QueueTransmit(buffer, true); + return PLLS_ConfUserDataTransmitWait::Instance(); + } + else //we're done! + { + ctx.CompleteSendOperation(true); + return PLLS_Idle::Instance(); + } +} + +PriStateBase& PLLS_ConfDataWait::OnNack(LinkContext& ctx, bool rxBuffFull) +{ + ctx.listener->OnStateChange(opendnp3::LinkStatus::UNRESET); + + if (rxBuffFull) + { + return Failure(ctx); + } + else + { + ctx.ResetRetry(); + ctx.CancelTimer(); + ctx.QueueResetLinks(); + return PLLS_LinkResetTransmitWait::Instance(); + } + +} + +PriStateBase& PLLS_ConfDataWait::Failure(LinkContext& ctx) +{ + ctx.CancelTimer(); + ctx.CompleteSendOperation(false); + return PLLS_Idle::Instance(); +} + +PriStateBase& PLLS_ConfDataWait::OnTimeout(LinkContext& ctx) +{ + if (ctx.Retry()) + { + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "confirmed data timeout, retrying %u remaining", ctx.numRetryRemaining); + auto buffer = ctx.FormatPrimaryBufferWithConfirmed(ctx.pSegments->GetSegment(), ctx.nextWriteFCB); + ctx.QueueTransmit(buffer, true); + return PLLS_ConfUserDataTransmitWait::Instance(); + } + else + { + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Confirmed data final timeout, no retries remain"); + ctx.listener->OnStateChange(opendnp3::LinkStatus::UNRESET); + ctx.CompleteSendOperation(false); + return PLLS_Idle::Instance(); + } +} + +//////////////////////////////////////////////////////// +// Class PLLS_RequestLinkStatusWait +//////////////////////////////////////////////////////// + +PLLS_RequestLinkStatusWait PLLS_RequestLinkStatusWait::instance; + +PriStateBase& PLLS_RequestLinkStatusWait::OnNack(LinkContext& ctx, bool) +{ + ctx.CancelTimer(); + ctx.FailKeepAlive(false); + return PLLS_Idle::Instance(); +} + +PriStateBase& PLLS_RequestLinkStatusWait::OnLinkStatus(LinkContext& ctx, bool) +{ + ctx.CancelTimer(); + ctx.CompleteKeepAlive(); + return PLLS_Idle::Instance(); +} + +PriStateBase& PLLS_RequestLinkStatusWait::OnNotSupported(LinkContext& ctx, bool) +{ + ctx.CancelTimer(); + ctx.FailKeepAlive(false); + return PLLS_Idle::Instance(); +} + +PriStateBase& PLLS_RequestLinkStatusWait::OnTimeout(LinkContext& ctx) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Link status request - response timeout"); + ctx.FailKeepAlive(true); + return PLLS_Idle::Instance(); +} + +} //end namepsace + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.h new file mode 100644 index 0000000..122bc68 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/PriLinkLayerStates.h @@ -0,0 +1,186 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_PRILINKLAYERSTATES_H +#define OPENDNP3_PRILINKLAYERSTATES_H + +#include "opendnp3/link/Singleton.h" + +namespace opendnp3 +{ + +class LinkContext; +class ITransportSegment; + + +class PriStateBase +{ +public: + + // Incoming messages for primary station + virtual PriStateBase& OnAck(LinkContext&, bool receiveBuffFull); + virtual PriStateBase& OnNack(LinkContext&, bool receiveBuffFull); + virtual PriStateBase& OnLinkStatus(LinkContext&, bool receiveBuffFull); + virtual PriStateBase& OnNotSupported(LinkContext&, bool receiveBuffFull); + + virtual PriStateBase& OnTransmitResult(LinkContext&, bool success); + + virtual PriStateBase& OnTimeout(LinkContext&); + + // transmission events to handle + virtual PriStateBase& TrySendConfirmed(LinkContext&, ITransportSegment& segments); + virtual PriStateBase& TrySendUnconfirmed(LinkContext&, ITransportSegment& segments); + virtual PriStateBase& TrySendRequestLinkStatus(LinkContext&); + + //every concrete state implements this for logging purposes + virtual char const* Name() const = 0; +}; + +// @section desc Entry state for primary station +class PLLS_Idle final : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_Idle); + + virtual PriStateBase& TrySendUnconfirmed(LinkContext&, ITransportSegment& segments) override; + virtual PriStateBase& TrySendConfirmed(LinkContext&, ITransportSegment& segments) override; + virtual PriStateBase& TrySendRequestLinkStatus(LinkContext&) override; +}; + + +///////////////////////////////////////////////////////////////////////////// +// template wait state for send unconfirmed data +///////////////////////////////////////////////////////////////////////////// + +class PLLS_SendUnconfirmedTransmitWait : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_SendUnconfirmedTransmitWait); + + virtual PriStateBase& OnTransmitResult(LinkContext& link, bool success) override; +}; + + +///////////////////////////////////////////////////////////////////////////// +// Wait for the link layer to transmit the reset links +///////////////////////////////////////////////////////////////////////////// + +class PLLS_LinkResetTransmitWait : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_LinkResetTransmitWait); + + virtual PriStateBase& OnTransmitResult(LinkContext& link, bool success) override; +}; + +///////////////////////////////////////////////////////////////////////////// +// Wait for the link layer to transmit confirmed user data +///////////////////////////////////////////////////////////////////////////// + +class PLLS_ConfUserDataTransmitWait : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_ConfUserDataTransmitWait); + + virtual PriStateBase& OnTransmitResult(LinkContext& link, bool success) override; +}; + +///////////////////////////////////////////////////////////////////////////// +// Wait for the link layer to transmit confirmed user data +///////////////////////////////////////////////////////////////////////////// + +class PLLS_RequestLinkStatusTransmitWait : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_RequestLinkStatusTransmitWait); + + virtual PriStateBase& OnTransmitResult(LinkContext& link, bool success) override; +}; + +///////////////////////////////////////////////////////////////////////////// +// Waiting for a ACK to reset the link +///////////////////////////////////////////////////////////////////////////// + +// @section desc As soon as we get an ACK, send the delayed pri frame +class PLLS_ResetLinkWait final : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_ResetLinkWait); + + PriStateBase& OnAck(LinkContext&, bool aIsRcvBuffFull) override; + + PriStateBase& OnNack(LinkContext& link, bool) override + { + return Failure(link); + } + PriStateBase& OnLinkStatus(LinkContext& link, bool) override + { + return Failure(link); + } + PriStateBase& OnNotSupported(LinkContext& link, bool) override + { + return Failure(link); + } + + PriStateBase& OnTimeout(LinkContext&) override; + +private: + PriStateBase& Failure(LinkContext&); +}; + +///////////////////////////////////////////////////////////////////////////// +// Waiting for a ACK to user data +///////////////////////////////////////////////////////////////////////////// + +// @section desc As soon as we get an ACK, send the delayed pri frame +class PLLS_ConfDataWait final : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_ConfDataWait); + + PriStateBase& OnAck(LinkContext&, bool aIsRcvBuffFull) override; + PriStateBase& OnNack(LinkContext& link, bool) override; + PriStateBase& OnLinkStatus(LinkContext& link, bool) override + { + return Failure(link); + } + PriStateBase& OnNotSupported(LinkContext& link, bool) override + { + return Failure(link); + } + + PriStateBase& OnTimeout(LinkContext&) override; + +private: + PriStateBase& Failure(LinkContext&); +}; + +///////////////////////////////////////////////////////////////////////////// +// Waiting for a link status response +///////////////////////////////////////////////////////////////////////////// + +// @section desc As soon as we get an ACK, send the delayed pri frame +class PLLS_RequestLinkStatusWait final : public PriStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(PLLS_RequestLinkStatusWait); + + PriStateBase& OnNack(LinkContext& link, bool) override; + PriStateBase& OnLinkStatus(LinkContext& link, bool) override; + PriStateBase& OnNotSupported(LinkContext& link, bool) override; + PriStateBase& OnTimeout(LinkContext&) override; +}; + +} //end namepsace + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.cpp new file mode 100644 index 0000000..ea700bb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.cpp @@ -0,0 +1,139 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "SecLinkLayerStates.h" + +#include "openpal/logging/LogMacros.h" + +#include "opendnp3/link/LinkLayer.h" +#include "opendnp3/LogLevels.h" + +using namespace openpal; + +namespace opendnp3 +{ + +//////////////////////////////////////// +// SecStateBase +//////////////////////////////////////// + +SecStateBase& SecStateBase::OnTransmitResult(LinkContext& ctx, bool success) +{ + FORMAT_LOG_BLOCK(ctx.logger, flags::ERR, "Invalid event for state: %s", this->Name()); + return *this; +} + +//////////////////////////////////////////////////////// +// Class SLLS_NotReset +//////////////////////////////////////////////////////// +SLLS_NotReset SLLS_NotReset::instance; + +SecStateBase& SLLS_NotReset::OnTestLinkStatus(LinkContext& ctx, bool aFcb) +{ + ++ctx.statistics.numUnexpectedFrame; + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "TestLinkStatus ignored"); + return *this; +} + +SecStateBase& SLLS_NotReset::OnConfirmedUserData(LinkContext& ctx, bool aFcb, const openpal::RSlice&) +{ + ++ctx.statistics.numUnexpectedFrame; + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "ConfirmedUserData ignored"); + return *this; +} + +SecStateBase& SLLS_NotReset::OnResetLinkStates(LinkContext& ctx) +{ + ctx.QueueAck(); + ctx.ResetReadFCB(); + return SLLS_TransmitWaitReset::Instance(); +} + +SecStateBase& SLLS_NotReset::OnRequestLinkStatus(LinkContext& ctx) +{ + ctx.QueueLinkStatus(); + return SLLS_TransmitWaitNotReset::Instance(); +} + +//////////////////////////////////////////////////////// +// Class SLLS_Reset +//////////////////////////////////////////////////////// +SLLS_Reset SLLS_Reset::instance; + +SecStateBase& SLLS_Reset::OnTestLinkStatus(LinkContext& ctx, bool fcb) +{ + if(ctx.nextReadFCB == fcb) + { + ctx.QueueAck(); + ctx.ToggleReadFCB(); + return SLLS_TransmitWaitReset::Instance(); + } + else + { + // "Re-transmit most recent response that contained function code 0 (ACK) or 1 (NACK)." + // This is a PITA implement + // TODO - see if this function is deprecated or not + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Received TestLinkStatus with invalid FCB"); + return *this; + } +} + +SecStateBase& SLLS_Reset::OnConfirmedUserData(LinkContext& ctx, bool fcb, const openpal::RSlice& data) +{ + ctx.QueueAck(); + + if (ctx.nextReadFCB == fcb) + { + ctx.ToggleReadFCB(); + ctx.PushDataUp(data); + } + else + { + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Confirmed data w/ wrong FCB"); + } + + return SLLS_TransmitWaitReset::Instance(); +} + +SecStateBase& SLLS_Reset::OnResetLinkStates(LinkContext& ctx) +{ + ctx.QueueAck(); + ctx.ResetReadFCB(); + return SLLS_TransmitWaitReset::Instance(); +} + +SecStateBase& SLLS_Reset::OnRequestLinkStatus(LinkContext& ctx) +{ + ctx.QueueLinkStatus(); + return SLLS_TransmitWaitReset::Instance(); +} + +//////////////////////////////////////////////////////// +// Class SLLS_TransmitWaitReset +//////////////////////////////////////////////////////// +SLLS_TransmitWaitReset SLLS_TransmitWaitReset::instance; + +//////////////////////////////////////////////////////// +// Class SLLS_TransmitWaitNotReset +//////////////////////////////////////////////////////// +SLLS_TransmitWaitNotReset SLLS_TransmitWaitNotReset::instance; + +} //end namepsace + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.h new file mode 100644 index 0000000..13c9b44 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/SecLinkLayerStates.h @@ -0,0 +1,152 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SECLINKLAYERSTATES_H +#define OPENDNP3_SECLINKLAYERSTATES_H + +#include "opendnp3/LogLevels.h" +#include "opendnp3/link/Singleton.h" +#include "opendnp3/link/LinkContext.h" + +#include + +namespace opendnp3 +{ + +class SecStateBase +{ +public: + + // Incoming messages to secondary station + + virtual SecStateBase& OnResetLinkStates(LinkContext&) = 0; + virtual SecStateBase& OnRequestLinkStatus(LinkContext&) = 0; + + virtual SecStateBase& OnTestLinkStatus(LinkContext&, bool fcb) = 0; + virtual SecStateBase& OnConfirmedUserData(LinkContext&, bool fcb, const openpal::RSlice&) = 0; + + virtual SecStateBase& OnTransmitResult(LinkContext& ctx, bool success); + + //every concrete state implements this for logging purposes + + virtual char const* Name() const = 0; +}; + +//////////////////////////////////////////////////////// +// Class SLLS_TransmitWait +//////////////////////////////////////////////////////// +template +class SLLS_TransmitWaitBase : public SecStateBase +{ + +protected: + SLLS_TransmitWaitBase() + {} + +public: + + virtual SecStateBase& OnTransmitResult(LinkContext& ctx, bool success) override final; + virtual SecStateBase& OnResetLinkStates(LinkContext&) override final; + virtual SecStateBase& OnRequestLinkStatus(LinkContext&) override final; + virtual SecStateBase& OnTestLinkStatus(LinkContext&, bool fcb) override final; + virtual SecStateBase& OnConfirmedUserData(LinkContext&, bool fcb, const openpal::RSlice&) override final; +}; + + +template +SecStateBase& SLLS_TransmitWaitBase::OnTransmitResult(LinkContext& ctx, bool success) +{ + // with secondary replies, we dont' really care about success + return NextState::Instance(); +} + +template +SecStateBase& SLLS_TransmitWaitBase::OnResetLinkStates(LinkContext& ctx) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Ignoring link frame, remote is flooding"); + return *this; +} + +template +SecStateBase& SLLS_TransmitWaitBase::OnRequestLinkStatus(LinkContext& ctx) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Ignoring link frame, remote is flooding"); + return *this; +} + +template +SecStateBase& SLLS_TransmitWaitBase::OnTestLinkStatus(LinkContext& ctx, bool fcb) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Ignoring link frame, remote is flooding"); + return *this; +} + +template +SecStateBase& SLLS_TransmitWaitBase::OnConfirmedUserData(LinkContext& ctx, bool fcb, const openpal::RSlice&) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "Ignoring link frame, remote is flooding"); + return *this; +} + +//////////////////////////////////////////////////////// +// Class SLLS_UnReset +//////////////////////////////////////////////////////// +class SLLS_NotReset final : public SecStateBase +{ +public: + + MACRO_STATE_SINGLETON_INSTANCE(SLLS_NotReset); + + virtual SecStateBase& OnConfirmedUserData(LinkContext&, bool fcb, const openpal::RSlice&) override; + virtual SecStateBase& OnResetLinkStates(LinkContext&) override; + virtual SecStateBase& OnRequestLinkStatus(LinkContext&) override; + virtual SecStateBase& OnTestLinkStatus(LinkContext&, bool fcb) override; + +}; + +//////////////////////////////////////////////////////// +// Class SLLS_Reset +//////////////////////////////////////////////////////// +class SLLS_Reset final : public SecStateBase +{ + MACRO_STATE_SINGLETON_INSTANCE(SLLS_Reset); + + virtual SecStateBase& OnConfirmedUserData(LinkContext&, bool fcb, const openpal::RSlice&) override; + virtual SecStateBase& OnResetLinkStates(LinkContext&) override; + virtual SecStateBase& OnRequestLinkStatus(LinkContext&) override; + virtual SecStateBase& OnTestLinkStatus(LinkContext&, bool fcb) override; +}; + + +class SLLS_TransmitWaitReset : public SLLS_TransmitWaitBase +{ + MACRO_STATE_SINGLETON_INSTANCE(SLLS_TransmitWaitReset); +}; + +class SLLS_TransmitWaitNotReset : public SLLS_TransmitWaitBase +{ + MACRO_STATE_SINGLETON_INSTANCE(SLLS_TransmitWaitNotReset); +}; + + +} //end namepsace + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.cpp new file mode 100644 index 0000000..8a7e0ad --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.cpp @@ -0,0 +1,88 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ShiftableBuffer.h" + +#include +#include +#include +#include + +namespace opendnp3 +{ + + +ShiftableBuffer::ShiftableBuffer(uint8_t* pBuffer_, uint32_t size) : + pBuffer(pBuffer_), + M_SIZE(size), + writePos(0), + readPos(0) +{ + +} + +void ShiftableBuffer::Shift() +{ + auto numRead = this->NumBytesRead(); + + //copy all unread data to the front of the buffer + memmove(pBuffer, pBuffer + readPos, numRead); + + readPos = 0; + writePos = numRead; +} + +void ShiftableBuffer::Reset() +{ + writePos = 0; + readPos = 0; +} + +void ShiftableBuffer::AdvanceRead(uint32_t numBytes) +{ + assert(numBytes <= this->NumBytesRead()); + readPos += numBytes; +} + +void ShiftableBuffer::AdvanceWrite(uint32_t aNumBytes) +{ + assert(aNumBytes <= this->NumWriteBytes()); + writePos += aNumBytes; +} + +bool ShiftableBuffer::Sync(uint32_t& skipCount) +{ + while (this->NumBytesRead() > 1) // at least 2 bytes + { + if (this->ReadBuffer()[0] == 0x05 && this->ReadBuffer()[1] == 0x64) + { + return true; + } + else + { + this->AdvanceRead(1); // skip the first byte + ++skipCount; + } + } + + return false; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.h new file mode 100644 index 0000000..c2a365b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/ShiftableBuffer.h @@ -0,0 +1,104 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SHIFTABLEBUFFER_H +#define OPENDNP3_SHIFTABLEBUFFER_H + +#include +#include + +namespace opendnp3 +{ + + +/** @section DESCRIPTION + Implements a buffer that can shift its contents as it is read */ +class ShiftableBuffer +{ +public: + + /** + * Construct the facade over the specified underlying buffer + */ + ShiftableBuffer(uint8_t* pBuffer_, uint32_t size); + + + // ------- Functions related to reading ----------- + + uint32_t NumBytesRead() const + { + return writePos - readPos; + } + + /// @return Pointer to the next byte to be read in the buffer + openpal::RSlice ReadBuffer() const + { + return openpal::RSlice(pBuffer + readPos, NumBytesRead()); + } + + /// Signal that some bytes don't have to be stored any longer. They'll be recovered during the next shift operation. + void AdvanceRead(uint32_t aNumBytes); + + // ------- Functions related to writing ----------- + + /// Shift the buffer back to front, writing over bytes that have already been read. The objective + /// being to free space for further writing. + void Shift(); + + /// Reset the buffer to its initial state, empty + void Reset(); + + /// @return Bytes of available for writing + uint32_t NumWriteBytes() const + { + return M_SIZE - writePos; + } + + /// @return Pointer to the position in the buffer available for writing + uint8_t* WriteBuff() const + { + return pBuffer + writePos; + } + + /// Signal to the buffer bytes were written to the current write position + void AdvanceWrite(uint32_t numBytes); + + //////////////////////////////////////////// + // Other functions + //////////////////////////////////////////// + + + /// Searches the read subsequence for 0x0564 sync bytes + /// @return true if both sync bytes were found in the buffer. + bool Sync(uint32_t& skipCount); + +private: + + + + uint8_t* pBuffer; + const uint32_t M_SIZE; + uint32_t writePos; + uint32_t readPos; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/link/Singleton.h b/utils/dnp3_src/cpp/libs/src/opendnp3/link/Singleton.h new file mode 100644 index 0000000..dbe5ff3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/link/Singleton.h @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SINGLETON_H +#define OPENDNP3_SINGLETON_H + +#define MACRO_SINGLETON_INSTANCE(type) \ + private:\ + static type instance;\ + protected: \ + type(){}; \ + public:\ + static type& Instance(){ return instance; } + +#define MACRO_NAME_SINGLETON_INSTANCE(type) \ + MACRO_SINGLETON_INSTANCE(type) \ + char const* Name() const override { return #type; } + +#define MACRO_STATE_SINGLETON_INSTANCE(type) MACRO_NAME_SINGLETON_INSTANCE(type) + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.cpp new file mode 100644 index 0000000..f597e5f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.cpp @@ -0,0 +1,79 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "AssignClassTask.h" + +#include "opendnp3/master/IMasterApplication.h" + +#include "opendnp3/app/HeaderWriter.h" + +using namespace openpal; + +namespace opendnp3 +{ + +AssignClassTask::AssignClassTask(IMasterApplication& application, openpal::TimeDuration retryPeriod_, openpal::Logger logger) : + IMasterTask(application, openpal::MonotonicTimestamp(0), logger, TaskConfig::Default()), + retryPeriod(retryPeriod_) +{} + +bool AssignClassTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + request.SetControl(AppControlField(true, true, false, false, seq)); + request.SetFunction(FunctionCode::ASSIGN_CLASS); + auto writer = request.GetWriter(); + + bool success = true; + auto writeFun = [&](const Header & header) + { + success &= header.WriteTo(writer); + }; + + pApplication->ConfigureAssignClassRequest(writeFun); + return success; +} + +bool AssignClassTask::IsEnabled() const +{ + return pApplication->AssignClassDuringStartup(); +} + +IMasterTask::ResponseResult AssignClassTask::ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateNullResponse(header, objects) ? ResponseResult::OK_FINAL : ResponseResult::ERROR_BAD_RESPONSE; +} + +IMasterTask::TaskState AssignClassTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_NO_COMMS) : + return TaskState::Immediately(); + + case(TaskCompletion::FAILURE_RESPONSE_TIMEOUT) : + return TaskState::Retry(now.Add(retryPeriod)); + + default: + return TaskState::Infinite(); + } +} + +} //end ns + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.h new file mode 100644 index 0000000..4dee4a6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/AssignClassTask.h @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ASSIGNCLASSTASK_H +#define OPENDNP3_ASSIGNCLASSTASK_H + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/TaskPriority.h" + +namespace opendnp3 +{ + +class IMasterApplication; + +class AssignClassTask final : public IMasterTask +{ + +public: + + AssignClassTask(IMasterApplication& application, openpal::TimeDuration retryPeriod, openpal::Logger logger); + + virtual char const* Name() const override + { + return "Assign Class"; + } + + virtual bool IsRecurring() const override + { + return true; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + + virtual int Priority(void) const override + { + return priority::ASSIGN_CLASS; + } + + virtual bool BlocksLowerPriority() const override + { + return true; + } + +private: + + openpal::TimeDuration retryPeriod; + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::ASSIGN_CLASS; + } + + virtual ResponseResult ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) override; + + virtual TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; + + virtual bool IsEnabled() const override; + +}; + + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.cpp new file mode 100644 index 0000000..270a24e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.cpp @@ -0,0 +1,86 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ClearRestartTask.h" + +#include "opendnp3/app/APDUBuilders.h" +#include "opendnp3/LogLevels.h" +#include "opendnp3/master/MasterTasks.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +ClearRestartTask::ClearRestartTask(IMasterApplication& application, openpal::TimeDuration retryPeriod_, openpal::Logger logger) : + IMasterTask(application, MonotonicTimestamp::Max(), logger, TaskConfig::Default()), + retryPeriod(retryPeriod_) +{ + +} + +bool ClearRestartTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + build::ClearRestartIIN(request, seq); + return true; +} + +IMasterTask::ResponseResult ClearRestartTask::ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) +{ + // we only care that the response to this has FIR/FIN + if (ValidateSingleResponse(response)) + { + if (response.IIN.IsSet(IINBit::DEVICE_RESTART)) + { + // we tried to clear the restart, but the device responded with the restart still set + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Clear restart task failed to clear restart bit, permanently disabling task"); + return ResponseResult::ERROR_BAD_RESPONSE; + } + else + { + return ResponseResult::OK_FINAL; + } + } + else + { + return ResponseResult::ERROR_BAD_RESPONSE; + } +} + +IMasterTask::TaskState ClearRestartTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + // if the outstation ever rejects the task outright, disable this task so that it doesn't rapid-retry + case(TaskCompletion::FAILURE_NOT_AUTHORIZED) : + case(TaskCompletion::FAILURE_BAD_RESPONSE) : + return TaskState::Disabled(); + + case(TaskCompletion::FAILURE_RESPONSE_TIMEOUT) : + return TaskState::Retry(now.Add(retryPeriod)); + default: + return TaskState::Infinite(); + } +} + +} //end ns + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.h new file mode 100644 index 0000000..e2bb986 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ClearRestartTask.h @@ -0,0 +1,84 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CLEARRESTARTTASK_H +#define OPENDNP3_CLEARRESTARTTASK_H + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/TaskPriority.h" + +namespace opendnp3 +{ + +/** +* Clear the IIN restart bit +*/ +class ClearRestartTask final : public IMasterTask +{ + +public: + + ClearRestartTask(IMasterApplication& application, openpal::TimeDuration retryPeriod, openpal::Logger logger); + + virtual char const* Name() const override + { + return "Clear Restart IIN"; + } + + virtual bool IsRecurring() const override + { + return true; + } + + virtual int Priority() const override + { + return priority::CLEAR_RESTART; + } + + virtual bool BlocksLowerPriority() const override + { + return true; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + +private: + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::CLEAR_RESTART; + } + + virtual bool IsEnabled() const override + { + return true; + } + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; + + virtual ResponseResult ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) override; + + openpal::TimeDuration retryPeriod; +}; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSet.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSet.cpp new file mode 100644 index 0000000..656d48b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSet.cpp @@ -0,0 +1,107 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "opendnp3/master/CommandSet.h" + +#include "opendnp3/master/TypedCommandHeader.h" + +#include +#include + +namespace opendnp3 +{ + +CommandSet::CommandSet(CommandSet&& other) : m_headers(std::move(other.m_headers)) +{ + +} + +CommandSet::~CommandSet() +{ + for(auto header : m_headers) + { + delete header; + } +} + +CommandSet::CommandSet(std::initializer_list> items) +{ + this->Add(items); +} + +CommandSet::CommandSet(std::initializer_list> items) +{ + this->Add(items); +} + +CommandSet::CommandSet(std::initializer_list> items) +{ + this->Add(items); +} + +CommandSet::CommandSet(std::initializer_list> items) +{ + this->Add(items); +} + +CommandSet::CommandSet(std::initializer_list> items) +{ + this->Add(items); +} + +ICommandCollection& CommandSet::StartHeaderCROB() +{ + TypedCommandHeader* header = new TypedCommandHeader(Group12Var1::Inst()); + this->m_headers.push_back(header); + return *header; +} + +ICommandCollection& CommandSet::StartHeaderAOInt32() +{ + TypedCommandHeader* header = new TypedCommandHeader(Group41Var1::Inst()); + this->m_headers.push_back(header); + return *header; +} + +ICommandCollection& CommandSet::StartHeaderAOInt16() +{ + TypedCommandHeader* header = new TypedCommandHeader(Group41Var2::Inst()); + this->m_headers.push_back(header); + return *header; +} + +ICommandCollection& CommandSet::StartHeaderAOFloat32() +{ + TypedCommandHeader* header = new TypedCommandHeader(Group41Var3::Inst()); + this->m_headers.push_back(header); + return *header; +} + +ICommandCollection& CommandSet::StartHeaderAODouble64() +{ + TypedCommandHeader* header = new TypedCommandHeader(Group41Var4::Inst()); + this->m_headers.push_back(header); + return *header; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.cpp new file mode 100644 index 0000000..d9e9f76 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.cpp @@ -0,0 +1,150 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "CommandSetOps.h" + +#include "opendnp3/master/ICommandHeader.h" +#include "opendnp3/master/CommandTaskResult.h" + +#include "opendnp3/app/parsing/APDUParser.h" + +#include + +namespace opendnp3 +{ + +template +IINField CommandSetOps::ProcessAny(const PrefixHeader& header, const ICollection>& values) +{ + if (header.GetQualifierCode() != QualifierCode::UINT16_CNT_UINT16_INDEX) + { + return IINBit::PARAM_ERROR; + } + + if (header.headerIndex >= commands->m_headers.size()) // more response headers than request headers + { + return IINBit::PARAM_ERROR; + } + + if (mode == Mode::Select) + { + commands->m_headers[header.headerIndex]->ApplySelectResponse(values); + } + else + { + commands->m_headers[header.headerIndex]->ApplyOperateResponse(values); + } + + return IINField::Empty(); +} + +CommandSetOps::CommandSetOps(Mode mode_, CommandSet& commands_) : + mode(mode_), + commands(&commands_) +{} + +bool CommandSetOps::Write(const CommandSet& set, HeaderWriter& writer) +{ + for(auto& header : set.m_headers) + { + if (!header->Write(writer)) + { + return false; + } + } + + return true; +} + +void CommandSetOps::InvokeCallback(const CommandSet& set, TaskCompletion result, CommandCallbackT& callback) +{ + CommandTaskResult impl(result, set.m_headers); + callback(impl); +} + +CommandSetOps::SelectResult CommandSetOps::ProcessSelectResponse(CommandSet& set, const openpal::RSlice& headers, openpal::Logger* logger) +{ + CommandSetOps handler(Mode::Select, set); + if (APDUParser::Parse(headers, handler, logger) != ParseResult::OK) + { + return SelectResult::FAIL_PARSE; + } + + auto selected = [](const ICommandHeader * header) -> bool + { + return header->AreAllSelected(); + }; + return std::all_of(set.m_headers.begin(), set.m_headers.end(), selected) ? SelectResult::OK : SelectResult::FAIL_SELECT; +} + +CommandSetOps::OperateResult CommandSetOps::ProcessOperateResponse(CommandSet& set, const openpal::RSlice& headers, openpal::Logger* logger) +{ + CommandSetOps handler(Mode::Operate, set); + return (APDUParser::Parse(headers, handler, logger) == ParseResult::OK) ? OperateResult::OK : OperateResult::FAIL_PARSE; +} + +bool CommandSetOps::IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) +{ + if (qc != QualifierCode::UINT16_CNT_UINT16_INDEX) + { + return false; + } + + switch (gv) + { + case(GroupVariation::Group12Var1) : // CROB + case(GroupVariation::Group41Var1) : // 4 kinds of AO + case(GroupVariation::Group41Var2) : + case(GroupVariation::Group41Var3) : + case(GroupVariation::Group41Var4) : + return true; + default: + return false; + } +} + +IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->ProcessAny(header, values); +} + +IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->ProcessAny(header, values); +} + +IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->ProcessAny(header, values); +} + +IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->ProcessAny(header, values); +} + +IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->ProcessAny(header, values); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.h new file mode 100644 index 0000000..2cb12df --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandSetOps.h @@ -0,0 +1,105 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COMMAND_SET_OPS_H +#define OPENDNP3_COMMAND_SET_OPS_H + +#include "opendnp3/master/CommandSet.h" +#include "opendnp3/master/CommandCallbackT.h" + +#include "opendnp3/app/HeaderWriter.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" + +#include + +namespace opendnp3 +{ +/** +* +* Has private access to CommandSet +* +* Used to reduce the public API surface exposed in includes to users +*/ +class CommandSetOps final : public IAPDUHandler, private openpal::Uncopyable +{ + enum class Mode : uint8_t + { + Select, + Operate + }; + + CommandSetOps(Mode mode, CommandSet& commands_); + + Mode mode; + +public: + + enum class OperateResult : uint8_t + { + OK, + FAIL_PARSE + }; + + enum class SelectResult : uint8_t + { + OK, + FAIL_PARSE, + FAIL_SELECT + }; + + /// Write the headers to an ASDU + static bool Write(const CommandSet& set, HeaderWriter& writer); + + /// Invoke the callback for a response + static void InvokeCallback(const CommandSet& set, TaskCompletion result, CommandCallbackT& callback); + + /** + * parses a response to a select, applying each received header to the command set + * + * @return true if every object in every header was correctly selected, false otherwise + */ + static SelectResult ProcessSelectResponse(CommandSet& set, const openpal::RSlice& headers, openpal::Logger* logger); + + /** + * parses a response to an operate (or DO), applying each received header to the command set + * + * @return true if parsing was successful, the results are left in the set + */ + static OperateResult ProcessOperateResponse(CommandSet& set, const openpal::RSlice& headers, openpal::Logger* logger); + +private: + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override; + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + + template + IINField ProcessAny(const PrefixHeader& header, const ICollection>& values); + + CommandSet* commands; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.cpp new file mode 100644 index 0000000..75c363f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.cpp @@ -0,0 +1,126 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CommandTask.h" + +#include "opendnp3/master/CommandSetOps.h" +#include "opendnp3/master/ICommandHeader.h" + +#include + +#include "opendnp3/app/parsing/APDUParser.h" +#include "opendnp3/LogLevels.h" + +using namespace openpal; + +namespace opendnp3 +{ + +std::shared_ptr CommandTask::CreateDirectOperate(CommandSet&& set, IMasterApplication& app, const CommandCallbackT& callback, const TaskConfig& config, openpal::Logger logger) +{ + auto task = std::make_shared(std::move(set), app, callback, config, logger); + task->LoadDirectOperate(); + return task; +} + + +std::shared_ptr CommandTask::CreateSelectAndOperate(CommandSet&& set, IMasterApplication& app, const CommandCallbackT& callback, const TaskConfig& config, openpal::Logger logger) +{ + auto task = std::make_shared(std::move(set), app, callback, config, logger); + task->LoadSelectAndOperate(); + return task; +} + +CommandTask::CommandTask(CommandSet&& commands, IMasterApplication& app, const CommandCallbackT& callback, const TaskConfig& config, openpal::Logger logger) : + IMasterTask(app, MonotonicTimestamp::Min(), logger, config), + statusResult(CommandStatus::UNDEFINED), + commandCallback(callback), + commands(std::move(commands)) +{ + +} + +void CommandTask::LoadSelectAndOperate() +{ + functionCodes.clear(); + functionCodes.push_back(FunctionCode::SELECT); + functionCodes.push_back(FunctionCode::OPERATE); +} + +void CommandTask::LoadDirectOperate() +{ + functionCodes.clear(); + functionCodes.push_back(FunctionCode::DIRECT_OPERATE); +} + +bool CommandTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + if (!functionCodes.empty()) + { + request.SetFunction(functionCodes.front()); + functionCodes.pop_front(); + request.SetControl(AppControlField::Request(seq)); + auto writer = request.GetWriter(); + return CommandSetOps::Write(commands, writer); + } + + return false; +} + +IMasterTask::ResponseResult CommandTask::ProcessResponse(const APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateSingleResponse(header) ? ProcessResponse(objects) : ResponseResult::ERROR_BAD_RESPONSE; +} + +IMasterTask::TaskState CommandTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + CommandSetOps::InvokeCallback(commands, result, this->commandCallback); + return TaskState::Infinite(); +} + +void CommandTask::Initialize() +{ + statusResult = CommandStatus::UNDEFINED; +} + +IMasterTask::ResponseResult CommandTask::ProcessResponse(const openpal::RSlice& objects) +{ + if (functionCodes.empty()) + { + auto result = CommandSetOps::ProcessOperateResponse(commands, objects, &logger); + return (result == CommandSetOps::OperateResult::FAIL_PARSE) ? ResponseResult::ERROR_BAD_RESPONSE : ResponseResult::OK_FINAL; + } + else + { + auto result = CommandSetOps::ProcessSelectResponse(commands, objects, &logger); + + switch (result) + { + case(CommandSetOps::SelectResult::OK) : + return ResponseResult::OK_REPEAT; // proceed to OPERATE + case(CommandSetOps::SelectResult::FAIL_SELECT) : + return ResponseResult::OK_FINAL; // end the task, let the user examine each command point + default: + return ResponseResult::ERROR_BAD_RESPONSE; + } + } +} + +} //ens ns diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.h new file mode 100644 index 0000000..e879fba --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTask.h @@ -0,0 +1,111 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COMMANDTASK_H +#define OPENDNP3_COMMANDTASK_H + + +#include "opendnp3/gen/FunctionCode.h" + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/ITaskCallback.h" +#include "opendnp3/master/ICommandProcessor.h" +#include "opendnp3/master/TaskPriority.h" +#include "opendnp3/master/CommandSet.h" + + +#include +#include +#include + +#include +#include + +namespace opendnp3 +{ + +// Base class with machinery for performing command operations +class CommandTask : public IMasterTask +{ + +public: + + CommandTask(CommandSet&& set, IMasterApplication& app, const CommandCallbackT& callback, const TaskConfig& config, openpal::Logger logger); + + static std::shared_ptr CreateDirectOperate(CommandSet&& commands, IMasterApplication& app, const CommandCallbackT& callback, const TaskConfig& config, openpal::Logger logger); + static std::shared_ptr CreateSelectAndOperate(CommandSet&& commands, IMasterApplication& app, const CommandCallbackT& callback, const TaskConfig& config, openpal::Logger logger); + + virtual char const* Name() const override final + { + return "Command Task"; + } + + virtual int Priority() const override final + { + return priority::COMMAND; + } + + virtual bool BlocksLowerPriority() const override final + { + return false; + } + + virtual bool IsRecurring() const override final + { + return false; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override final; + +private: + + virtual bool IsEnabled() const override final + { + return true; + } + + virtual MasterTaskType GetTaskType() const override final + { + return MasterTaskType::USER_TASK; + } + + virtual void Initialize() override final; + + virtual ResponseResult ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) override final; + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override final; + + ResponseResult ProcessResponse(const openpal::RSlice& objects); + + void LoadSelectAndOperate(); + void LoadDirectOperate(); + + std::deque functionCodes; + + CommandStatus statusResult; + CommandCallbackT commandCallback; + CommandSet commands; + +}; + + +} //ens ns + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.cpp new file mode 100644 index 0000000..3980c5f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.cpp @@ -0,0 +1,73 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "CommandTaskResult.h" + +#include "opendnp3/master/ICommandHeader.h" + +namespace opendnp3 +{ + +CommandTaskResult::CommandTaskResult(TaskCompletion result, const CommandSet::HeaderVector& vector) : + ICommandTaskResult(result), + m_vector(&vector) +{ + +} + +/// --- Implement ICollection ---- + +size_t CommandTaskResult::Count() const +{ + size_t count = 0; + for (auto& header : *m_vector) + { + count += header->Count(); + } + return count; +} + +void CommandTaskResult::Foreach(IVisitor& visitor) const +{ + uint32_t headerIndex = 0; + + for (auto& header : *m_vector) + { + auto visit = [&](const CommandState & state) + { + visitor.OnValue( + CommandPointResult( + headerIndex, + state.index, + state.state, + state.status + ) + ); + }; + + header->ForeachItem(visit); + ++headerIndex; + } +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.h new file mode 100644 index 0000000..d516624 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/CommandTaskResult.h @@ -0,0 +1,56 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_COMMAND_TASK_RESULT_H +#define OPENDNP3_COMMAND_TASK_RESULT_H + +#include "opendnp3/master/ICommandTaskResult.h" + +#include "opendnp3/master/CommandSet.h" + +#include + +namespace opendnp3 +{ + +class CommandTaskResult final : public ICommandTaskResult, private openpal::Uncopyable +{ +public: + + CommandTaskResult(TaskCompletion result, const CommandSet::HeaderVector& vector); + + /// --- Implement ICollection ---- + + virtual size_t Count() const override; + virtual void Foreach(IVisitor& visitor) const override; + +private: + + CommandTaskResult() = delete; + + const CommandSet::HeaderVector* m_vector; +}; + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.cpp new file mode 100644 index 0000000..f5cddd6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.cpp @@ -0,0 +1,71 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "DisableUnsolicitedTask.h" + +#include "opendnp3/app/APDUBuilders.h" + +#include "MasterTasks.h" + +using namespace openpal; + +namespace opendnp3 +{ + +DisableUnsolicitedTask::DisableUnsolicitedTask(IMasterApplication& application, bool enabled_, TimeDuration retryPeriod_, openpal::Logger logger) : + IMasterTask(application, MonotonicTimestamp::Min(), logger, TaskConfig::Default()), + enabled(enabled_), + retryPeriod(retryPeriod_) +{ + +} + +bool DisableUnsolicitedTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + build::DisableUnsolicited(request, seq); + return true; +} + +IMasterTask::ResponseResult DisableUnsolicitedTask::ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateNullResponse(header, objects) ? ResponseResult::OK_FINAL : ResponseResult::ERROR_BAD_RESPONSE; +} + +IMasterTask::TaskState DisableUnsolicitedTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_BAD_RESPONSE) : + return TaskState::Disabled(); + + case(TaskCompletion::FAILURE_NO_COMMS) : + return TaskState::Immediately(); + + case(TaskCompletion::FAILURE_RESPONSE_TIMEOUT) : + return TaskState::Retry(now.Add(retryPeriod)); + + default: + return TaskState::Infinite(); + } +} + + +} //end ns + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.h new file mode 100644 index 0000000..2012e3e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/DisableUnsolicitedTask.h @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DISABLEUNSOLICITEDTASK_H +#define OPENDNP3_DISABLEUNSOLICITEDTASK_H + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/TaskPriority.h" + +namespace opendnp3 +{ + +class DisableUnsolicitedTask final : public IMasterTask +{ + +public: + + DisableUnsolicitedTask(IMasterApplication& application, bool enabled, openpal::TimeDuration retryPeriod, openpal::Logger logger); + + virtual char const* Name() const override + { + return "Disable Unsolicited"; + } + + virtual bool IsRecurring() const override + { + return true; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + + virtual int Priority() const override + { + return priority::DISABLE_UNSOLICITED; + } + + virtual bool BlocksLowerPriority() const override + { + return true; + } + +private: + + bool enabled; + openpal::TimeDuration retryPeriod; + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::DISABLE_UNSOLICITED; + } + + virtual bool IsEnabled() const override + { + return enabled; + } + + virtual ResponseResult ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) override; + + virtual TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; +}; + + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.cpp new file mode 100644 index 0000000..7fe979e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.cpp @@ -0,0 +1,44 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "EmptyResponseTask.h" + +#include "opendnp3/master/TaskPriority.h" + +using namespace openpal; + +namespace opendnp3 +{ + +EmptyResponseTask::EmptyResponseTask(IMasterApplication& app, const std::string& name, FunctionCode func, const std::function& format, openpal::Logger logger, const TaskConfig& config) : + SimpleRequestTaskBase(app, func, priority::USER_REQUEST, format, logger, config), + m_name(name) +{ + +} + +IMasterTask::ResponseResult EmptyResponseTask::ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateNullResponse(header, objects) ? ResponseResult::OK_FINAL : ResponseResult::ERROR_BAD_RESPONSE; +} + + +} //end ns + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.h new file mode 100644 index 0000000..7a408b1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EmptyResponseTask.h @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EMPTY_RESPONSE_TASK_H +#define OPENDNP3_EMPTY_RESPONSE_TASK_H + +#include "opendnp3/master/SimpleRequestTaskBase.h" + +#include + +namespace opendnp3 +{ + +class EmptyResponseTask : public SimpleRequestTaskBase +{ + +public: + + EmptyResponseTask(IMasterApplication& app, const std::string& name, FunctionCode func, const HeaderBuilderT& format, openpal::Logger logger, const TaskConfig& config); + + virtual char const* Name() const override final + { + return m_name.c_str(); + } + +private: + + std::string m_name; + + IMasterTask::ResponseResult ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) override final; + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override final + { + return TaskState::Infinite(); + } +}; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.cpp new file mode 100644 index 0000000..c185b73 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.cpp @@ -0,0 +1,76 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "EnableUnsolicitedTask.h" +#include "MasterTasks.h" + +#include "opendnp3/app/APDUBuilders.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +EnableUnsolicitedTask::EnableUnsolicitedTask(IMasterApplication& app, ClassField enabledClasses_, openpal::TimeDuration retryPeriod_, openpal::Logger logger) : + IMasterTask(app, openpal::MonotonicTimestamp(0), logger, TaskConfig::Default()), + enabledClasses(enabledClasses_), + retryPeriod(retryPeriod_) +{ + +} + +bool EnableUnsolicitedTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + build::EnableUnsolicited(request, enabledClasses.OnlyEventClasses(), seq); + return true; +} + +bool EnableUnsolicitedTask::IsEnabled() const +{ + return enabledClasses.HasEventClass(); +} + +IMasterTask::ResponseResult EnableUnsolicitedTask::ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateNullResponse(header, objects) ? ResponseResult::OK_FINAL : ResponseResult::ERROR_BAD_RESPONSE; +} + +IMasterTask::TaskState EnableUnsolicitedTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_BAD_RESPONSE) : + return TaskState::Disabled(); + + case(TaskCompletion::FAILURE_NO_COMMS) : + return TaskState::Immediately(); + + case(TaskCompletion::FAILURE_RESPONSE_TIMEOUT) : + return TaskState::Retry(now.Add(retryPeriod)); + + default: + return TaskState::Infinite(); + } +} + +} //end ns + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.h new file mode 100644 index 0000000..0f6e0cc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EnableUnsolicitedTask.h @@ -0,0 +1,93 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ENABLEUNSOLICITEDTASK_H +#define OPENDNP3_ENABLEUNSOLICITEDTASK_H + + +#include "opendnp3/app/ClassField.h" + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/TaskPriority.h" + + +namespace openpal +{ +class IExecutor; +} + +namespace opendnp3 +{ + +/** +* Base class for tasks that only require a single response +*/ + +class EnableUnsolicitedTask final : public IMasterTask +{ + +public: + + EnableUnsolicitedTask(IMasterApplication& app, ClassField enabledClasses, openpal::TimeDuration retryPeriod, openpal::Logger logger); + + virtual bool IsRecurring() const override + { + return true; + } + + virtual char const* Name() const override + { + return "Enable Unsolicited"; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + + virtual int Priority() const override + { + return priority::ENABLE_UNSOLICITED; + } + + virtual bool BlocksLowerPriority() const override + { + return true; + } + +private: + + ClassField enabledClasses; + openpal::TimeDuration retryPeriod; + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::ENABLE_UNSOLICITED; + } + + virtual ResponseResult ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) override; + + virtual bool IsEnabled() const override; + + virtual TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; + +}; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.cpp new file mode 100644 index 0000000..0b87b51 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.cpp @@ -0,0 +1,95 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +/** +* Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +* more contributor license agreements. See the NOTICE file distributed +* with this work for additional information regarding copyright ownership. +* Green Energy Corp licenses this file to you under the Apache License, +* Version 2.0 (the "License"); you may not use this file except in +* compliance with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This project was forked on 01/01/2013 by Automatak, LLC and modifications +* may have been made to this file. Automatak, LLC licenses these modifications +* to you under the terms of the License. +*/ + +#include "EventScanTask.h" + +#include "MasterTasks.h" + +#include "opendnp3/app/parsing/APDUParser.h" +#include "opendnp3/app/APDUBuilders.h" + +#include "opendnp3/master/MeasurementHandler.h" + +#include "opendnp3/LogLevels.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +EventScanTask::EventScanTask(IMasterApplication& application, ISOEHandler& soeHandler, ClassField classes_, TimeDuration retryPeriod_, openpal::Logger logger) : + PollTaskBase(application, soeHandler, MonotonicTimestamp::Max(), logger, TaskConfig::Default()), + classes(classes_.OnlyEventClasses()), + retryPeriod(retryPeriod_) +{ + +} + +bool EventScanTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + build::ClassRequest(request, FunctionCode::READ, classes, seq); + return true; +} + +bool EventScanTask::IsEnabled() const +{ + return classes.HasEventClass(); +} + +IMasterTask::TaskState EventScanTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_BAD_RESPONSE) : + return TaskState::Disabled(); + + case(TaskCompletion::FAILURE_RESPONSE_TIMEOUT) : + return TaskState::Retry(now.Add(retryPeriod)); + + default: + return TaskState::Infinite(); + } +} + + +} //end ns diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.h new file mode 100644 index 0000000..ac2acd7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/EventScanTask.h @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTSCANTASK_H +#define OPENDNP3_EVENTSCANTASK_H + +#include "opendnp3/app/ClassField.h" + +#include "opendnp3/master/PollTaskBase.h" +#include "opendnp3/master/TaskPriority.h" + +namespace opendnp3 +{ +class ISOEHandler; + +/** +* An auto event scan task that happens when the master sees the event IIN bits +*/ +class EventScanTask final : public PollTaskBase +{ + +public: + + EventScanTask(IMasterApplication& application, ISOEHandler& soeHandler, ClassField classes, openpal::TimeDuration retryPeriod, openpal::Logger logger); + + virtual bool IsRecurring() const override + { + return true; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + + virtual int Priority() const override + { + return priority::EVENT_SCAN; + } + + virtual bool BlocksLowerPriority() const override + { + return true; + } + +private: + + ClassField classes; + + openpal::TimeDuration retryPeriod; + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::AUTO_EVENT_SCAN; + } + + virtual bool IsEnabled() const override; + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; + +}; + + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderBuilder.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderBuilder.h new file mode 100644 index 0000000..3bbd201 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderBuilder.h @@ -0,0 +1,36 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_HEADERBUILDER_H +#define OPENDNP3_HEADERBUILDER_H + +#include + +#include + +namespace opendnp3 +{ + +typedef std::function HeaderBuilderT; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderTypes.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderTypes.cpp new file mode 100644 index 0000000..87b361a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/HeaderTypes.cpp @@ -0,0 +1,112 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/master/HeaderTypes.h" + +#include + + +namespace opendnp3 +{ + +Header Header::AllObjects(uint8_t group, uint8_t variation) +{ + return Header(group, variation); +} + +Header Header::From(PointClass pc) +{ + switch (pc) + { + case(PointClass::Class0): + return Header::AllObjects(60, 1); + case(PointClass::Class1): + return Header::AllObjects(60, 2); + case(PointClass::Class2): + return Header::AllObjects(60, 3); + default: + return Header::AllObjects(60, 4); + } +} + +Header Header::Range8(uint8_t group, uint8_t variation, uint8_t start, uint8_t stop) +{ + return Header(group, variation, start, stop); +} + +Header Header::Range16(uint8_t group, uint8_t variation, uint16_t start, uint16_t stop) +{ + return Header(group, variation, start, stop); +} + +Header Header::Count8(uint8_t group, uint8_t variation, uint8_t count) +{ + return Header(group, variation, count); +} + +Header Header::Count16(uint8_t group, uint8_t variation, uint16_t count) +{ + return Header(group, variation, count); +} + +Header::Header(uint8_t group, uint8_t var) : id(group, var), type(HeaderType::AllObjects) {} + +Header::Header(uint8_t group, uint8_t var, uint8_t start, uint8_t stop) : id(group, var), type(HeaderType::Ranged8) +{ + value.range8 = { start, stop }; +} + +Header::Header(uint8_t group, uint8_t var, uint16_t start, uint16_t stop) : id(group, var), type(HeaderType::Ranged16) +{ + value.range16 = { start, stop }; +} + +Header::Header(uint8_t group, uint8_t var, uint8_t count) : id(group, var), type(HeaderType::LimitedCount8) +{ + value.count8.value = count; +} + +Header::Header(uint8_t group, uint8_t var, uint16_t count) : id(group, var), type(HeaderType::LimitedCount16) +{ + value.count16.value = count; +} + +bool Header::WriteTo(opendnp3::HeaderWriter& writer) const +{ + switch (type) + { + case(HeaderType::AllObjects) : + return writer.WriteHeader(id, QualifierCode::ALL_OBJECTS); + case(HeaderType::Ranged8) : + return writer.WriteRangeHeader(QualifierCode::UINT8_START_STOP, id, value.range8.start, value.range8.stop); + case(HeaderType::Ranged16) : + return writer.WriteRangeHeader(QualifierCode::UINT16_START_STOP, id, value.range16.start, value.range16.stop); + case(HeaderType::LimitedCount8) : + return writer.WriteCountHeader(QualifierCode::UINT8_CNT, id, value.count8.value); + case(HeaderType::LimitedCount16) : + return writer.WriteCountHeader(QualifierCode::UINT16_CNT, id, value.count16.value); + default: + return false; + } +} +} + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ICommandHeader.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ICommandHeader.h new file mode 100644 index 0000000..281aa11 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ICommandHeader.h @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICOMMAND_HEADER_H +#define OPENDNP3_ICOMMAND_HEADER_H + +#include "opendnp3/master/HeaderInfo.h" +#include "opendnp3/master/CommandPointResult.h" + +#include "opendnp3/app/parsing/ICollection.h" + +#include "opendnp3/app/ControlRelayOutputBlock.h" +#include "opendnp3/app/AnalogOutput.h" +#include "opendnp3/app/Indexed.h" + +namespace opendnp3 +{ + +class HeaderWriter; + +struct CommandState +{ + CommandState(uint16_t index_) : + state(CommandPointState::INIT), + status(CommandStatus::UNDEFINED), + index(index_) + {} + + CommandPointState state; + CommandStatus status; + uint16_t index; +}; + +/** +* Represents an object header of command objects (CROB or AO) +*/ +class ICommandHeader : public ICollection +{ +public: + + virtual ~ICommandHeader() {} + + /// Write all of the headers to an ASDU + virtual bool Write(HeaderWriter&) const = 0; + + /// Ask if all of the individual commands have been selected + virtual bool AreAllSelected() const = 0; + + // --- each overriden classs will only override one of these --- + + virtual void ApplySelectResponse(const ICollection>& commands) {} + virtual void ApplySelectResponse(const ICollection>& commands) {} + virtual void ApplySelectResponse(const ICollection>& commands) {} + virtual void ApplySelectResponse(const ICollection>& commands) {} + virtual void ApplySelectResponse(const ICollection>& commands) {} + + // --- each overriden classs will only override one of these --- + + virtual void ApplyOperateResponse(const ICollection>& commands) {} + virtual void ApplyOperateResponse(const ICollection>& commands) {} + virtual void ApplyOperateResponse(const ICollection>& commands) {} + virtual void ApplyOperateResponse(const ICollection>& commands) {} + virtual void ApplyOperateResponse(const ICollection>& commands) {} +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.cpp new file mode 100644 index 0000000..aa2d883 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.cpp @@ -0,0 +1,202 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "IMasterTask.h" + +#include "openpal/logging/LogMacros.h" +#include "opendnp3/LogLevels.h" + +using namespace openpal; + +namespace opendnp3 +{ + +IMasterTask::IMasterTask(IMasterApplication& app, openpal::MonotonicTimestamp expiration, openpal::Logger logger_, TaskConfig config_) : + pApplication(&app), + logger(logger_), + state(expiration), + config(config_), + taskStartExpiration(MonotonicTimestamp::Max()) +{} + +IMasterTask::~IMasterTask() +{ + if (config.pCallback) + { + config.pCallback->OnDestroyed(); + } +} + +openpal::MonotonicTimestamp IMasterTask::ExpirationTime() const +{ + return (!state.disabled && this->IsEnabled()) ? state.expiration : MonotonicTimestamp::Max(); +} + +void IMasterTask::ConfigureStartExpiration(openpal::MonotonicTimestamp time) +{ + this->taskStartExpiration = time; +} + +openpal::MonotonicTimestamp IMasterTask::StartExpirationTime() const +{ + return taskStartExpiration; +} + +IMasterTask::ResponseResult IMasterTask::OnResponse(const APDUResponseHeader& response, const openpal::RSlice& objects, openpal::MonotonicTimestamp now) +{ + auto result = ProcessResponse(response, objects); + + switch (result) + { + case(ResponseResult::ERROR_BAD_RESPONSE) : + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_BAD_RESPONSE, now); + this->NotifyResult(TaskCompletion::FAILURE_BAD_RESPONSE); + break; + case(ResponseResult::ERROR_INTERNAL_FAILURE) : + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_INTERNAL_ERROR, now); + this->NotifyResult(TaskCompletion::FAILURE_INTERNAL_ERROR); + break; + case(ResponseResult::OK_FINAL) : + this->state = this->OnTaskComplete(TaskCompletion::SUCCESS, now); + this->NotifyResult(TaskCompletion::SUCCESS); + break; + default: + break; + } + + return result; +} + +void IMasterTask::OnResponseTimeout(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_RESPONSE_TIMEOUT, now); + this->NotifyResult(TaskCompletion::FAILURE_RESPONSE_TIMEOUT); +} + +void IMasterTask::OnLowerLayerClose(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_NO_COMMS, now); + this->NotifyResult(TaskCompletion::FAILURE_NO_COMMS); +} + +void IMasterTask::OnStartTimeout(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_START_TIMEOUT, now); + this->NotifyResult(TaskCompletion::FAILURE_START_TIMEOUT); +} + +void IMasterTask::OnNoUser(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_NO_USER, now); + this->NotifyResult(TaskCompletion::FAILURE_NO_USER); +} + +void IMasterTask::OnInternalError(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_INTERNAL_ERROR, now); + this->NotifyResult(TaskCompletion::FAILURE_INTERNAL_ERROR); +} + +void IMasterTask::OnAuthenticationFailure(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_BAD_AUTHENTICATION, now); + this->NotifyResult(TaskCompletion::FAILURE_BAD_AUTHENTICATION); +} + +void IMasterTask::OnAuthorizationFailure(openpal::MonotonicTimestamp now) +{ + this->state = this->OnTaskComplete(TaskCompletion::FAILURE_NOT_AUTHORIZED, now); + this->NotifyResult(TaskCompletion::FAILURE_NOT_AUTHORIZED); +} + +void IMasterTask::NotifyResult(TaskCompletion result) +{ + if (config.pCallback) + { + config.pCallback->OnComplete(result); + } + + pApplication->OnTaskComplete(TaskInfo(this->GetTaskType(), result, config.taskId)); +} + +void IMasterTask::OnStart() +{ + if (config.pCallback) + { + config.pCallback->OnStart(); + } + + pApplication->OnTaskStart(this->GetTaskType(), config.taskId); + + this->Initialize(); +} + +void IMasterTask::Demand() +{ + this->state = TaskState::Immediately(); +} + +bool IMasterTask::ValidateSingleResponse(const APDUResponseHeader& header) +{ + if (header.control.FIR && header.control.FIN) + { + return true; + } + else + { + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Ignoring unexpected response FIR/FIN not set"); + return false; + } +} + +bool IMasterTask::ValidateNullResponse(const APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateSingleResponse(header) && ValidateNoObjects(objects) && ValidateInternalIndications(header); +} + + +bool IMasterTask::ValidateInternalIndications(const APDUResponseHeader& header) +{ + if (header.IIN.HasRequestError()) + { + FORMAT_LOG_BLOCK(logger, flags::WARN, "Task was explicitly rejected via response with error IIN bit(s): %s", this->Name()); + return false; + } + else + { + return true; + } +} + +bool IMasterTask::ValidateNoObjects(const openpal::RSlice& objects) +{ + if (objects.IsEmpty()) + { + return true; + } + else + { + FORMAT_LOG_BLOCK(logger, flags::WARN, "Received unexpected response object headers for task: %s", this->Name()); + return false; + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.h new file mode 100644 index 0000000..b5d6a20 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/IMasterTask.h @@ -0,0 +1,244 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IMASTERTASK_H +#define OPENDNP3_IMASTERTASK_H + +#include +#include +#include + +#include "opendnp3/app/APDUHeader.h" +#include "opendnp3/app/APDURequest.h" + +#include "opendnp3/master/TaskConfig.h" +#include "opendnp3/master/IMasterApplication.h" + +namespace opendnp3 +{ + +/** + * A generic interface for defining master request/response style tasks + */ +class IMasterTask +{ + +protected: + + class TaskState + { + public: + + TaskState(openpal::MonotonicTimestamp expiration_, bool disabled_ = false) : disabled(disabled_), expiration(expiration_) + {} + + static TaskState Immediately() + { + return TaskState(openpal::MonotonicTimestamp(0), false); + } + + static TaskState Infinite() + { + return TaskState(openpal::MonotonicTimestamp::Max(), false); + } + + static TaskState Retry(openpal::MonotonicTimestamp exp) + { + return TaskState(exp, false); + } + + static TaskState Disabled() + { + return TaskState(openpal::MonotonicTimestamp::Max(), true); + } + + bool disabled; + openpal::MonotonicTimestamp expiration; + + private: + TaskState() = delete; + }; + + +public: + + enum class ResponseResult : uint8_t + { + /// The response was bad, the task has failed + ERROR_BAD_RESPONSE, + + /// An internal error occured like a failure calculating an HMAC + ERROR_INTERNAL_FAILURE, + + /// The response was good and the task is complete + OK_FINAL, + + /// The response was good and the task should repeat the format, transmit, and await response sequence + OK_REPEAT, + + /// The response was good and the task should continue executing. Restart the response timer, and increment expected SEQ#. + OK_CONTINUE + }; + + + IMasterTask(IMasterApplication& app, openpal::MonotonicTimestamp expiration, openpal::Logger logger, TaskConfig config); + + + virtual ~IMasterTask(); + + /** + * Overridable for auth tasks + */ + virtual bool IsAuthTask() const + { + return false; + } + + /** + * + * @return the name of the task + */ + virtual char const* Name() const = 0; + + /** + * The task's priority. Lower numbers are higher priority. + */ + virtual int Priority() const = 0; + + /** + * Allows tasks to enter a blocking mode where lower priority + * tasks cannot run until this task completes + */ + virtual bool BlocksLowerPriority() const = 0; + + /** + * Indicates if the task should be rescheduled (true) or discarded + * after a single execution (false) + */ + virtual bool IsRecurring() const = 0; + + /** + * The time when this task can run again. + */ + openpal::MonotonicTimestamp ExpirationTime() const; + + /** + * Configure the start expiration time + */ + void ConfigureStartExpiration(openpal::MonotonicTimestamp time); + + /** + * The time when this task expires if it is unable to start + */ + openpal::MonotonicTimestamp StartExpirationTime() const; + + /** + * Build a request APDU. + * + * Return false if some kind of internal error prevents the task for formatting the request. + */ + virtual bool BuildRequest(APDURequest& request, uint8_t seq) = 0; + + /** + * Handler for responses + */ + ResponseResult OnResponse(const APDUResponseHeader& response, const openpal::RSlice& objects, openpal::MonotonicTimestamp now); + + /** + * Called when a response times out + */ + void OnResponseTimeout(openpal::MonotonicTimestamp now); + + /** + * Called when the layer closes while the task is executing. + */ + void OnLowerLayerClose(openpal::MonotonicTimestamp now); + + /** + * The start timeout expired before the task could be run + */ + void OnStartTimeout(openpal::MonotonicTimestamp now); + + /** + * Called when a task is discared because it's user doesn't exist + */ + void OnNoUser(openpal::MonotonicTimestamp now); + + /** + * Called when a task has an internal error of some sort like not being able to write a request + */ + void OnInternalError(openpal::MonotonicTimestamp now); + + /** + * Called when the request is reject due to an authentication failure + */ + void OnAuthenticationFailure(openpal::MonotonicTimestamp now); + + /** + * Called when the request is reject due to an authorization failure + */ + void OnAuthorizationFailure(openpal::MonotonicTimestamp now); + + /** + * Called when the task first starts, before the first request is formatted + */ + void OnStart(); + + /** + * Demand that the task run immediately by setting the expiration to 0 + */ + void Demand(); + +protected: + + // called during OnStart() to initialize any state for a new run + virtual void Initialize() {} + + virtual ResponseResult ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) = 0; + + virtual TaskState OnTaskComplete(TaskCompletion completion, openpal::MonotonicTimestamp now) = 0; + + virtual bool IsEnabled() const = 0; + + virtual MasterTaskType GetTaskType() const = 0; + + IMasterApplication* pApplication; + openpal::Logger logger; + + // Validation helpers for various behaviors to avoid deep inheritance + bool ValidateSingleResponse(const APDUResponseHeader& header); + bool ValidateNullResponse(const APDUResponseHeader& header, const openpal::RSlice& objects); + bool ValidateNoObjects(const openpal::RSlice& objects); + bool ValidateInternalIndications(const APDUResponseHeader& header); + + void NotifyResult(TaskCompletion result); + +private: + + IMasterTask(); + + TaskState state; + TaskConfig config; + openpal::MonotonicTimestamp taskStartExpiration; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/IScheduleCallback.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/IScheduleCallback.h new file mode 100644 index 0000000..bd82258 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/IScheduleCallback.h @@ -0,0 +1,36 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ISCHEDULECALLBACK_H +#define OPENDNP3_ISCHEDULECALLBACK_H + +namespace opendnp3 +{ + +class IScheduleCallback +{ +public: + + virtual void OnPendingTask() = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskFilter.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskFilter.h new file mode 100644 index 0000000..6ee88c3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskFilter.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ITASKFILTER_H +#define OPENDNP3_ITASKFILTER_H + +#include "opendnp3/master/IMasterTask.h" + +#include + +namespace opendnp3 +{ + +/** +* Evaluates a task to determine if it can run based on additional state information not available in the scheduler +*/ +class ITaskFilter +{ + +public: + + virtual bool CanRun(const IMasterTask& task) = 0; + + virtual void SetTaskStartTimeout(const openpal::MonotonicTimestamp& time) = 0; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.cpp new file mode 100644 index 0000000..97931dd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.cpp @@ -0,0 +1,34 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ITaskLock.h" + +namespace opendnp3 +{ + +NullTaskLock NullTaskLock::instance; + +ITaskLock& NullTaskLock::Instance() +{ + return instance; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.h new file mode 100644 index 0000000..43bde0d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ITaskLock.h @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ITASKLOCK_H +#define OPENDNP3_ITASKLOCK_H + +#include + +#include "opendnp3/master/IScheduleCallback.h" + +namespace opendnp3 +{ + +/** + Interface used in multi-drop configurations (multiple masters on same channel) + to control task execution such that only 1 master is running a task at a time. +*/ +class ITaskLock +{ +public: + + /// Acquire a lock + virtual bool Acquire(IScheduleCallback&) = 0; + + /// Release a lock + virtual bool Release(IScheduleCallback&) = 0; + +}; + +class NullTaskLock final : public ITaskLock, private openpal::Uncopyable +{ +public: + + virtual bool Acquire(IScheduleCallback&) override + { + return true; + } + + virtual bool Release(IScheduleCallback&) override + { + return true; + } + + static ITaskLock& Instance(); + +private: + + NullTaskLock() {} + + static NullTaskLock instance; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.cpp new file mode 100644 index 0000000..aac86a3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.cpp @@ -0,0 +1,630 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MasterContext.h" + + +#include "opendnp3/LogLevels.h" +#include "opendnp3/app/APDULogging.h" +#include "opendnp3/app/parsing/APDUHeaderParser.h" +#include "opendnp3/app/APDUBuilders.h" +#include "opendnp3/master/MeasurementHandler.h" +#include "opendnp3/master/EmptyResponseTask.h" +#include "opendnp3/master/RestartOperationTask.h" +#include "opendnp3/objects/Group12.h" +#include "opendnp3/objects/Group41.h" + +#include + + +using namespace openpal; + +namespace opendnp3 +{ +MContext::MContext( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& lower, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const MasterParams& params, + ITaskLock& taskLock +) : + logger(logger), + executor(executor), + lower(lower), + params(params), + SOEHandler(SOEHandler), + application(application), + pTaskLock(&taskLock), + responseTimer(*executor), + scheduleTimer(*executor), + taskStartTimeoutTimer(*executor), + tasks(params, logger, *application, *SOEHandler), + scheduler(*this), + txBuffer(params.maxTxFragSize), + tstate(TaskState::IDLE) +{} + +bool MContext::OnLowerLayerUp() +{ + if (isOnline) + { + return false; + } + + isOnline = true; + tasks.Initialize(scheduler); + this->PostCheckForTask(); + + this->application->OnOpen(); + + return true; +} + +bool MContext::OnLowerLayerDown() +{ + if (!isOnline) + { + return false; + } + + auto now = executor->GetTime(); + scheduler.Shutdown(now); + + if (activeTask) + { + activeTask->OnLowerLayerClose(now); + activeTask.reset(); + } + + tstate = TaskState::IDLE; + + pTaskLock->Release(*this); + + responseTimer.Cancel(); + taskStartTimeoutTimer.Cancel(); + scheduleTimer.Cancel(); + + solSeq = unsolSeq = 0; + isOnline = isSending = false; + + this->application->OnClose(); + + return true; +} + +bool MContext::OnReceive(const openpal::RSlice& apdu) +{ + if (!this->isOnline) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, "Ignorning rx data while offline"); + return false; + } + + APDUResponseHeader header; + if (!APDUHeaderParser::ParseResponse(apdu, header, &this->logger)) + { + return true; + } + + + FORMAT_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, + "FIR: %i FIN: %i CON: %i UNS: %i SEQ: %i FUNC: %s IIN: [0x%02x, 0x%02x]", + header.control.FIR, + header.control.FIN, + header.control.CON, + header.control.UNS, + header.control.SEQ, + FunctionCodeToString(header.function), + header.IIN.LSB, + header.IIN.MSB); + + this->OnParsedHeader(apdu, header, apdu.Skip(APDU_RESPONSE_HEADER_SIZE)); + return true; +} + +bool MContext::OnSendResult(bool isSucccess) +{ + if (!this->isOnline || !this->isSending) + { + return false; + } + + this->isSending = false; + this->CheckConfirmTransmit(); + this->CheckForTask(); + return true; +} + +void MContext::CheckForTask() +{ + if (isOnline) + { + this->tstate = this->OnStartEvent(); + } +} + +void MContext::OnResponseTimeout() +{ + if (isOnline) + { + this->tstate = this->OnResponseTimeoutEvent(); + } +} + +void MContext::CompleteActiveTask() +{ + if (this->activeTask) + { + if (this->activeTask->IsRecurring()) + { + this->scheduler.Schedule(std::move(this->activeTask)); + } + else + { + this->activeTask.reset(); + } + + pTaskLock->Release(*this); + this->PostCheckForTask(); + } +} + +void MContext::OnParsedHeader(const RSlice& apdu, const APDUResponseHeader& header, const RSlice& objects) +{ + // Note: this looks silly, but OnParsedHeader() is virtual and can be overriden to do SA + this->ProcessAPDU(header, objects); +} + +/// --- command handlers ---- + +void MContext::DirectOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config) +{ + this->ScheduleAdhocTask(CommandTask::CreateDirectOperate(std::move(commands), *application, callback, config, logger)); +} + +void MContext::SelectAndOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config) +{ + this->ScheduleAdhocTask(CommandTask::CreateSelectAndOperate(std::move(commands), *application, callback, config, logger)); +} + +void MContext::ProcessAPDU(const APDUResponseHeader& header, const RSlice& objects) +{ + switch (header.function) + { + case(FunctionCode::UNSOLICITED_RESPONSE) : + this->ProcessUnsolicitedResponse(header, objects); + break; + case(FunctionCode::RESPONSE) : + this->ProcessResponse(header, objects); + break; + default: + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Ignoring unsupported function code: %s", FunctionCodeToString(header.function)); + break; + } +} + +void MContext::ProcessIIN(const IINField& iin) +{ + if (iin.IsSet(IINBit::DEVICE_RESTART) && !this->params.ignoreRestartIIN) + { + this->tasks.clearRestart->Demand(); + this->tasks.assignClass->Demand(); + this->tasks.startupIntegrity->Demand(); + this->tasks.enableUnsol->Demand(); + } + + if (iin.IsSet(IINBit::EVENT_BUFFER_OVERFLOW) && this->params.integrityOnEventOverflowIIN) + { + this->tasks.startupIntegrity->Demand(); + } + + if (iin.IsSet(IINBit::NEED_TIME)) + { + switch (this->params.timeSyncMode) + { + case(TimeSyncMode::SerialTimeSync): + this->tasks.timeSync->Demand(); + break; + default: + break; + } + } + + if ((iin.IsSet(IINBit::CLASS1_EVENTS) && this->params.eventScanOnEventsAvailableClassMask.HasClass1()) || + (iin.IsSet(IINBit::CLASS2_EVENTS) && this->params.eventScanOnEventsAvailableClassMask.HasClass2()) || + (iin.IsSet(IINBit::CLASS3_EVENTS) && this->params.eventScanOnEventsAvailableClassMask.HasClass3())) + { + this->tasks.eventScan->Demand(); + } + + this->application->OnReceiveIIN(iin); +} + +void MContext::ProcessUnsolicitedResponse(const APDUResponseHeader& header, const RSlice& objects) +{ + if (!header.control.UNS) + { + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Ignoring unsolicited response without UNS bit set"); + return; + } + + auto result = MeasurementHandler::ProcessMeasurements(objects, logger, SOEHandler.get()); + + if ((result == ParseResult::OK) && header.control.CON) + { + this->QueueConfirm(APDUHeader::UnsolicitedConfirm(header.control.SEQ)); + } + + this->ProcessIIN(header.IIN); +} + +void MContext::ProcessResponse(const APDUResponseHeader& header, const RSlice& objects) +{ + this->tstate = this->OnResponseEvent(header, objects); + this->ProcessIIN(header.IIN); // TODO - should we process IIN bits for unexpected responses? +} + +void MContext::QueueConfirm(const APDUHeader& header) +{ + this->confirmQueue.push_back(header); + this->CheckConfirmTransmit(); +} + +bool MContext::CheckConfirmTransmit() +{ + if (this->isSending || this->confirmQueue.empty()) + { + return false; + } + + auto confirm = this->confirmQueue.front(); + APDUWrapper wrapper(this->txBuffer.GetWSlice()); + wrapper.SetFunction(confirm.function); + wrapper.SetControl(confirm.control); + this->Transmit(wrapper.ToRSlice()); + this->confirmQueue.pop_front(); + return true; +} + +void MContext::Transmit(const RSlice& data) +{ + logging::ParseAndLogRequestTx(this->logger, data); + assert(!this->isSending); + this->isSending = true; + this->lower->BeginTransmit(data); +} + +void MContext::StartResponseTimer() +{ + auto timeout = [this]() + { + this->OnResponseTimeout(); + }; + this->responseTimer.Start(this->params.responseTimeout, timeout); +} + +void MContext::PostCheckForTask() +{ + auto callback = [this]() + { + this->CheckForTask(); + }; + this->executor->Post(callback); +} + +std::shared_ptr MContext::AddScan(openpal::TimeDuration period, const HeaderBuilderT& builder, TaskConfig config) +{ + auto task = std::make_shared(builder, true, period, params.taskRetryPeriod, *application, *SOEHandler, logger, config); + this->ScheduleRecurringPollTask(task); + return task; +} + +std::shared_ptr MContext::AddClassScan(const ClassField& field, openpal::TimeDuration period, TaskConfig config) +{ + auto build = [field](HeaderWriter & writer) -> bool + { + return build::WriteClassHeaders(writer, field); + }; + return this->AddScan(period, build, config); +} + +std::shared_ptr MContext::AddAllObjectsScan(GroupVariationID gvId, openpal::TimeDuration period, TaskConfig config) +{ + auto build = [gvId](HeaderWriter & writer) -> bool + { + return writer.WriteHeader(gvId, QualifierCode::ALL_OBJECTS); + }; + return this->AddScan(period, build, config); +} + +std::shared_ptr MContext::AddRangeScan(GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, TaskConfig config) +{ + auto build = [gvId, start, stop](HeaderWriter & writer) -> bool + { + return writer.WriteRangeHeader(QualifierCode::UINT16_START_STOP, gvId, start, stop); + }; + return this->AddScan(period, build, config); +} + +void MContext::Scan(const HeaderBuilderT& builder, TaskConfig config) +{ + auto task = std::make_shared(builder, false, TimeDuration::Max(), params.taskRetryPeriod, *application, *SOEHandler, logger, config); + this->ScheduleAdhocTask(task); +} + +void MContext::ScanClasses(const ClassField& field, TaskConfig config) +{ + auto configure = [field](HeaderWriter & writer) -> bool + { + return build::WriteClassHeaders(writer, field); + }; + this->Scan(configure, config); +} + +void MContext::ScanAllObjects(GroupVariationID gvId, TaskConfig config) +{ + auto configure = [gvId](HeaderWriter & writer) -> bool + { + return writer.WriteHeader(gvId, QualifierCode::ALL_OBJECTS); + }; + this->Scan(configure, config); +} + +void MContext::ScanRange(GroupVariationID gvId, uint16_t start, uint16_t stop, TaskConfig config) +{ + auto configure = [gvId, start, stop](HeaderWriter & writer) -> bool + { + return writer.WriteRangeHeader(QualifierCode::UINT16_START_STOP, gvId, start, stop); + }; + this->Scan(configure, config); +} + +void MContext::Write(const TimeAndInterval& value, uint16_t index, TaskConfig config) +{ + auto builder = [value, index](HeaderWriter & writer) -> bool + { + return writer.WriteSingleIndexedValue(QualifierCode::UINT16_CNT_UINT16_INDEX, Group50Var4::Inst(), value, index); + }; + + auto task = std::make_shared(*this->application, "WRITE TimeAndInterval", FunctionCode::WRITE, builder, this->logger, config); + this->ScheduleAdhocTask(task); +} + +void MContext::Restart(RestartType op, const RestartOperationCallbackT& callback, TaskConfig config) +{ + auto task = std::make_shared(*this->application, op, callback, this->logger, config); + this->ScheduleAdhocTask(task); +} + +void MContext::PerformFunction(const std::string& name, opendnp3::FunctionCode func, const HeaderBuilderT& builder, TaskConfig config) +{ + auto task = std::make_shared(*this->application, name, func, builder, this->logger, config); + this->ScheduleAdhocTask(task); +} + +void MContext::SetTaskStartTimeout(const openpal::MonotonicTimestamp& time) +{ + auto action = [this]() + { + this->scheduler.CheckTaskStartTimeout(executor->GetTime()); + }; + + this->taskStartTimeoutTimer.Restart(time, action); +} + +/// ------ private helpers ---------- + +void MContext::ScheduleRecurringPollTask(const std::shared_ptr& task) +{ + this->tasks.BindTask(task); + + if (this->isOnline) + { + this->scheduler.Schedule(task); + this->PostCheckForTask(); + } +} + +void MContext::ScheduleAdhocTask(const std::shared_ptr& task) +{ + const auto NOW = this->executor->GetTime(); + + task->ConfigureStartExpiration(NOW.Add(params.taskStartTimeout)); + + if (this->isOnline) + { + if (this->MeetsUserRequirements(task)) + { + this->scheduler.Schedule(std::move(task)); + this->CheckForTask(); + } + else + { + // task is failed because an SA user doesn't exist + task->OnNoUser(NOW); + } + } + else + { + // can't run this task since we're offline so fail it immediately + task->OnLowerLayerClose(NOW); + } +} + +MContext::TaskState MContext::BeginNewTask(const std::shared_ptr& task) +{ + this->activeTask = task; + this->activeTask->OnStart(); + FORMAT_LOG_BLOCK(logger, flags::INFO, "Begining task: %s", this->activeTask->Name()); + return this->ResumeActiveTask(); +} + +MContext::TaskState MContext::ResumeActiveTask() +{ + if (!this->pTaskLock->Acquire(*this)) + { + return TaskState::TASK_READY; + } + + APDURequest request(this->txBuffer.GetWSlice()); + + /// try to build a requst for the task + if (!this->activeTask->BuildRequest(request, this->solSeq)) + { + activeTask->OnInternalError(executor->GetTime()); + this->CompleteActiveTask(); + return TaskState::IDLE; + } + + this->StartResponseTimer(); + auto apdu = request.ToRSlice(); + this->RecordLastRequest(apdu); + this->Transmit(apdu); + + return TaskState::WAIT_FOR_RESPONSE; +} + +//// --- State tables --- + +MContext::TaskState MContext::OnResponseEvent(const APDUResponseHeader& header, const RSlice& objects) +{ + switch (tstate) + { + case(TaskState::WAIT_FOR_RESPONSE) : + return OnResponse_WaitForResponse(header, objects); + default: + FORMAT_LOG_BLOCK(logger, flags::WARN, "Not expecting a response, sequence: %u", header.control.SEQ); + return tstate; + } +} + +MContext::TaskState MContext::OnStartEvent() +{ + switch (tstate) + { + case(TaskState::IDLE) : + return StartTask_Idle(); + case(TaskState::TASK_READY) : + return StartTask_TaskReady(); + default: + return tstate; + } +} + +MContext::TaskState MContext::OnResponseTimeoutEvent() +{ + switch (tstate) + { + case(TaskState::WAIT_FOR_RESPONSE) : + return OnResponseTimeout_WaitForResponse(); + default: + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Unexpected response timeout"); + return tstate; + } +} + +//// --- State actions ---- + +MContext::TaskState MContext::StartTask_Idle() +{ + if (this->isSending) + { + return TaskState::IDLE; + } + + MonotonicTimestamp next; + auto task = this->scheduler.GetNext(executor->GetTime(), next); + + if (task) + { + return this->BeginNewTask(task); + } + else + { + // restart the task timer + if (!next.IsMax()) + { + scheduleTimer.Restart(next, [this]() + { + this->CheckForTask(); + }); + } + return TaskState::IDLE; + } +} + +MContext::TaskState MContext::StartTask_TaskReady() +{ + if (this->isSending) + { + return TaskState::TASK_READY; + } + + return this->ResumeActiveTask(); +} + +MContext::TaskState MContext::OnResponse_WaitForResponse(const APDUResponseHeader& header, const RSlice& objects) +{ + if (header.control.SEQ != this->solSeq) + { + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Response with bad sequence: %u", header.control.SEQ); + return TaskState::WAIT_FOR_RESPONSE; + } + + this->responseTimer.Cancel(); + + this->solSeq.Increment(); + + auto now = this->executor->GetTime(); + + auto result = this->activeTask->OnResponse(header, objects, now); + + if (header.control.CON) + { + this->QueueConfirm(APDUHeader::SolicitedConfirm(header.control.SEQ)); + } + + switch (result) + { + case(IMasterTask::ResponseResult::OK_CONTINUE) : + this->StartResponseTimer(); + return TaskState::WAIT_FOR_RESPONSE; + case(IMasterTask::ResponseResult::OK_REPEAT) : + return StartTask_TaskReady(); + default: + // task completed or failed, either way go back to idle + this->CompleteActiveTask(); + return TaskState::IDLE; + } +} + +MContext::TaskState MContext::OnResponseTimeout_WaitForResponse() +{ + auto now = this->executor->GetTime(); + this->activeTask->OnResponseTimeout(now); + this->solSeq.Increment(); + this->CompleteActiveTask(); + return TaskState::IDLE; +} +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.h new file mode 100644 index 0000000..d4b596e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterContext.h @@ -0,0 +1,222 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MASTERCONTEXT_H +#define OPENDNP3_MASTERCONTEXT_H + +#include +#include +#include +#include + +#include "opendnp3/LayerInterfaces.h" + +#include "opendnp3/app/AppSeqNum.h" +#include "opendnp3/app/MeasurementTypes.h" + +#include "opendnp3/gen/RestartType.h" + +#include "opendnp3/master/MasterScheduler.h" +#include "opendnp3/master/ITaskFilter.h" +#include "opendnp3/master/MasterTasks.h" +#include "opendnp3/master/ITaskLock.h" +#include "opendnp3/master/IMasterApplication.h" +#include "opendnp3/master/HeaderBuilder.h" +#include "opendnp3/master/RestartOperationResult.h" + +namespace opendnp3 +{ +/* + All of the mutable state and configuration for a master +*/ +class MContext : public IUpperLayer, private IScheduleCallback, private ITaskFilter, private openpal::Uncopyable +{ + +protected: + + enum class TaskState + { + IDLE, + TASK_READY, + WAIT_FOR_RESPONSE + }; + +public: + + MContext( + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& lower, + const std::shared_ptr& SOEHandler, + const std::shared_ptr& application, + const MasterParams& params, + ITaskLock& taskLock + ); + + openpal::Logger logger; + const std::shared_ptr executor; + const std::shared_ptr lower; + + // ------- configuration -------- + MasterParams params; + const std::shared_ptr SOEHandler; + const std::shared_ptr application; + ITaskLock* pTaskLock; + + + // ------- dynamic state --------- + bool isOnline = false; + bool isSending = false; + AppSeqNum solSeq; + AppSeqNum unsolSeq; + std::shared_ptr activeTask; + openpal::TimerRef responseTimer; + openpal::TimerRef scheduleTimer; + openpal::TimerRef taskStartTimeoutTimer; + MasterTasks tasks; + MasterScheduler scheduler; + std::deque confirmQueue; + openpal::Buffer txBuffer; + TaskState tstate; + + /// --- implement IUpperLayer ------ + + virtual bool OnLowerLayerUp() override; + + virtual bool OnLowerLayerDown() override; + + virtual bool OnReceive(const openpal::RSlice& apdu) override final; + + virtual bool OnSendResult(bool isSucccess) override final; + + /// additional virtual methods that can be overriden to implement secure authentication + + virtual void OnParsedHeader(const openpal::RSlice& apdu, const APDUResponseHeader& header, const openpal::RSlice& objects); + + virtual void RecordLastRequest(const openpal::RSlice& apdu) {} + + virtual bool MeetsUserRequirements(const std::shared_ptr& task) + { + return true; + } + + /// ITaskFilter + + virtual bool CanRun(const IMasterTask& task) override + { + return true; + } + + virtual void SetTaskStartTimeout(const openpal::MonotonicTimestamp& time) override final; + + /// methods for initiating command sequences + + void DirectOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config); + void SelectAndOperate(CommandSet&& commands, const CommandCallbackT& callback, const TaskConfig& config); + + + /// ----- public methods used to add tasks ----- + + std::shared_ptr AddScan(openpal::TimeDuration period, const HeaderBuilderT& builder, TaskConfig config = TaskConfig::Default()); + + std::shared_ptr AddAllObjectsScan(GroupVariationID gvId, openpal::TimeDuration period, TaskConfig config = TaskConfig::Default()); + + std::shared_ptr AddClassScan(const ClassField& field, openpal::TimeDuration period, TaskConfig config = TaskConfig::Default()); + + std::shared_ptr AddRangeScan(GroupVariationID gvId, uint16_t start, uint16_t stop, openpal::TimeDuration period, TaskConfig config = TaskConfig::Default()); + + /// ---- Single shot immediate scans ---- + + void Scan(const HeaderBuilderT& builder, TaskConfig config = TaskConfig::Default()); + + void ScanAllObjects(GroupVariationID gvId, TaskConfig config = TaskConfig::Default()); + + void ScanClasses(const ClassField& field, TaskConfig config = TaskConfig::Default()); + + void ScanRange(GroupVariationID gvId, uint16_t start, uint16_t stop, TaskConfig config = TaskConfig::Default()); + + /// ---- Write tasks ----- + + void Write(const TimeAndInterval& value, uint16_t index, TaskConfig config = TaskConfig::Default()); + + void Restart(RestartType op, const RestartOperationCallbackT& callback, TaskConfig config = TaskConfig::Default()); + + void PerformFunction(const std::string& name, opendnp3::FunctionCode func, const HeaderBuilderT& builder, TaskConfig config = TaskConfig::Default()); + + /// public state manipulation actions + + TaskState BeginNewTask(const std::shared_ptr& task); + + TaskState ResumeActiveTask(); + + void CompleteActiveTask(); + + void QueueConfirm(const APDUHeader& header); + + void StartResponseTimer(); + + void ProcessAPDU(const APDUResponseHeader& header, const openpal::RSlice& objects); + + void CheckForTask(); + + bool CheckConfirmTransmit(); + + void PostCheckForTask(); + + void ProcessResponse(const APDUResponseHeader& header, const openpal::RSlice& objects); + + void ProcessUnsolicitedResponse(const APDUResponseHeader& header, const openpal::RSlice& objects); + + void Transmit(const openpal::RSlice& data); + +private: + + void ScheduleRecurringPollTask(const std::shared_ptr& task); + + virtual void OnPendingTask() override + { + this->PostCheckForTask(); + } + + void ProcessIIN(const IINField& iin); + + void OnResponseTimeout(); + +protected: + + void ScheduleAdhocTask(const std::shared_ptr& task); + + /// state switch lookups + TaskState OnStartEvent(); + TaskState OnResponseEvent(const APDUResponseHeader& header, const openpal::RSlice& objects); + TaskState OnResponseTimeoutEvent(); + + /// --- state handling functions ---- + + TaskState StartTask_Idle(); + TaskState StartTask_TaskReady(); + + TaskState OnResponse_WaitForResponse(const APDUResponseHeader& header, const openpal::RSlice& objects); + TaskState OnResponseTimeout_WaitForResponse(); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.cpp new file mode 100644 index 0000000..94d02a1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.cpp @@ -0,0 +1,140 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MasterScheduler.h" + +#include "opendnp3/master/TaskComparison.h" + +#include + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +MasterScheduler::MasterScheduler(ITaskFilter& filter) : + m_filter(&filter) +{ + +} + +void MasterScheduler::Schedule(const std::shared_ptr& task) +{ + m_tasks.push_back(task); + this->RecalculateTaskStartTimeout(); +} + +std::vector>::iterator MasterScheduler::GetNextTask(const MonotonicTimestamp& now) +{ + auto runningBest = m_tasks.begin(); + + if (!m_tasks.empty()) + { + auto current = m_tasks.begin(); + ++current; + + for (; current != m_tasks.end(); ++current) + { + auto result = TaskComparison::SelectHigherPriority(now, **runningBest, **current, *m_filter); + if (result == TaskComparison::Result::Right) + { + runningBest = current; + } + } + } + + return runningBest; +} + +std::shared_ptr MasterScheduler::GetNext(const MonotonicTimestamp& now, MonotonicTimestamp& next) +{ + auto elem = GetNextTask(now); + + if (elem == m_tasks.end()) + { + next = MonotonicTimestamp::Max(); + return nullptr; + } + else + { + const bool EXPIRED = (*elem)->ExpirationTime().milliseconds <= now.milliseconds; + const bool CAN_RUN = this->m_filter->CanRun(**elem); + + if (EXPIRED && CAN_RUN) + { + std::shared_ptr ret = *elem; + m_tasks.erase(elem); + return ret; + } + else + { + next = CAN_RUN ? (*elem)->ExpirationTime() : MonotonicTimestamp::Max(); + return nullptr; + } + } +} + +void MasterScheduler::Shutdown(const MonotonicTimestamp& now) +{ + m_tasks.clear(); +} + +bool MasterScheduler::IsTimedOut(const MonotonicTimestamp& now, const std::shared_ptr& task) +{ + if (task->IsRecurring() || task->StartExpirationTime() > now) + { + return false; + } + + task->OnStartTimeout(now); + + return true; +} + +void MasterScheduler::CheckTaskStartTimeout(const openpal::MonotonicTimestamp& now) +{ + auto timedOut = [this, now](const std::shared_ptr& task) + { + return this->IsTimedOut(now, task); + }; + + // erase-remove idion (https://en.wikipedia.org/wiki/Erase-remove_idiom) + m_tasks.erase(std::remove_if(m_tasks.begin(), m_tasks.end(), timedOut), m_tasks.end()); +} + +void MasterScheduler::RecalculateTaskStartTimeout() +{ + auto min = MonotonicTimestamp::Max(); + + for(auto& task : m_tasks) + { + if (!task->IsRecurring() && (task->StartExpirationTime() < min)) + { + min = task->StartExpirationTime(); + } + } + + this->m_filter->SetTaskStartTimeout(min); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.h new file mode 100644 index 0000000..338ac88 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterScheduler.h @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MASTERSCHEDULER_H +#define OPENDNP3_MASTERSCHEDULER_H + +#include +#include +#include + +#include "opendnp3/master/UserPollTask.h" +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/IScheduleCallback.h" +#include "opendnp3/master/ITaskFilter.h" + +#include +#include +#include + +namespace opendnp3 +{ + +class MasterScheduler +{ + +public: + + explicit MasterScheduler(ITaskFilter& filter); + + /* + * Add a task to the scheduler + */ + void Schedule(const std::shared_ptr& task); + + /** + * @return Task to start or undefined pointer if no task to start + * If there is no task to start, 'next' is set to the timestamp when the scheduler should be re-evaluated + */ + std::shared_ptr GetNext(const openpal::MonotonicTimestamp& now, openpal::MonotonicTimestamp& next); + + /** + * Cleanup all existing tasks & cancel any timers + */ + void Shutdown(const openpal::MonotonicTimestamp& now); + + /** + * Check if any tasks have exceeded their start timeout + */ + void CheckTaskStartTimeout(const openpal::MonotonicTimestamp& now); + +private: + + bool IsTimedOut(const openpal::MonotonicTimestamp& now, const std::shared_ptr& task); + + void RecalculateTaskStartTimeout(); + + + std::vector>::iterator GetNextTask(const openpal::MonotonicTimestamp& now); + + ITaskFilter* m_filter; + std::vector> m_tasks; +}; + +} + + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.cpp new file mode 100644 index 0000000..3107594 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.cpp @@ -0,0 +1,61 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MasterTasks.h" + +using namespace openpal; + +namespace opendnp3 +{ + +MasterTasks::MasterTasks(const MasterParams& params, const openpal::Logger& logger, IMasterApplication& app, ISOEHandler& SOEHandler) : + enableUnsol(std::make_shared(app, params.unsolClassMask, params.taskRetryPeriod, logger)), + clearRestart(std::make_shared(app, params.taskRetryPeriod, logger)), + assignClass(std::make_shared(app, params.taskRetryPeriod, logger)), + startupIntegrity(std::make_shared(app, SOEHandler, params.startupIntegrityClassMask, params.taskRetryPeriod, logger)), + disableUnsol(std::make_shared(app, params.disableUnsolOnStartup, params.taskRetryPeriod, logger)), + timeSync(std::make_shared(app, logger)), + eventScan(std::make_shared(app, SOEHandler, params.eventScanOnEventsAvailableClassMask, params.taskRetryPeriod, logger)) +{ + +} + +void MasterTasks::Initialize(MasterScheduler& scheduler) +{ + scheduler.Schedule(enableUnsol); + scheduler.Schedule(clearRestart); + scheduler.Schedule(assignClass); + scheduler.Schedule(startupIntegrity); + scheduler.Schedule(disableUnsol); + scheduler.Schedule(timeSync); + scheduler.Schedule(eventScan); + + for (auto& task : boundTasks) + { + scheduler.Schedule(task); + } +} + +void MasterTasks::BindTask(const std::shared_ptr& task) +{ + boundTasks.push_back(task); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.h new file mode 100644 index 0000000..426ac9c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MasterTasks.h @@ -0,0 +1,74 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MASTERTASKS_H +#define OPENDNP3_MASTERTASKS_H + +#include "opendnp3/master/ClearRestartTask.h" +#include "opendnp3/master/AssignClassTask.h" +#include "opendnp3/master/EnableUnsolicitedTask.h" +#include "opendnp3/master/StartupIntegrityPoll.h" +#include "opendnp3/master/DisableUnsolicitedTask.h" +#include "opendnp3/master/SerialTimeSyncTask.h" +#include "opendnp3/master/CommandTask.h" +#include "opendnp3/master/EventScanTask.h" + +#include "opendnp3/master/MasterParams.h" +#include "opendnp3/master/MasterScheduler.h" + +#include + +namespace opendnp3 +{ + +class IMasterApplication; + +class MasterTasks +{ + +public: + + MasterTasks(const MasterParams& params, const openpal::Logger& logger, IMasterApplication& application, ISOEHandler& SOEHandler); + + void Initialize(MasterScheduler& scheduler); + + // master tasks that can be "failed" (startup and in response to IIN bits) + const std::shared_ptr enableUnsol; + const std::shared_ptr clearRestart; + const std::shared_ptr assignClass; + const std::shared_ptr startupIntegrity; + const std::shared_ptr disableUnsol; + const std::shared_ptrtimeSync; + const std::shared_ptr eventScan; + + + void BindTask(const std::shared_ptr& task); + +private: + + std::vector> boundTasks; + +}; + +} + + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.cpp new file mode 100644 index 0000000..6aa28cd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.cpp @@ -0,0 +1,254 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MeasurementHandler.h" + +#include "opendnp3/app/parsing/APDUParser.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +ParseResult MeasurementHandler::ProcessMeasurements(const openpal::RSlice& objects, openpal::Logger& logger, ISOEHandler* pHandler) +{ + MeasurementHandler handler(logger, pHandler); + return APDUParser::Parse(objects, handler, &logger); +} + +MeasurementHandler::MeasurementHandler(const openpal::Logger& logger_, ISOEHandler* pSOEHandler_) : + logger(logger_), + txInitiated(false), + pSOEHandler(pSOEHandler_), + ctoMode(TimestampMode::INVALID), + commonTimeOccurence(0) +{ + +} + +MeasurementHandler::~MeasurementHandler() +{ + if (txInitiated) + { + Transaction::End(pSOEHandler); + } +} + +TimestampMode MeasurementHandler::ModeFromType(GroupVariation gv) +{ + return HasAbsoluteTime(gv) ? TimestampMode::SYNCHRONIZED : TimestampMode::INVALID; +} + + +void MeasurementHandler::CheckForTxStart() +{ + if (!txInitiated) + { + txInitiated = true; + Transaction::Start(pSOEHandler); + } +} + +IINField MeasurementHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + this->CheckForTxStart(); + + auto transform = [](const Group50Var1 & input) -> DNPTime + { + return input.time; + }; + + auto collection = Map(values, transform); + + HeaderInfo info(header.enumeration, header.GetQualifierCode(), TimestampMode::INVALID, header.headerIndex); + this->pSOEHandler->Process(info, collection); + + return IINField(); +} + +IINField MeasurementHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + Group51Var1 cto; + if (values.ReadOnlyValue(cto)) + { + ctoMode = TimestampMode::SYNCHRONIZED; + commonTimeOccurence = cto.time; + } + return IINField::Empty(); +} + +IINField MeasurementHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + Group51Var2 cto; + if (values.ReadOnlyValue(cto)) + { + ctoMode = TimestampMode::UNSYNCHRONIZED; + commonTimeOccurence = cto.time; + } + + return IINField::Empty(); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + return this->LoadValuesWithTransformTo(header, values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + if (header.enumeration == GroupVariation::Group2Var3) + { + return this->ProcessWithCTO(header, values); + } + else + { + return this->LoadValues(header, ModeFromType(header.enumeration), values); + } +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + if (header.enumeration == GroupVariation::Group4Var3) + { + return this->ProcessWithCTO(header, values); + } + else + { + return this->LoadValues(header, ModeFromType(header.enumeration), values); + } +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValues(header, ModeFromType(header.enumeration), values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValuesWithTransformTo(header, values); +} + +IINField MeasurementHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + return this->LoadValuesWithTransformTo(header, values); +} + +// ----------- Conversion routines from DNP3 types to API types ----------- + +SecurityStat MeasurementHandler::Convert(const Group121Var1& meas) +{ + return SecurityStat(meas.flags, meas.assocId, meas.value); +} + +SecurityStat MeasurementHandler::Convert(const Group122Var1& meas) +{ + return SecurityStat(meas.flags, meas.assocId, meas.value); +} + +SecurityStat MeasurementHandler::Convert(const Group122Var2& meas) +{ + return SecurityStat(meas.flags, meas.assocId, meas.value, meas.time); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.h new file mode 100644 index 0000000..fc17f17 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MeasurementHandler.h @@ -0,0 +1,178 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MEASUREMENTHANDLER_H +#define OPENDNP3_MEASUREMENTHANDLER_H + +#include +#include + +#include "opendnp3/master/ISOEHandler.h" +#include "opendnp3/app/APDUHeader.h" +#include "opendnp3/app/parsing/ParseResult.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/parsing/Collections.h" +#include "opendnp3/gen/Attributes.h" +#include "opendnp3/LogLevels.h" + +namespace opendnp3 +{ + +/** + * Dedicated class for processing response data in the master. + */ +class MeasurementHandler final : public IAPDUHandler +{ + +public: + + /** + * Static helper function for interpreting a response as a measurement response + */ + static ParseResult ProcessMeasurements(const openpal::RSlice& objects, openpal::Logger& logger, ISOEHandler* pHandler); + + // TODO + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override + { + return true; + }; + + /** + * Creates a new ResponseLoader instance. + * + * @param logger the Logger that the loader should use for message reporting + */ + MeasurementHandler(const openpal::Logger& logger, ISOEHandler* pSOEHandler); + + ~MeasurementHandler(); + +private: + + openpal::Logger logger; + + static TimestampMode ModeFromType(GroupVariation gv); + + + IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + + // Handle the CTO objects + IINField ProcessHeader(const CountHeader& header, const ICollection& cto) override; + IINField ProcessHeader(const CountHeader& header, const ICollection& cto) override; + + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override; + + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override; + + + template + IINField LoadValuesWithTransformTo(const HeaderRecord& record, const ICollection>& values) + { + auto transform = [](const Indexed& input) -> Indexed + { + return Convert(input); + }; + + auto collection = Map, Indexed>(values, transform); + + return this->LoadValues(record, ModeFromType(record.enumeration), collection); + } + + template + IINField LoadValues(const HeaderRecord& record, TimestampMode tsmode, const ICollection>& values) + { + this->CheckForTxStart(); + HeaderInfo info(record.enumeration, record.GetQualifierCode(), tsmode, record.headerIndex); + this->pSOEHandler->Process(info, values); + return IINField(); + } + + template + IINField ProcessWithCTO(const HeaderRecord& record, const ICollection>& values); + + bool txInitiated; + ISOEHandler* pSOEHandler; + + TimestampMode ctoMode; + DNPTime commonTimeOccurence; + + void CheckForTxStart(); + + static SecurityStat Convert(const Group121Var1& value); + static SecurityStat Convert(const Group122Var1& value); + static SecurityStat Convert(const Group122Var2& value); + + template + static Indexed Convert(const Indexed& input) + { + return WithIndex(Convert(input.value), input.index); + } + +}; + +template +IINField MeasurementHandler::ProcessWithCTO(const HeaderRecord& record, const ICollection>& values) +{ + if (ctoMode == TimestampMode::INVALID) + { + FORMAT_LOG_BLOCK(logger, flags::WARN, "No prior CTO objects for %s", GroupVariationToString(record.enumeration)); + return IINField(IINBit::PARAM_ERROR); + } + + const auto MODE = this->ctoMode; + const auto cto = this->commonTimeOccurence; + + auto transform = [cto](const Indexed& input) -> Indexed + { + Indexed copy(input); + copy.value.time = DNPTime(input.value.time + cto); + return copy; + }; + + auto adjusted = Map, Indexed>(values, transform); + + return this->LoadValues(record, MODE, adjusted); +} + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.cpp new file mode 100644 index 0000000..ee14324 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.cpp @@ -0,0 +1,96 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MultidropTaskLock.h" + +namespace opendnp3 +{ + +MultidropTaskLock::MultidropTaskLock() : m_is_online(false), m_active(nullptr) +{ + +} + +bool MultidropTaskLock::Acquire(IScheduleCallback& callback) +{ + if (!m_is_online) + { + return false; + } + + if (m_active) + { + if (&callback == m_active) + { + return true; + } + + + this->AddIfNotContained(callback); + return false; + } + else + { + m_active = &callback; + return true; + } +} + +bool MultidropTaskLock::Release(IScheduleCallback& callback) +{ + if (m_active != &callback) + { + return false; + } + + m_active = nullptr; + + if (!m_is_online) + { + return true; + } + + if (m_callback_queue.empty()) + { + return true; + } + + m_active = m_callback_queue.front(); + m_callback_queue.pop_front(); + m_callback_set.erase(m_active); + m_active->OnPendingTask(); + return true; +} + +bool MultidropTaskLock::AddIfNotContained(IScheduleCallback& callback) +{ + auto result = m_callback_set.find(&callback); + if (result != m_callback_set.end()) + { + return false; + } + + m_callback_set.insert(&callback); + m_callback_queue.push_back(&callback); + return true; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.h new file mode 100644 index 0000000..50c5e62 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/MultidropTaskLock.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MULTIDROPTASKLOCK_H +#define OPENDNP3_MULTIDROPTASKLOCK_H + +#include "opendnp3/master/ITaskLock.h" + +#include +#include + +namespace opendnp3 +{ + +class MultidropTaskLock final : public opendnp3::ITaskLock +{ +public: + + MultidropTaskLock(); + + /// these are controlled by the link layer router + void SetOnline() + { + m_is_online = true; + } + + void SetOffline() + { + m_is_online = false; + } + + virtual bool Acquire(IScheduleCallback&) override; + virtual bool Release(IScheduleCallback&) override; + +private: + + bool AddIfNotContained(IScheduleCallback&); + + bool m_is_online; + std::set m_callback_set; + std::deque m_callback_queue; + + IScheduleCallback* m_active; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.cpp new file mode 100644 index 0000000..a717ab1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.cpp @@ -0,0 +1,96 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "PollTaskBase.h" + +#include "opendnp3/master/MeasurementHandler.h" + +#include "opendnp3/LogLevels.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +PollTaskBase::PollTaskBase(IMasterApplication& application, ISOEHandler& soeHandler, openpal::MonotonicTimestamp expiration, openpal::Logger logger, TaskConfig config) : + IMasterTask(application, expiration, logger, config), + rxCount(0), + pSOEHandler(&soeHandler) +{ + +} + +void PollTaskBase::Initialize() +{ + rxCount = 0; +} + +IMasterTask::ResponseResult PollTaskBase::ProcessResponse(const APDUResponseHeader& header, const openpal::RSlice& objects) +{ + if (header.control.FIR) + { + if (rxCount > 0) + { + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Ignoring unexpected FIR frame"); + return ResponseResult::ERROR_BAD_RESPONSE; + } + else + { + return ProcessMeasurements(header, objects); + } + } + else + { + if (rxCount > 0) + { + return ProcessMeasurements(header, objects); + } + else + { + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Ignoring unexpected non-FIR frame"); + return ResponseResult::ERROR_BAD_RESPONSE; + } + } +} + +IMasterTask::ResponseResult PollTaskBase::ProcessMeasurements(const APDUResponseHeader& header, const openpal::RSlice& objects) +{ + ++rxCount; + + if (MeasurementHandler::ProcessMeasurements(objects, logger, pSOEHandler) == ParseResult::OK) + { + if (header.control.FIN) + { + return ResponseResult::OK_FINAL; + } + else + { + return ResponseResult::OK_CONTINUE; + } + } + else + { + return ResponseResult::ERROR_BAD_RESPONSE; + } +} + +} //end ns diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.h new file mode 100644 index 0000000..6c84743 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/PollTaskBase.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_POLLTASKBASE_H +#define OPENDNP3_POLLTASKBASE_H + +#include "opendnp3/master/IMasterTask.h" + +#include + +namespace opendnp3 +{ + +class ISOEHandler; + +/** + * Base class for measurement polls + */ +class PollTaskBase : public IMasterTask, openpal::Uncopyable +{ + +public: + + PollTaskBase(IMasterApplication& application, ISOEHandler& soeHandler, openpal::MonotonicTimestamp expiration, openpal::Logger logger, TaskConfig config); + + virtual const char* Name() const override final + { + return "Application Poll"; + }; + +protected: + + virtual ResponseResult ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) override final; + + ResponseResult ProcessMeasurements(const APDUResponseHeader& header, const openpal::RSlice& objects); + + virtual void Initialize() override final; + + uint16_t rxCount; + ISOEHandler* pSOEHandler; +}; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.cpp new file mode 100644 index 0000000..b1180b9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.cpp @@ -0,0 +1,132 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "opendnp3/master/RestartOperationTask.h" + +#include "opendnp3/master/TaskPriority.h" +#include "opendnp3/app/parsing/APDUParser.h" + +using namespace openpal; + +namespace opendnp3 +{ + +RestartOperationTask::RestartOperationTask(IMasterApplication& app, RestartType operationType, const RestartOperationCallbackT& callback, openpal::Logger logger, const TaskConfig& config) : + SimpleRequestTaskBase(app, ToFunctionCode(operationType), priority::USER_REQUEST, [](HeaderWriter&) +{ + return true; +}, logger, config), +m_callback(callback), +m_duration(TimeDuration::Min()) +{ + +} + +bool RestartOperationTask::IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) +{ + if (headerCount != 0) + { + return false; + } + + switch (gv) + { + case(GroupVariation::Group52Var1) : + case(GroupVariation::Group52Var2) : + return true; + default: + return false; + } +} + +char const* RestartOperationTask::Name() const +{ + return FunctionCodeToString(m_func); +} + +IMasterTask::ResponseResult RestartOperationTask::ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) +{ + if (!(ValidateSingleResponse(header) && ValidateInternalIndications(header))) + { + return ResponseResult::ERROR_BAD_RESPONSE; + } + + if (objects.IsEmpty()) + { + return ResponseResult::ERROR_BAD_RESPONSE; + } + + auto result = APDUParser::Parse(objects, *this, &logger); + + return (result == ParseResult::OK) ? ResponseResult::OK_FINAL : ResponseResult::ERROR_BAD_RESPONSE; +} + +IINField RestartOperationTask::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + Group52Var1 value; + if (values.ReadOnlyValue(value)) + { + this->m_duration = TimeDuration::Seconds(value.time); + return IINField::Empty(); + } + else + { + return IINBit::PARAM_ERROR; + } +} + +IINField RestartOperationTask::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + Group52Var2 value; + if (values.ReadOnlyValue(value)) + { + this->m_duration = TimeDuration::Milliseconds(value.time); + return IINField::Empty(); + } + else + { + return IINBit::PARAM_ERROR; + } +} + +FunctionCode RestartOperationTask::ToFunctionCode(RestartType op) +{ + return (op == RestartType::COLD) ? FunctionCode::COLD_RESTART : FunctionCode::WARM_RESTART; +} + +IMasterTask::TaskState RestartOperationTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + if (this->Errors().Any()) + { + this->m_callback(RestartOperationResult(TaskCompletion::FAILURE_BAD_RESPONSE, m_duration)); + } + else + { + this->m_callback(RestartOperationResult(result, m_duration)); + } + + return TaskState::Infinite(); +} + +} //end ns + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.h new file mode 100644 index 0000000..8b20e65 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/RestartOperationTask.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_RESTART_OPERATION_TASK_H +#define OPENDNP3_RESTART_OPERATION_TASK_H + +#include "opendnp3/master/SimpleRequestTaskBase.h" +#include "opendnp3/master/RestartOperationResult.h" +#include "opendnp3/app/parsing/IAPDUHandler.h" + +#include "opendnp3/gen/RestartType.h" + +namespace opendnp3 +{ + +class RestartOperationTask final : public SimpleRequestTaskBase, private IAPDUHandler +{ + +public: + + RestartOperationTask(IMasterApplication& app, RestartType operationType, const RestartOperationCallbackT& callback, openpal::Logger logger, const TaskConfig& config); + + virtual char const* Name() const override; + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override; + +private: + + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override; + + static FunctionCode ToFunctionCode(RestartType op); + + RestartOperationCallbackT m_callback; + openpal::TimeDuration m_duration; + + + virtual IMasterTask::ResponseResult ProcessResponse(const opendnp3::APDUResponseHeader& header, const openpal::RSlice& objects) override; + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; +}; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/ScanResult.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ScanResult.h new file mode 100644 index 0000000..e4fa191 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/ScanResult.h @@ -0,0 +1,40 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SCANRESULT_H +#define OPENDNP3_SCANRESULT_H + +#include "opendnp3/gen/ScanStatus.h" + +namespace opendnp3 +{ + +/** +* A struct to hold status information about a particular poll/scan +*/ +struct ScanResult +{ + ScanStatus status; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.cpp new file mode 100644 index 0000000..d33356f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.cpp @@ -0,0 +1,125 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "SerialTimeSyncTask.h" + +#include "opendnp3/objects/Group50.h" +#include "opendnp3/app/parsing/APDUParser.h" +#include "opendnp3/app/APDUBuilders.h" +#include "opendnp3/master/TimeSyncHandler.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +SerialTimeSyncTask::SerialTimeSyncTask(IMasterApplication& app, openpal::Logger logger) : + IMasterTask(app, MonotonicTimestamp::Max(), logger, TaskConfig::Default()), + delay(-1) +{} + +void SerialTimeSyncTask::Initialize() +{ + delay = -1; +} + +bool SerialTimeSyncTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + if (delay < 0) + { + start = pApplication->Now(); + build::MeasureDelay(request, seq); + } + else + { + auto now = pApplication->Now(); + Group50Var1 time; + time.time = DNPTime(now.msSinceEpoch + delay); + request.SetFunction(FunctionCode::WRITE); + request.SetControl(AppControlField::Request(seq)); + auto writer = request.GetWriter(); + writer.WriteSingleValue(QualifierCode::UINT8_CNT, time); + } + + return true; +} + +IMasterTask::TaskState SerialTimeSyncTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_BAD_RESPONSE) : + return TaskState::Disabled(); + default: + return TaskState::Infinite(); + } +} + +IMasterTask::ResponseResult SerialTimeSyncTask::ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) +{ + return (delay < 0) ? OnResponseDelayMeas(response, objects) : OnResponseWriteTime(response, objects); +} + +IMasterTask::ResponseResult SerialTimeSyncTask::OnResponseDelayMeas(const APDUResponseHeader& response, const openpal::RSlice& objects) +{ + if (ValidateSingleResponse(response)) + { + TimeSyncHandler handler; + auto result = APDUParser::Parse(objects, handler, &logger); + if (result == ParseResult::OK) + { + uint16_t rtuTurnAroundTime; + if (handler.GetTimeDelay(rtuTurnAroundTime)) + { + auto now = pApplication->Now(); + auto sendReceieveTime = now.msSinceEpoch - start.msSinceEpoch; + + // The later shouldn't happen, but could cause a negative delay which would result in a weird time setting + delay = (sendReceieveTime >= rtuTurnAroundTime) ? (sendReceieveTime - rtuTurnAroundTime) / 2 : 0; + + return ResponseResult::OK_REPEAT; + } + else + { + return ResponseResult::ERROR_BAD_RESPONSE; + } + } + else + { + return ResponseResult::ERROR_BAD_RESPONSE; + } + } + else + { + return ResponseResult::ERROR_BAD_RESPONSE; + } +} + +IMasterTask::ResponseResult SerialTimeSyncTask::OnResponseWriteTime(const APDUResponseHeader& header, const openpal::RSlice& objects) +{ + return ValidateNullResponse(header, objects) ? ResponseResult::OK_FINAL : ResponseResult::ERROR_BAD_RESPONSE; +} + +} //ens ns + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.h new file mode 100644 index 0000000..a6530e7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SerialTimeSyncTask.h @@ -0,0 +1,93 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SERIALTIMESYNCTASK_H +#define OPENDNP3_SERIALTIMESYNCTASK_H + +#include + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/TaskPriority.h" + +namespace opendnp3 +{ + +// Synchronizes the time on the outstation +class SerialTimeSyncTask : public IMasterTask +{ + +public: + SerialTimeSyncTask(IMasterApplication& app, openpal::Logger logger); + + virtual char const* Name() const override final + { + return "serial time sync"; + } + + virtual int Priority() const override final + { + return priority::TIME_SYNC; + } + + virtual bool BlocksLowerPriority() const override final + { + return true; + } + + virtual bool IsRecurring() const override final + { + return true; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override final; + +private: + + virtual MasterTaskType GetTaskType() const override final + { + return MasterTaskType::SERIAL_TIME_SYNC; + } + + virtual bool IsEnabled() const override final + { + return true; + } + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override final; + + virtual ResponseResult ProcessResponse(const APDUResponseHeader& response, const openpal::RSlice& objects) override final; + + ResponseResult OnResponseDelayMeas(const APDUResponseHeader& header, const openpal::RSlice& objects); + + ResponseResult OnResponseWriteTime(const APDUResponseHeader& header, const openpal::RSlice& objects); + + virtual void Initialize() override final; + + // < 0 implies the delay measure hasn't happened yet + int64_t delay; + + // what time we sent the delay meas + openpal::UTCTimestamp start; +}; + +} //ens ns + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.cpp new file mode 100644 index 0000000..caf3506 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.cpp @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "opendnp3/master/SimpleRequestTaskBase.h" + +using namespace openpal; + +namespace opendnp3 +{ + +SimpleRequestTaskBase::SimpleRequestTaskBase(IMasterApplication& app, FunctionCode func, int taskPriority, const HeaderBuilderT& format, openpal::Logger logger, const TaskConfig& config) : + IMasterTask(app, MonotonicTimestamp::Min(), logger, config), + m_func(func), + m_priority(taskPriority), + m_format(format) +{ + +} + + +bool SimpleRequestTaskBase::BuildRequest(APDURequest& request, uint8_t seq) +{ + request.SetFunction(m_func); + request.SetControl(AppControlField::Request(seq)); + auto writer = request.GetWriter(); + return m_format(writer); +} + +} //end ns + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.h new file mode 100644 index 0000000..445a842 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/SimpleRequestTaskBase.h @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SIMPLE_REQUEST_TASK_BASE_H +#define OPENDNP3_SIMPLE_REQUEST_TASK_BASE_H + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/HeaderBuilder.h" + +#include + +namespace opendnp3 +{ + +class IMasterApplication; + +class SimpleRequestTaskBase : public IMasterTask +{ + +public: + + SimpleRequestTaskBase(IMasterApplication& app, FunctionCode func, int taskPriority, const HeaderBuilderT& format, openpal::Logger logger, const TaskConfig& config); + + virtual bool IsRecurring() const override final + { + return false; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override final; + + virtual int Priority(void) const override final + { + return m_priority; + } + + virtual bool BlocksLowerPriority() const override final + { + return false; + } + +protected: + + const FunctionCode m_func; + +private: + + const int m_priority; + const HeaderBuilderT m_format; + + + virtual bool IsEnabled() const override final + { + return true; + } + + virtual MasterTaskType GetTaskType() const override final + { + return MasterTaskType::USER_TASK; + } + +}; + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.cpp new file mode 100644 index 0000000..14052ab --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.cpp @@ -0,0 +1,75 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "StartupIntegrityPoll.h" + +#include "MasterTasks.h" + +#include "opendnp3/app/parsing/APDUParser.h" +#include "opendnp3/app/APDUBuilders.h" + +#include "opendnp3/master/MeasurementHandler.h" + +#include "opendnp3/LogLevels.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +StartupIntegrityPoll::StartupIntegrityPoll(IMasterApplication& app, ISOEHandler& soeHandler, ClassField classes_, TimeDuration retryPeriod_, openpal::Logger logger) : + PollTaskBase(app, soeHandler, openpal::MonotonicTimestamp(0), logger, TaskConfig::Default()), + classes(classes_), + retryPeriod(retryPeriod_) +{ + +} + +bool StartupIntegrityPoll::BuildRequest(APDURequest& request, uint8_t seq) +{ + build::ReadIntegrity(request, classes, seq); + request.SetFunction(FunctionCode::READ); + request.SetControl(AppControlField::Request(seq)); + return true; +} + +bool StartupIntegrityPoll::IsEnabled() const +{ + return classes.HasAnyClass(); +} + +IMasterTask::TaskState StartupIntegrityPoll::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_NO_COMMS) : + return TaskState::Immediately(); + + case(TaskCompletion::SUCCESS) : + return TaskState::Infinite(); + + default: + return TaskState::Infinite(); + } +} + +} //end ns diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.h new file mode 100644 index 0000000..c1f07c5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/StartupIntegrityPoll.h @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_STARTUPINTEGRITYPOLL_H +#define OPENDNP3_STARTUPINTEGRITYPOLL_H + +#include "opendnp3/app/ClassField.h" + +#include "opendnp3/master/PollTaskBase.h" +#include "opendnp3/master/TaskPriority.h" + +namespace opendnp3 +{ + +class ISOEHandler; + +/** + * A generic interface for defining master request/response style tasks + */ +class StartupIntegrityPoll final : public PollTaskBase +{ + +public: + + StartupIntegrityPoll(IMasterApplication& app, ISOEHandler& soeHandler, ClassField classes, openpal::TimeDuration retryPeriod, openpal::Logger logger); + + virtual bool IsRecurring() const override + { + return true; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + + virtual int Priority() const override + { + return priority::INTEGRITY_POLL; + } + + virtual bool BlocksLowerPriority() const override + { + return true; + } + +private: + + ClassField classes; + + openpal::TimeDuration retryPeriod; + + virtual bool IsEnabled() const override; + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::STARTUP_INTEGRITY_POLL; + } + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; + +}; + + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.cpp new file mode 100644 index 0000000..73681f9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.cpp @@ -0,0 +1,103 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "TaskComparison.h" + +using namespace openpal; + +namespace opendnp3 +{ + +TaskComparison::Result TaskComparison::SelectHigherPriority(const openpal::MonotonicTimestamp& now, const IMasterTask& lhs, const IMasterTask& rhs, ITaskFilter& filter) +{ + // if one of the tasks is disabled, pick the enabled one + + bool leftEnabled = TaskComparison::Enabled(lhs, filter); + bool rightEnabled = TaskComparison::Enabled(rhs, filter); + + if (!leftEnabled || !rightEnabled) + { + // always prefer the enabled task over the one that is disabled + return rightEnabled ? Result::Right : Result::Left; + } + + if ((lhs.Priority() > rhs.Priority()) && rhs.BlocksLowerPriority()) + { + return Result::Right; + } + else if (rhs.Priority() > lhs.Priority() && lhs.BlocksLowerPriority()) + { + return Result::Left; + } + else // equal priority or neither task blocks lower priority tasks, compare based on time + { + auto tlhs = lhs.ExpirationTime(); + auto trhs = rhs.ExpirationTime(); + auto lhsExpired = tlhs.milliseconds <= now.milliseconds; + auto rhsExpired = trhs.milliseconds <= now.milliseconds; + + if (lhsExpired && rhsExpired) + { + // both expired, compare based on priority + return HigherPriority(lhs, rhs); + } + else + { + if (tlhs.milliseconds < trhs.milliseconds) + { + return Result::Left; + } + else if (tlhs.milliseconds > trhs.milliseconds) + { + return Result::Right; + } + else + { + // if equal times, compare based on priority + return HigherPriority(lhs, rhs); + } + } + } +} + +bool TaskComparison::Enabled(const IMasterTask& task, ITaskFilter& filter) +{ + return !task.ExpirationTime().IsMax() && filter.CanRun(task); +} + +TaskComparison::Result TaskComparison::HigherPriority(const IMasterTask& lhs, const IMasterTask& rhs) +{ + if (lhs.Priority() < rhs.Priority()) + { + return Result::Left; + } + else if (rhs.Priority() < lhs.Priority()) + { + return Result::Right; + } + else + { + return Result::Same; + } +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.h new file mode 100644 index 0000000..10d8f04 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskComparison.h @@ -0,0 +1,56 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TASKCOMPARISON_H +#define OPENDNP3_TASKCOMPARISON_H + +#include +#include + +#include "opendnp3/master/IMasterTask.h" +#include "opendnp3/master/ITaskFilter.h" + + +namespace opendnp3 +{ + +class TaskComparison : private openpal::StaticOnly +{ +public: + + enum class Result : uint8_t + { + Left, + Right, + Same + }; + + static Result SelectHigherPriority(const openpal::MonotonicTimestamp& now, const IMasterTask& lhs, const IMasterTask& rhs, ITaskFilter& filter); + +private: + + static Result HigherPriority(const IMasterTask& lhs, const IMasterTask& rhs); + + static bool Enabled(const IMasterTask& task, ITaskFilter& filter); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskPriority.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskPriority.h new file mode 100644 index 0000000..a2afd5b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TaskPriority.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TASKPRIORITY_H +#define OPENDNP3_TASKPRIORITY_H + +namespace opendnp3 +{ +namespace priority +{ +const int USER_STATUS_CHANGE = 20; + +const int UPDATE_KEY_CHANGE = 40; + +const int SESSION_KEY = 50; + +const int COMMAND = 100; + +const int USER_REQUEST = 110; + +const int CLEAR_RESTART = 120; + +const int DISABLE_UNSOLICITED = 130; + +const int ASSIGN_CLASS = 140; + +const int INTEGRITY_POLL = 150; + +const int TIME_SYNC = 160; + +const int ENABLE_UNSOLICITED = 170; + +const int EVENT_SCAN = 180; + +const int USER_POLL = 190; +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/TimeSyncHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TimeSyncHandler.h new file mode 100644 index 0000000..03c1354 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TimeSyncHandler.h @@ -0,0 +1,95 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TIMESYNCHANDLER_H +#define OPENDNP3_TIMESYNCHANDLER_H + +#include "opendnp3/app/parsing/IAPDUHandler.h" + +#include "opendnp3/LogLevels.h" + +#include +#include + +namespace opendnp3 +{ + +/** + * Dedicated class for processing response data in the master. + */ +class TimeSyncHandler : public IAPDUHandler, private openpal::Uncopyable +{ + +public: + + TimeSyncHandler() : + m_valid(false), + m_time(0) + {} + + bool GetTimeDelay(uint16_t& time) + { + if (this->Errors().Any()) + { + return false; + } + else + { + if (m_valid) + { + time = m_time; + } + return m_valid; + } + } + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final + { + return (headerCount == 0) && (gv == GroupVariation::Group52Var2); + } + +private: + + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& times) override final + { + Group52Var2 value; + if (times.ReadOnlyValue(value)) + { + m_valid = true; + m_time = value.time; + return IINField::Empty(); + } + else + { + return IINBit::PARAM_ERROR; + } + } + + bool m_valid; + uint16_t m_time; + +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/TypedCommandHeader.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TypedCommandHeader.h new file mode 100644 index 0000000..268e61b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/TypedCommandHeader.h @@ -0,0 +1,211 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TYPED_COMMAND_HEADER_H +#define OPENDNP3_TYPED_COMMAND_HEADER_H + +#include "opendnp3/master/ICommandHeader.h" +#include "opendnp3/master/ICommandCollection.h" + +#include "opendnp3/gen/CommandStatus.h" +#include "opendnp3/gen/CommandPointState.h" + +#include "opendnp3/app/HeaderWriter.h" +#include "opendnp3/app/parsing/ICollection.h" +#include "opendnp3/app/Indexed.h" + + +#include +#include + +namespace opendnp3 +{ + +template +class TypedCommandHeader final : public ICommandHeader, public ICommandCollection +{ + struct Record : public CommandState + { + Record(const Indexed& pair) : CommandState(pair.index), command(pair.value) + {} + + T command; + }; + +public: + + TypedCommandHeader(const DNP3Serializer& serializer) : m_serializer(serializer) + {} + + // --- Implement ICommandCollection --- + + virtual ICommandCollection& Add(const T& command, uint16_t index) override; + + // --- Implement ICommandHeader ---- + + virtual bool AreAllSelected() const override; + + virtual bool Write(HeaderWriter&) const override; + + virtual void ApplySelectResponse(const ICollection>& commands) override; + + virtual void ApplyOperateResponse(const ICollection>& commands) override; + + // --- Implement ICollection> ---- + + virtual size_t Count() const override; + + virtual void Foreach(IVisitor& visitor) const override; + +private: + + DNP3Serializer m_serializer; + std::vector m_records; +}; + + +template +ICommandCollection& TypedCommandHeader::Add(const T& command, uint16_t index) +{ + m_records.push_back(WithIndex(command, index)); + return *this; +} + +template +bool TypedCommandHeader::AreAllSelected() const +{ + auto isSuccess = [](const Record & rec) -> bool { return rec.state == CommandPointState::SELECT_SUCCESS; }; + return std::all_of(m_records.begin(), m_records.end(), isSuccess); +} + +template +bool TypedCommandHeader::Write(HeaderWriter& writer) const +{ + if (m_records.empty()) + { + return false; + } + + auto iter = writer.IterateOverCountWithPrefix(QualifierCode::UINT16_CNT_UINT16_INDEX, m_serializer); + + for(auto& rec : m_records) + { + if (!iter.Write(rec.command, rec.index)) + { + return false; + } + } + + return iter.IsValid(); +} + +template +void TypedCommandHeader::ApplySelectResponse(const ICollection>& commands) +{ + if (commands.Count() > m_records.size()) + { + return; + } + + uint32_t index = 0; + + auto visit = [&](const Indexed item) -> void + { + auto& rec = m_records[index]; + ++index; + + if (item.index != rec.index) + { + return; + } + + if (!item.value.ValuesEqual(rec.command)) + { + rec.state = CommandPointState::SELECT_MISMATCH; + return; + } + + if (item.value.status != CommandStatus::SUCCESS) + { + rec.state = CommandPointState::SELECT_FAIL; + rec.status = item.value.status; + return; + } + + if (rec.state == CommandPointState::INIT) + { + rec.state = CommandPointState::SELECT_SUCCESS; + } + }; + + commands.ForeachItem(visit); +} + +template +void TypedCommandHeader::ApplyOperateResponse(const ICollection>& commands) +{ + if (commands.Count() > m_records.size()) + { + return; + } + + uint32_t index = 0; + + auto visit = [&](const Indexed item) + { + auto& rec = m_records[index]; + ++index; + + if (item.index != rec.index) + { + return; + } + + if (!item.value.ValuesEqual(rec.command)) + { + rec.state = CommandPointState::OPERATE_FAIL; + return; + } + + rec.state = CommandPointState::SUCCESS; + rec.status = item.value.status; + }; + + commands.ForeachItem(visit); +} + +template +size_t TypedCommandHeader::Count() const +{ + return m_records.size(); +} + +template +void TypedCommandHeader::Foreach(IVisitor& visitor) const +{ + for(auto& rec : m_records) + { + visitor.OnValue(rec); + } +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.cpp new file mode 100644 index 0000000..e0c088c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.cpp @@ -0,0 +1,70 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "UserPollTask.h" + +using namespace openpal; + +namespace opendnp3 +{ + +UserPollTask::UserPollTask( + const HeaderBuilderT& builder_, + bool recurring_, + openpal::TimeDuration period_, + openpal::TimeDuration retryDelay_, + IMasterApplication& app, + ISOEHandler& soeHandler, + openpal::Logger logger, + TaskConfig config +) : + PollTaskBase(app, soeHandler, openpal::MonotonicTimestamp(0), logger, config), + builder(builder_), + recurring(recurring_), + period(period_), + retryDelay(retryDelay_) +{} + +bool UserPollTask::BuildRequest(APDURequest& request, uint8_t seq) +{ + rxCount = 0; + request.SetFunction(FunctionCode::READ); + request.SetControl(AppControlField::Request(seq)); + auto writer = request.GetWriter(); + return builder(writer); +} + +IMasterTask::TaskState UserPollTask::OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) +{ + switch (result) + { + case(TaskCompletion::FAILURE_BAD_RESPONSE) : + return TaskState::Disabled(); + case(TaskCompletion::FAILURE_NO_COMMS) : + return TaskState::Immediately(); + default: + return period.IsNegative() ? TaskState::Infinite() : TaskState::Retry(now.Add(period)); + } +} + +} //end ns + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.h b/utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.h new file mode 100644 index 0000000..39f956d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/master/UserPollTask.h @@ -0,0 +1,98 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_USERPOLLTASK_H +#define OPENDNP3_USERPOLLTASK_H + +#include "opendnp3/master/PollTaskBase.h" +#include "opendnp3/master/TaskPriority.h" +#include "opendnp3/master/ITaskCallback.h" +#include "opendnp3/master/HeaderBuilder.h" + +#include + +namespace opendnp3 +{ + +class ISOEHandler; + +/** + * A generic interface for defining master request/response style tasks + */ + +class UserPollTask final : public PollTaskBase +{ + +public: + + UserPollTask( + const HeaderBuilderT& builder, + bool recurring, + openpal::TimeDuration period, + openpal::TimeDuration retryDelay, + IMasterApplication& app, + ISOEHandler& soeHandler, + openpal::Logger logger, + TaskConfig config + ); + + virtual int Priority() const override + { + return priority::USER_POLL; + } + + virtual bool BuildRequest(APDURequest& request, uint8_t seq) override; + + virtual bool BlocksLowerPriority() const override + { + return false; + } + + virtual bool IsRecurring() const override + { + return recurring; + } + + virtual bool IsEnabled() const override + { + return true; + } + +private: + + virtual IMasterTask::TaskState OnTaskComplete(TaskCompletion result, openpal::MonotonicTimestamp now) override; + + virtual MasterTaskType GetTaskType() const override + { + return MasterTaskType::USER_TASK; + } + + + HeaderBuilderT builder; + bool recurring; + openpal::TimeDuration period; + openpal::TimeDuration retryDelay; +}; + + +} //end ns + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.cpp new file mode 100644 index 0000000..5cc0af1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.cpp @@ -0,0 +1,67 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group1.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group1Var2 ------- + +Group1Var2::Group1Var2() : flags(0) +{} + +bool Group1Var2::Read(RSlice& buffer, Group1Var2& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group1Var2::Write(const Group1Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group1Var2::ReadTarget(RSlice& buff, Binary& output) +{ + Group1Var2 value; + if(Read(buff, value)) + { + output = BinaryFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group1Var2::WriteTarget(const Binary& value, openpal::WSlice& buff) +{ + return Group1Var2::Write(ConvertGroup1Var2::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.h new file mode 100644 index 0000000..31c2dfe --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group1.h @@ -0,0 +1,68 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP1_H +#define OPENDNP3_GROUP1_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Binary Input - Any Variation +struct Group1Var0 +{ + static GroupVariationID ID() { return GroupVariationID(1,0); } +}; + +// Binary Input - Packed Format +struct Group1Var1 +{ + static GroupVariationID ID() { return GroupVariationID(1,1); } +}; + +// Binary Input - With Flags +struct Group1Var2 +{ + static GroupVariationID ID() { return GroupVariationID(1,2); } + + Group1Var2(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group1Var2&); + static bool Write(const Group1Var2&, openpal::WSlice&); + + uint8_t flags; + + typedef Binary Target; + typedef BinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, Binary&); + static bool WriteTarget(const Binary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.cpp new file mode 100644 index 0000000..a8e9796 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.cpp @@ -0,0 +1,67 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group10.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group10Var2 ------- + +Group10Var2::Group10Var2() : flags(0) +{} + +bool Group10Var2::Read(RSlice& buffer, Group10Var2& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group10Var2::Write(const Group10Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group10Var2::ReadTarget(RSlice& buff, BinaryOutputStatus& output) +{ + Group10Var2 value; + if(Read(buff, value)) + { + output = BinaryOutputStatusFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group10Var2::WriteTarget(const BinaryOutputStatus& value, openpal::WSlice& buff) +{ + return Group10Var2::Write(ConvertGroup10Var2::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.h new file mode 100644 index 0000000..690a97c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group10.h @@ -0,0 +1,68 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP10_H +#define OPENDNP3_GROUP10_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Binary Output - Any Variation +struct Group10Var0 +{ + static GroupVariationID ID() { return GroupVariationID(10,0); } +}; + +// Binary Output - Packed Format +struct Group10Var1 +{ + static GroupVariationID ID() { return GroupVariationID(10,1); } +}; + +// Binary Output - Output Status With Flags +struct Group10Var2 +{ + static GroupVariationID ID() { return GroupVariationID(10,2); } + + Group10Var2(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group10Var2&); + static bool Write(const Group10Var2&, openpal::WSlice&); + + uint8_t flags; + + typedef BinaryOutputStatus Target; + typedef BinaryOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, BinaryOutputStatus&); + static bool WriteTarget(const BinaryOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.cpp new file mode 100644 index 0000000..00b0db6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.cpp @@ -0,0 +1,101 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group11.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group11Var1 ------- + +Group11Var1::Group11Var1() : flags(0) +{} + +bool Group11Var1::Read(RSlice& buffer, Group11Var1& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group11Var1::Write(const Group11Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group11Var1::ReadTarget(RSlice& buff, BinaryOutputStatus& output) +{ + Group11Var1 value; + if(Read(buff, value)) + { + output = BinaryOutputStatusFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group11Var1::WriteTarget(const BinaryOutputStatus& value, openpal::WSlice& buff) +{ + return Group11Var1::Write(ConvertGroup11Var1::Apply(value), buff); +} + +// ------- Group11Var2 ------- + +Group11Var2::Group11Var2() : flags(0), time(0) +{} + +bool Group11Var2::Read(RSlice& buffer, Group11Var2& output) +{ + return Parse::Many(buffer, output.flags, output.time); +} + +bool Group11Var2::Write(const Group11Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.time); +} + +bool Group11Var2::ReadTarget(RSlice& buff, BinaryOutputStatus& output) +{ + Group11Var2 value; + if(Read(buff, value)) + { + output = BinaryOutputStatusFactory::From(value.flags, value.time); + return true; + } + else + { + return false; + } +} + +bool Group11Var2::WriteTarget(const BinaryOutputStatus& value, openpal::WSlice& buff) +{ + return Group11Var2::Write(ConvertGroup11Var2::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.h new file mode 100644 index 0000000..baf540c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group11.h @@ -0,0 +1,83 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP11_H +#define OPENDNP3_GROUP11_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Binary Output Event - Any Variation +struct Group11Var0 +{ + static GroupVariationID ID() { return GroupVariationID(11,0); } +}; + +// Binary Output Event - Output Status Without Time +struct Group11Var1 +{ + static GroupVariationID ID() { return GroupVariationID(11,1); } + + Group11Var1(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group11Var1&); + static bool Write(const Group11Var1&, openpal::WSlice&); + + uint8_t flags; + + typedef BinaryOutputStatus Target; + typedef BinaryOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, BinaryOutputStatus&); + static bool WriteTarget(const BinaryOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Binary Output Event - Output Status With Time +struct Group11Var2 +{ + static GroupVariationID ID() { return GroupVariationID(11,2); } + + Group11Var2(); + + static uint32_t Size() { return 7; } + static bool Read(openpal::RSlice&, Group11Var2&); + static bool Write(const Group11Var2&, openpal::WSlice&); + + uint8_t flags; + DNPTime time; + + typedef BinaryOutputStatus Target; + typedef BinaryOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, BinaryOutputStatus&); + static bool WriteTarget(const BinaryOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group110.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group110.h new file mode 100644 index 0000000..13d5ea9 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group110.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP110_H +#define OPENDNP3_GROUP110_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// Octet String - Sized by variation +struct Group110Var0 +{ + static GroupVariationID ID() { return GroupVariationID(110,0); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group111.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group111.h new file mode 100644 index 0000000..0b31053 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group111.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP111_H +#define OPENDNP3_GROUP111_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// Octet String Event - Sized by variation +struct Group111Var0 +{ + static GroupVariationID ID() { return GroupVariationID(111,0); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group112.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group112.h new file mode 100644 index 0000000..1887917 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group112.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP112_H +#define OPENDNP3_GROUP112_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// Virtual Terminal Output Block - Sized by variation +struct Group112Var0 +{ + static GroupVariationID ID() { return GroupVariationID(112,0); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group113.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group113.h new file mode 100644 index 0000000..b526ed4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group113.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP113_H +#define OPENDNP3_GROUP113_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// Virtual Terminal Event Data - Sized by variation +struct Group113Var0 +{ + static GroupVariationID ID() { return GroupVariationID(113,0); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.cpp new file mode 100644 index 0000000..04c1204 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.cpp @@ -0,0 +1,67 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group12.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group12Var1 ------- + +Group12Var1::Group12Var1() : code(0), count(0), onTime(0), offTime(0), status(0) +{} + +bool Group12Var1::Read(RSlice& buffer, Group12Var1& output) +{ + return Parse::Many(buffer, output.code, output.count, output.onTime, output.offTime, output.status); +} + +bool Group12Var1::Write(const Group12Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.code, arg.count, arg.onTime, arg.offTime, arg.status); +} + +bool Group12Var1::ReadTarget(RSlice& buff, ControlRelayOutputBlock& output) +{ + Group12Var1 value; + if(Read(buff, value)) + { + output = ControlRelayOutputBlockFactory::From(value.code, value.count, value.onTime, value.offTime, value.status); + return true; + } + else + { + return false; + } +} + +bool Group12Var1::WriteTarget(const ControlRelayOutputBlock& value, openpal::WSlice& buff) +{ + return Group12Var1::Write(ConvertGroup12Var1::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.h new file mode 100644 index 0000000..83e5f89 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group12.h @@ -0,0 +1,65 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP12_H +#define OPENDNP3_GROUP12_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/ControlRelayOutputBlock.h" + +namespace opendnp3 { + +// Binary Command - Any Variation +struct Group12Var0 +{ + static GroupVariationID ID() { return GroupVariationID(12,0); } +}; + +// Binary Command - CROB +struct Group12Var1 +{ + static GroupVariationID ID() { return GroupVariationID(12,1); } + + Group12Var1(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group12Var1&); + static bool Write(const Group12Var1&, openpal::WSlice&); + + uint8_t code; + uint8_t count; + uint32_t onTime; + uint32_t offTime; + uint8_t status; + + typedef ControlRelayOutputBlock Target; + static bool ReadTarget(openpal::RSlice&, ControlRelayOutputBlock&); + static bool WriteTarget(const ControlRelayOutputBlock&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.cpp new file mode 100644 index 0000000..b90cc93 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.cpp @@ -0,0 +1,820 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group120.h" + +#include +#include "opendnp3/app/parsing/PrefixFields.h" +#include +#include + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group120Var1 ------- + +Group120Var1::Group120Var1() : + challengeSeqNum(0), userNum(0), hmacAlgo(HMACType::UNKNOWN), challengeReason(ChallengeReason::UNKNOWN) +{} + +Group120Var1::Group120Var1( + uint32_t challengeSeqNum_, + uint16_t userNum_, + HMACType hmacAlgo_, + ChallengeReason challengeReason_, + const openpal::RSlice& challengeData_ +) : + challengeSeqNum(challengeSeqNum_), + userNum(userNum_), + hmacAlgo(hmacAlgo_), + challengeReason(challengeReason_), + challengeData(challengeData_) +{} + +uint32_t Group120Var1::Size() const +{ + return MIN_SIZE + challengeData.Size(); +} + +bool Group120Var1::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var1::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->challengeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + this->hmacAlgo = HMACTypeFromType(UInt8::ReadBuffer(copy)); + this->challengeReason = ChallengeReasonFromType(UInt8::ReadBuffer(copy)); + + this->challengeData = copy; // whatever is left over + return true; +} + +bool Group120Var1::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->challengeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + UInt8::WriteBuffer(buffer, HMACTypeToType(this->hmacAlgo)); + UInt8::WriteBuffer(buffer, ChallengeReasonToType(this->challengeReason)); + + challengeData.CopyTo(buffer); + return true; +} + +// ------- Group120Var2 ------- + +Group120Var2::Group120Var2() : + challengeSeqNum(0), userNum(0) +{} + +Group120Var2::Group120Var2( + uint32_t challengeSeqNum_, + uint16_t userNum_, + const openpal::RSlice& hmacValue_ +) : + challengeSeqNum(challengeSeqNum_), + userNum(userNum_), + hmacValue(hmacValue_) +{} + +uint32_t Group120Var2::Size() const +{ + return MIN_SIZE + hmacValue.Size(); +} + +bool Group120Var2::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var2::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->challengeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + + this->hmacValue = copy; // whatever is left over + return true; +} + +bool Group120Var2::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->challengeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + + hmacValue.CopyTo(buffer); + return true; +} + +// ------- Group120Var3 ------- + +Group120Var3::Group120Var3() : challengeSeqNum(0), userNum(0) +{} + +bool Group120Var3::Read(RSlice& buffer, Group120Var3& output) +{ + return Parse::Many(buffer, output.challengeSeqNum, output.userNum); +} + +bool Group120Var3::Write(const Group120Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.challengeSeqNum, arg.userNum); +} + +// ------- Group120Var4 ------- + +Group120Var4::Group120Var4() : userNum(0) +{} + +bool Group120Var4::Read(RSlice& buffer, Group120Var4& output) +{ + return Parse::Many(buffer, output.userNum); +} + +bool Group120Var4::Write(const Group120Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.userNum); +} + +// ------- Group120Var5 ------- + +Group120Var5::Group120Var5() : + keyChangeSeqNum(0), userNum(0), keyWrapAlgo(KeyWrapAlgorithm::UNDEFINED), keyStatus(KeyStatus::UNDEFINED), hmacAlgo(HMACType::UNKNOWN) +{} + +Group120Var5::Group120Var5( + uint32_t keyChangeSeqNum_, + uint16_t userNum_, + KeyWrapAlgorithm keyWrapAlgo_, + KeyStatus keyStatus_, + HMACType hmacAlgo_, + const openpal::RSlice& challengeData_, + const openpal::RSlice& hmacValue_ +) : + keyChangeSeqNum(keyChangeSeqNum_), + userNum(userNum_), + keyWrapAlgo(keyWrapAlgo_), + keyStatus(keyStatus_), + hmacAlgo(hmacAlgo_), + challengeData(challengeData_), + hmacValue(hmacValue_) +{} + +uint32_t Group120Var5::Size() const +{ + return MIN_SIZE + challengeData.Size() + hmacValue.Size(); +} + +bool Group120Var5::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var5::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + this->keyWrapAlgo = KeyWrapAlgorithmFromType(UInt8::ReadBuffer(copy)); + this->keyStatus = KeyStatusFromType(UInt8::ReadBuffer(copy)); + this->hmacAlgo = HMACTypeFromType(UInt8::ReadBuffer(copy)); + + if(!PrefixFields::Read(copy, challengeData)) + { + return false; + } + + this->hmacValue = copy; // whatever is left over + return true; +} + +bool Group120Var5::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + // All of the fields that have a uint16_t length must have the proper size + if(!PrefixFields::LengthFitsInUInt16(challengeData)) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->keyChangeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + UInt8::WriteBuffer(buffer, KeyWrapAlgorithmToType(this->keyWrapAlgo)); + UInt8::WriteBuffer(buffer, KeyStatusToType(this->keyStatus)); + UInt8::WriteBuffer(buffer, HMACTypeToType(this->hmacAlgo)); + + if(!PrefixFields::Write(buffer, challengeData)) + { + return false; + } + + hmacValue.CopyTo(buffer); + return true; +} + +// ------- Group120Var6 ------- + +Group120Var6::Group120Var6() : + keyChangeSeqNum(0), userNum(0) +{} + +Group120Var6::Group120Var6( + uint32_t keyChangeSeqNum_, + uint16_t userNum_, + const openpal::RSlice& keyWrapData_ +) : + keyChangeSeqNum(keyChangeSeqNum_), + userNum(userNum_), + keyWrapData(keyWrapData_) +{} + +uint32_t Group120Var6::Size() const +{ + return MIN_SIZE + keyWrapData.Size(); +} + +bool Group120Var6::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var6::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + + this->keyWrapData = copy; // whatever is left over + return true; +} + +bool Group120Var6::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->keyChangeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + + keyWrapData.CopyTo(buffer); + return true; +} + +// ------- Group120Var7 ------- + +Group120Var7::Group120Var7() : + challengeSeqNum(0), userNum(0), assocId(0), errorCode(AuthErrorCode::UNKNOWN), time(0) +{} + +Group120Var7::Group120Var7( + uint32_t challengeSeqNum_, + uint16_t userNum_, + uint16_t assocId_, + AuthErrorCode errorCode_, + DNPTime time_, + const openpal::RSlice& errorText_ +) : + challengeSeqNum(challengeSeqNum_), + userNum(userNum_), + assocId(assocId_), + errorCode(errorCode_), + time(time_), + errorText(errorText_) +{} + +uint32_t Group120Var7::Size() const +{ + return MIN_SIZE + errorText.Size(); +} + +bool Group120Var7::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var7::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->challengeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + this->assocId = UInt16::ReadBuffer(copy); + this->errorCode = AuthErrorCodeFromType(UInt8::ReadBuffer(copy)); + this->time = UInt48::ReadBuffer(copy); + + this->errorText = copy; // whatever is left over + return true; +} + +bool Group120Var7::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->challengeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + UInt16::WriteBuffer(buffer, this->assocId); + UInt8::WriteBuffer(buffer, AuthErrorCodeToType(this->errorCode)); + UInt48::WriteBuffer(buffer, this->time); + + errorText.CopyTo(buffer); + return true; +} + +// ------- Group120Var8 ------- + +Group120Var8::Group120Var8() : + keyChangeMethod(KeyChangeMethod::UNDEFINED), certificateType(CertificateType::UNKNOWN) +{} + +Group120Var8::Group120Var8( + KeyChangeMethod keyChangeMethod_, + CertificateType certificateType_, + const openpal::RSlice& certificate_ +) : + keyChangeMethod(keyChangeMethod_), + certificateType(certificateType_), + certificate(certificate_) +{} + +uint32_t Group120Var8::Size() const +{ + return MIN_SIZE + certificate.Size(); +} + +bool Group120Var8::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var8::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeMethod = KeyChangeMethodFromType(UInt8::ReadBuffer(copy)); + this->certificateType = CertificateTypeFromType(UInt8::ReadBuffer(copy)); + + this->certificate = copy; // whatever is left over + return true; +} + +bool Group120Var8::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + UInt8::WriteBuffer(buffer, KeyChangeMethodToType(this->keyChangeMethod)); + UInt8::WriteBuffer(buffer, CertificateTypeToType(this->certificateType)); + + certificate.CopyTo(buffer); + return true; +} + +// ------- Group120Var9 ------- + +Group120Var9::Group120Var9() +{} + +Group120Var9::Group120Var9( + const openpal::RSlice& hmacValue_ +) : + hmacValue(hmacValue_) +{} + +uint32_t Group120Var9::Size() const +{ + return MIN_SIZE + hmacValue.Size(); +} + +bool Group120Var9::Read(const RSlice& buffer) +{ + this->hmacValue = buffer; // the object is just the remainder field + return true; +} + +bool Group120Var9::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + hmacValue.CopyTo(buffer); + return true; +} + +// ------- Group120Var10 ------- + +Group120Var10::Group120Var10() : + keyChangeMethod(KeyChangeMethod::UNDEFINED), userOperation(UserOperation::OP_UNDEFINED), statusChangeSeqNum(0), userRole(0), userRoleExpDays(0) +{} + +Group120Var10::Group120Var10( + KeyChangeMethod keyChangeMethod_, + UserOperation userOperation_, + uint32_t statusChangeSeqNum_, + uint16_t userRole_, + uint16_t userRoleExpDays_, + const openpal::RSlice& userName_, + const openpal::RSlice& userPublicKey_, + const openpal::RSlice& certificationData_ +) : + keyChangeMethod(keyChangeMethod_), + userOperation(userOperation_), + statusChangeSeqNum(statusChangeSeqNum_), + userRole(userRole_), + userRoleExpDays(userRoleExpDays_), + userName(userName_), + userPublicKey(userPublicKey_), + certificationData(certificationData_) +{} + +uint32_t Group120Var10::Size() const +{ + return MIN_SIZE + userName.Size() + userPublicKey.Size() + certificationData.Size(); +} + +bool Group120Var10::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var10::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeMethod = KeyChangeMethodFromType(UInt8::ReadBuffer(copy)); + this->userOperation = UserOperationFromType(UInt8::ReadBuffer(copy)); + this->statusChangeSeqNum = UInt32::ReadBuffer(copy); + this->userRole = UInt16::ReadBuffer(copy); + this->userRoleExpDays = UInt16::ReadBuffer(copy); + + if(!PrefixFields::Read(copy, userName, userPublicKey, certificationData)) + { + return false; + } + + // object does not have a remainder field so it should be fully consumed + // The header length disagrees with object encoding so abort + if(copy.IsNotEmpty()) + { + return false; + } + + return true; +} + +bool Group120Var10::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + // All of the fields that have a uint16_t length must have the proper size + if(!PrefixFields::LengthFitsInUInt16(userName, userPublicKey, certificationData)) + { + return false; + } + + UInt8::WriteBuffer(buffer, KeyChangeMethodToType(this->keyChangeMethod)); + UInt8::WriteBuffer(buffer, UserOperationToType(this->userOperation)); + UInt32::WriteBuffer(buffer, this->statusChangeSeqNum); + UInt16::WriteBuffer(buffer, this->userRole); + UInt16::WriteBuffer(buffer, this->userRoleExpDays); + + if(!PrefixFields::Write(buffer, userName, userPublicKey, certificationData)) + { + return false; + } + + return true; +} + +// ------- Group120Var11 ------- + +Group120Var11::Group120Var11() : + keyChangeMethod(KeyChangeMethod::UNDEFINED) +{} + +Group120Var11::Group120Var11( + KeyChangeMethod keyChangeMethod_, + const openpal::RSlice& userName_, + const openpal::RSlice& challengeData_ +) : + keyChangeMethod(keyChangeMethod_), + userName(userName_), + challengeData(challengeData_) +{} + +uint32_t Group120Var11::Size() const +{ + return MIN_SIZE + userName.Size() + challengeData.Size(); +} + +bool Group120Var11::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var11::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeMethod = KeyChangeMethodFromType(UInt8::ReadBuffer(copy)); + + if(!PrefixFields::Read(copy, userName, challengeData)) + { + return false; + } + + // object does not have a remainder field so it should be fully consumed + // The header length disagrees with object encoding so abort + if(copy.IsNotEmpty()) + { + return false; + } + + return true; +} + +bool Group120Var11::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + // All of the fields that have a uint16_t length must have the proper size + if(!PrefixFields::LengthFitsInUInt16(userName, challengeData)) + { + return false; + } + + UInt8::WriteBuffer(buffer, KeyChangeMethodToType(this->keyChangeMethod)); + + if(!PrefixFields::Write(buffer, userName, challengeData)) + { + return false; + } + + return true; +} + +// ------- Group120Var12 ------- + +Group120Var12::Group120Var12() : + keyChangeSeqNum(0), userNum(0) +{} + +Group120Var12::Group120Var12( + uint32_t keyChangeSeqNum_, + uint16_t userNum_, + const openpal::RSlice& challengeData_ +) : + keyChangeSeqNum(keyChangeSeqNum_), + userNum(userNum_), + challengeData(challengeData_) +{} + +uint32_t Group120Var12::Size() const +{ + return MIN_SIZE + challengeData.Size(); +} + +bool Group120Var12::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var12::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + + if(!PrefixFields::Read(copy, challengeData)) + { + return false; + } + + // object does not have a remainder field so it should be fully consumed + // The header length disagrees with object encoding so abort + if(copy.IsNotEmpty()) + { + return false; + } + + return true; +} + +bool Group120Var12::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + // All of the fields that have a uint16_t length must have the proper size + if(!PrefixFields::LengthFitsInUInt16(challengeData)) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->keyChangeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + + if(!PrefixFields::Write(buffer, challengeData)) + { + return false; + } + + return true; +} + +// ------- Group120Var13 ------- + +Group120Var13::Group120Var13() : + keyChangeSeqNum(0), userNum(0) +{} + +Group120Var13::Group120Var13( + uint32_t keyChangeSeqNum_, + uint16_t userNum_, + const openpal::RSlice& encryptedUpdateKey_ +) : + keyChangeSeqNum(keyChangeSeqNum_), + userNum(userNum_), + encryptedUpdateKey(encryptedUpdateKey_) +{} + +uint32_t Group120Var13::Size() const +{ + return MIN_SIZE + encryptedUpdateKey.Size(); +} + +bool Group120Var13::Read(const RSlice& buffer) +{ + if(buffer.Size() < Group120Var13::MIN_SIZE) + { + return false; + } + + RSlice copy(buffer); //mutable copy for parsing + + this->keyChangeSeqNum = UInt32::ReadBuffer(copy); + this->userNum = UInt16::ReadBuffer(copy); + + if(!PrefixFields::Read(copy, encryptedUpdateKey)) + { + return false; + } + + // object does not have a remainder field so it should be fully consumed + // The header length disagrees with object encoding so abort + if(copy.IsNotEmpty()) + { + return false; + } + + return true; +} + +bool Group120Var13::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + // All of the fields that have a uint16_t length must have the proper size + if(!PrefixFields::LengthFitsInUInt16(encryptedUpdateKey)) + { + return false; + } + + UInt32::WriteBuffer(buffer, this->keyChangeSeqNum); + UInt16::WriteBuffer(buffer, this->userNum); + + if(!PrefixFields::Write(buffer, encryptedUpdateKey)) + { + return false; + } + + return true; +} + +// ------- Group120Var14 ------- + +Group120Var14::Group120Var14() +{} + +Group120Var14::Group120Var14( + const openpal::RSlice& digitalSignature_ +) : + digitalSignature(digitalSignature_) +{} + +uint32_t Group120Var14::Size() const +{ + return MIN_SIZE + digitalSignature.Size(); +} + +bool Group120Var14::Read(const RSlice& buffer) +{ + this->digitalSignature = buffer; // the object is just the remainder field + return true; +} + +bool Group120Var14::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + digitalSignature.CopyTo(buffer); + return true; +} + +// ------- Group120Var15 ------- + +Group120Var15::Group120Var15() +{} + +Group120Var15::Group120Var15( + const openpal::RSlice& hmacValue_ +) : + hmacValue(hmacValue_) +{} + +uint32_t Group120Var15::Size() const +{ + return MIN_SIZE + hmacValue.Size(); +} + +bool Group120Var15::Read(const RSlice& buffer) +{ + this->hmacValue = buffer; // the object is just the remainder field + return true; +} + +bool Group120Var15::Write(openpal::WSlice& buffer) const +{ + if(this->Size() > buffer.Size()) + { + return false; + } + + hmacValue.CopyTo(buffer); + return true; +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.h new file mode 100644 index 0000000..a2b4027 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group120.h @@ -0,0 +1,439 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP120_H +#define OPENDNP3_GROUP120_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/IVariableLength.h" +#include "opendnp3/gen/HMACType.h" +#include "opendnp3/gen/ChallengeReason.h" +#include "opendnp3/gen/KeyWrapAlgorithm.h" +#include "opendnp3/gen/KeyStatus.h" +#include "opendnp3/gen/AuthErrorCode.h" +#include "opendnp3/gen/KeyChangeMethod.h" +#include "opendnp3/gen/CertificateType.h" +#include "opendnp3/gen/UserOperation.h" + +namespace opendnp3 { + +// Authentication - Challenge +struct Group120Var1 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,1); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var1(); + + Group120Var1( + uint32_t challengeSeqNum, + uint16_t userNum, + HMACType hmacAlgo, + ChallengeReason challengeReason, + const openpal::RSlice& challengeData + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 8; + + // member variables + uint32_t challengeSeqNum; + uint16_t userNum; + HMACType hmacAlgo; + ChallengeReason challengeReason; + openpal::RSlice challengeData; +}; + +// Authentication - Reply +struct Group120Var2 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,2); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var2(); + + Group120Var2( + uint32_t challengeSeqNum, + uint16_t userNum, + const openpal::RSlice& hmacValue + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 6; + + // member variables + uint32_t challengeSeqNum; + uint16_t userNum; + openpal::RSlice hmacValue; +}; + +// Authentication - Aggressive Mode Request +struct Group120Var3 +{ + static GroupVariationID ID() { return GroupVariationID(120,3); } + + Group120Var3(); + + static uint32_t Size() { return 6; } + static bool Read(openpal::RSlice&, Group120Var3&); + static bool Write(const Group120Var3&, openpal::WSlice&); + + uint32_t challengeSeqNum; + uint16_t userNum; +}; + +// Authentication - Session Key Status Request +struct Group120Var4 +{ + static GroupVariationID ID() { return GroupVariationID(120,4); } + + Group120Var4(); + + static uint32_t Size() { return 2; } + static bool Read(openpal::RSlice&, Group120Var4&); + static bool Write(const Group120Var4&, openpal::WSlice&); + + uint16_t userNum; +}; + +// Authentication - Session Key Status +struct Group120Var5 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,5); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var5(); + + Group120Var5( + uint32_t keyChangeSeqNum, + uint16_t userNum, + KeyWrapAlgorithm keyWrapAlgo, + KeyStatus keyStatus, + HMACType hmacAlgo, + const openpal::RSlice& challengeData, + const openpal::RSlice& hmacValue + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 11; + + // member variables + uint32_t keyChangeSeqNum; + uint16_t userNum; + KeyWrapAlgorithm keyWrapAlgo; + KeyStatus keyStatus; + HMACType hmacAlgo; + openpal::RSlice challengeData; + openpal::RSlice hmacValue; +}; + +// Authentication - Session Key Change +struct Group120Var6 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,6); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var6(); + + Group120Var6( + uint32_t keyChangeSeqNum, + uint16_t userNum, + const openpal::RSlice& keyWrapData + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 6; + + // member variables + uint32_t keyChangeSeqNum; + uint16_t userNum; + openpal::RSlice keyWrapData; +}; + +// Authentication - Error +struct Group120Var7 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,7); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var7(); + + Group120Var7( + uint32_t challengeSeqNum, + uint16_t userNum, + uint16_t assocId, + AuthErrorCode errorCode, + DNPTime time, + const openpal::RSlice& errorText + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 15; + + // member variables + uint32_t challengeSeqNum; + uint16_t userNum; + uint16_t assocId; + AuthErrorCode errorCode; + DNPTime time; + openpal::RSlice errorText; +}; + +// Authentication - User Certificate +struct Group120Var8 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,8); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var8(); + + Group120Var8( + KeyChangeMethod keyChangeMethod, + CertificateType certificateType, + const openpal::RSlice& certificate + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 2; + + // member variables + KeyChangeMethod keyChangeMethod; + CertificateType certificateType; + openpal::RSlice certificate; +}; + +// Authentication - HMAC +struct Group120Var9 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,9); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var9(); + + explicit Group120Var9( + const openpal::RSlice& hmacValue + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 0; + + // member variables + openpal::RSlice hmacValue; +}; + +// Authentication - User Status Change +struct Group120Var10 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,10); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var10(); + + Group120Var10( + KeyChangeMethod keyChangeMethod, + UserOperation userOperation, + uint32_t statusChangeSeqNum, + uint16_t userRole, + uint16_t userRoleExpDays, + const openpal::RSlice& userName, + const openpal::RSlice& userPublicKey, + const openpal::RSlice& certificationData + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 16; + + // member variables + KeyChangeMethod keyChangeMethod; + UserOperation userOperation; + uint32_t statusChangeSeqNum; + uint16_t userRole; + uint16_t userRoleExpDays; + openpal::RSlice userName; + openpal::RSlice userPublicKey; + openpal::RSlice certificationData; +}; + +// Authentication - Update Key Change Request +struct Group120Var11 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,11); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var11(); + + Group120Var11( + KeyChangeMethod keyChangeMethod, + const openpal::RSlice& userName, + const openpal::RSlice& challengeData + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 5; + + // member variables + KeyChangeMethod keyChangeMethod; + openpal::RSlice userName; + openpal::RSlice challengeData; +}; + +// Authentication - Update Key Change Reply +struct Group120Var12 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,12); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var12(); + + Group120Var12( + uint32_t keyChangeSeqNum, + uint16_t userNum, + const openpal::RSlice& challengeData + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 8; + + // member variables + uint32_t keyChangeSeqNum; + uint16_t userNum; + openpal::RSlice challengeData; +}; + +// Authentication - Update Key Change +struct Group120Var13 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,13); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var13(); + + Group120Var13( + uint32_t keyChangeSeqNum, + uint16_t userNum, + const openpal::RSlice& encryptedUpdateKey + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 8; + + // member variables + uint32_t keyChangeSeqNum; + uint16_t userNum; + openpal::RSlice encryptedUpdateKey; +}; + +// Authentication - Update Key Change Signature +struct Group120Var14 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,14); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var14(); + + explicit Group120Var14( + const openpal::RSlice& digitalSignature + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 0; + + // member variables + openpal::RSlice digitalSignature; +}; + +// Authentication - Update Key Change Confirmation +struct Group120Var15 : public IVariableLength +{ + static GroupVariationID ID() { return GroupVariationID(120,15); } + + virtual GroupVariationID InstanceID() const override final { return ID(); } + + Group120Var15(); + + explicit Group120Var15( + const openpal::RSlice& hmacValue + ); + + virtual uint32_t Size() const override final; + virtual bool Read(const openpal::RSlice&) override final; + virtual bool Write(openpal::WSlice&) const override final; + + static const uint32_t MIN_SIZE = 0; + + // member variables + openpal::RSlice hmacValue; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.cpp new file mode 100644 index 0000000..3243ed8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.cpp @@ -0,0 +1,67 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group121.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group121Var1 ------- + +Group121Var1::Group121Var1() : flags(0), assocId(0), value(0) +{} + +bool Group121Var1::Read(RSlice& buffer, Group121Var1& output) +{ + return Parse::Many(buffer, output.flags, output.assocId, output.value); +} + +bool Group121Var1::Write(const Group121Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.assocId, arg.value); +} + +bool Group121Var1::ReadTarget(RSlice& buff, SecurityStat& output) +{ + Group121Var1 value; + if(Read(buff, value)) + { + output = SecurityStatFactory::From(value.flags, value.assocId, value.value); + return true; + } + else + { + return false; + } +} + +bool Group121Var1::WriteTarget(const SecurityStat& value, openpal::WSlice& buff) +{ + return Group121Var1::Write(ConvertGroup121Var1::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.h new file mode 100644 index 0000000..7d2bfa1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group121.h @@ -0,0 +1,65 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP121_H +#define OPENDNP3_GROUP121_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Security statistic - Any Variation +struct Group121Var0 +{ + static GroupVariationID ID() { return GroupVariationID(121,0); } +}; + +// Security statistic - 32-bit With Flag +struct Group121Var1 +{ + static GroupVariationID ID() { return GroupVariationID(121,1); } + + Group121Var1(); + + static uint32_t Size() { return 7; } + static bool Read(openpal::RSlice&, Group121Var1&); + static bool Write(const Group121Var1&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint16_t assocId; + uint32_t value; + + typedef SecurityStat Target; + typedef SecurityStatSpec Spec; + static bool ReadTarget(openpal::RSlice&, SecurityStat&); + static bool WriteTarget(const SecurityStat&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.cpp new file mode 100644 index 0000000..6edbd11 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.cpp @@ -0,0 +1,101 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group122.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group122Var1 ------- + +Group122Var1::Group122Var1() : flags(0), assocId(0), value(0) +{} + +bool Group122Var1::Read(RSlice& buffer, Group122Var1& output) +{ + return Parse::Many(buffer, output.flags, output.assocId, output.value); +} + +bool Group122Var1::Write(const Group122Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.assocId, arg.value); +} + +bool Group122Var1::ReadTarget(RSlice& buff, SecurityStat& output) +{ + Group122Var1 value; + if(Read(buff, value)) + { + output = SecurityStatFactory::From(value.flags, value.assocId, value.value); + return true; + } + else + { + return false; + } +} + +bool Group122Var1::WriteTarget(const SecurityStat& value, openpal::WSlice& buff) +{ + return Group122Var1::Write(ConvertGroup122Var1::Apply(value), buff); +} + +// ------- Group122Var2 ------- + +Group122Var2::Group122Var2() : flags(0), assocId(0), value(0), time(0) +{} + +bool Group122Var2::Read(RSlice& buffer, Group122Var2& output) +{ + return Parse::Many(buffer, output.flags, output.assocId, output.value, output.time); +} + +bool Group122Var2::Write(const Group122Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.assocId, arg.value, arg.time); +} + +bool Group122Var2::ReadTarget(RSlice& buff, SecurityStat& output) +{ + Group122Var2 value; + if(Read(buff, value)) + { + output = SecurityStatFactory::From(value.flags, value.assocId, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group122Var2::WriteTarget(const SecurityStat& value, openpal::WSlice& buff) +{ + return Group122Var2::Write(ConvertGroup122Var2::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.h new file mode 100644 index 0000000..e725d1d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group122.h @@ -0,0 +1,89 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP122_H +#define OPENDNP3_GROUP122_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Security Statistic event - Any Variation +struct Group122Var0 +{ + static GroupVariationID ID() { return GroupVariationID(122,0); } +}; + +// Security Statistic event - 32-bit With Flag +struct Group122Var1 +{ + static GroupVariationID ID() { return GroupVariationID(122,1); } + + Group122Var1(); + + static uint32_t Size() { return 7; } + static bool Read(openpal::RSlice&, Group122Var1&); + static bool Write(const Group122Var1&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint16_t assocId; + uint32_t value; + + typedef SecurityStat Target; + typedef SecurityStatSpec Spec; + static bool ReadTarget(openpal::RSlice&, SecurityStat&); + static bool WriteTarget(const SecurityStat&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Security Statistic event - 32-bit With Flag and Time +struct Group122Var2 +{ + static GroupVariationID ID() { return GroupVariationID(122,2); } + + Group122Var2(); + + static uint32_t Size() { return 13; } + static bool Read(openpal::RSlice&, Group122Var2&); + static bool Write(const Group122Var2&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint16_t assocId; + uint32_t value; + DNPTime time; + + typedef SecurityStat Target; + typedef SecurityStatSpec Spec; + static bool ReadTarget(openpal::RSlice&, SecurityStat&); + static bool WriteTarget(const SecurityStat&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.cpp new file mode 100644 index 0000000..61ca45f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.cpp @@ -0,0 +1,101 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group13.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group13Var1 ------- + +Group13Var1::Group13Var1() : flags(0) +{} + +bool Group13Var1::Read(RSlice& buffer, Group13Var1& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group13Var1::Write(const Group13Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group13Var1::ReadTarget(RSlice& buff, BinaryCommandEvent& output) +{ + Group13Var1 value; + if(Read(buff, value)) + { + output = BinaryCommandEventFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group13Var1::WriteTarget(const BinaryCommandEvent& value, openpal::WSlice& buff) +{ + return Group13Var1::Write(ConvertGroup13Var1::Apply(value), buff); +} + +// ------- Group13Var2 ------- + +Group13Var2::Group13Var2() : flags(0), time(0) +{} + +bool Group13Var2::Read(RSlice& buffer, Group13Var2& output) +{ + return Parse::Many(buffer, output.flags, output.time); +} + +bool Group13Var2::Write(const Group13Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.time); +} + +bool Group13Var2::ReadTarget(RSlice& buff, BinaryCommandEvent& output) +{ + Group13Var2 value; + if(Read(buff, value)) + { + output = BinaryCommandEventFactory::From(value.flags, value.time); + return true; + } + else + { + return false; + } +} + +bool Group13Var2::WriteTarget(const BinaryCommandEvent& value, openpal::WSlice& buff) +{ + return Group13Var2::Write(ConvertGroup13Var2::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.h new file mode 100644 index 0000000..1c78bad --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group13.h @@ -0,0 +1,75 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP13_H +#define OPENDNP3_GROUP13_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/BinaryCommandEvent.h" + +namespace opendnp3 { + +// Binary Command Event - Without Time +struct Group13Var1 +{ + static GroupVariationID ID() { return GroupVariationID(13,1); } + + Group13Var1(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group13Var1&); + static bool Write(const Group13Var1&, openpal::WSlice&); + + uint8_t flags; + + typedef BinaryCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, BinaryCommandEvent&); + static bool WriteTarget(const BinaryCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Binary Command Event - With Time +struct Group13Var2 +{ + static GroupVariationID ID() { return GroupVariationID(13,2); } + + Group13Var2(); + + static uint32_t Size() { return 7; } + static bool Read(openpal::RSlice&, Group13Var2&); + static bool Write(const Group13Var2&, openpal::WSlice&); + + uint8_t flags; + DNPTime time; + + typedef BinaryCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, BinaryCommandEvent&); + static bool WriteTarget(const BinaryCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.cpp new file mode 100644 index 0000000..8de77e5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.cpp @@ -0,0 +1,135 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group2.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group2Var1 ------- + +Group2Var1::Group2Var1() : flags(0) +{} + +bool Group2Var1::Read(RSlice& buffer, Group2Var1& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group2Var1::Write(const Group2Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group2Var1::ReadTarget(RSlice& buff, Binary& output) +{ + Group2Var1 value; + if(Read(buff, value)) + { + output = BinaryFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group2Var1::WriteTarget(const Binary& value, openpal::WSlice& buff) +{ + return Group2Var1::Write(ConvertGroup2Var1::Apply(value), buff); +} + +// ------- Group2Var2 ------- + +Group2Var2::Group2Var2() : flags(0), time(0) +{} + +bool Group2Var2::Read(RSlice& buffer, Group2Var2& output) +{ + return Parse::Many(buffer, output.flags, output.time); +} + +bool Group2Var2::Write(const Group2Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.time); +} + +bool Group2Var2::ReadTarget(RSlice& buff, Binary& output) +{ + Group2Var2 value; + if(Read(buff, value)) + { + output = BinaryFactory::From(value.flags, value.time); + return true; + } + else + { + return false; + } +} + +bool Group2Var2::WriteTarget(const Binary& value, openpal::WSlice& buff) +{ + return Group2Var2::Write(ConvertGroup2Var2::Apply(value), buff); +} + +// ------- Group2Var3 ------- + +Group2Var3::Group2Var3() : flags(0), time(0) +{} + +bool Group2Var3::Read(RSlice& buffer, Group2Var3& output) +{ + return Parse::Many(buffer, output.flags, output.time); +} + +bool Group2Var3::Write(const Group2Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.time); +} + +bool Group2Var3::ReadTarget(RSlice& buff, Binary& output) +{ + Group2Var3 value; + if(Read(buff, value)) + { + output = BinaryFactory::From(value.flags, value.time); + return true; + } + else + { + return false; + } +} + +bool Group2Var3::WriteTarget(const Binary& value, openpal::WSlice& buff) +{ + return Group2Var3::Write(ConvertGroup2Var3::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.h new file mode 100644 index 0000000..b1ec735 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group2.h @@ -0,0 +1,104 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP2_H +#define OPENDNP3_GROUP2_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Binary Input Event - Any Variation +struct Group2Var0 +{ + static GroupVariationID ID() { return GroupVariationID(2,0); } +}; + +// Binary Input Event - Without Time +struct Group2Var1 +{ + static GroupVariationID ID() { return GroupVariationID(2,1); } + + Group2Var1(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group2Var1&); + static bool Write(const Group2Var1&, openpal::WSlice&); + + uint8_t flags; + + typedef Binary Target; + typedef BinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, Binary&); + static bool WriteTarget(const Binary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Binary Input Event - With Absolute Time +struct Group2Var2 +{ + static GroupVariationID ID() { return GroupVariationID(2,2); } + + Group2Var2(); + + static uint32_t Size() { return 7; } + static bool Read(openpal::RSlice&, Group2Var2&); + static bool Write(const Group2Var2&, openpal::WSlice&); + + uint8_t flags; + DNPTime time; + + typedef Binary Target; + typedef BinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, Binary&); + static bool WriteTarget(const Binary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Binary Input Event - With Relative Time +struct Group2Var3 +{ + static GroupVariationID ID() { return GroupVariationID(2,3); } + + Group2Var3(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group2Var3&); + static bool Write(const Group2Var3&, openpal::WSlice&); + + uint8_t flags; + uint16_t time; + + typedef Binary Target; + typedef BinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, Binary&); + static bool WriteTarget(const Binary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.cpp new file mode 100644 index 0000000..acffd60 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.cpp @@ -0,0 +1,169 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group20.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group20Var1 ------- + +Group20Var1::Group20Var1() : flags(0), value(0) +{} + +bool Group20Var1::Read(RSlice& buffer, Group20Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group20Var1::Write(const Group20Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group20Var1::ReadTarget(RSlice& buff, Counter& output) +{ + Group20Var1 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group20Var1::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group20Var1::Write(ConvertGroup20Var1::Apply(value), buff); +} + +// ------- Group20Var2 ------- + +Group20Var2::Group20Var2() : flags(0), value(0) +{} + +bool Group20Var2::Read(RSlice& buffer, Group20Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group20Var2::Write(const Group20Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group20Var2::ReadTarget(RSlice& buff, Counter& output) +{ + Group20Var2 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group20Var2::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group20Var2::Write(ConvertGroup20Var2::Apply(value), buff); +} + +// ------- Group20Var5 ------- + +Group20Var5::Group20Var5() : value(0) +{} + +bool Group20Var5::Read(RSlice& buffer, Group20Var5& output) +{ + return Parse::Many(buffer, output.value); +} + +bool Group20Var5::Write(const Group20Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value); +} + +bool Group20Var5::ReadTarget(RSlice& buff, Counter& output) +{ + Group20Var5 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.value); + return true; + } + else + { + return false; + } +} + +bool Group20Var5::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group20Var5::Write(ConvertGroup20Var5::Apply(value), buff); +} + +// ------- Group20Var6 ------- + +Group20Var6::Group20Var6() : value(0) +{} + +bool Group20Var6::Read(RSlice& buffer, Group20Var6& output) +{ + return Parse::Many(buffer, output.value); +} + +bool Group20Var6::Write(const Group20Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value); +} + +bool Group20Var6::ReadTarget(RSlice& buff, Counter& output) +{ + Group20Var6 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.value); + return true; + } + else + { + return false; + } +} + +bool Group20Var6::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group20Var6::Write(ConvertGroup20Var6::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.h new file mode 100644 index 0000000..ab8d06b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group20.h @@ -0,0 +1,128 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP20_H +#define OPENDNP3_GROUP20_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Counter - Any Variation +struct Group20Var0 +{ + static GroupVariationID ID() { return GroupVariationID(20,0); } +}; + +// Counter - 32-bit With Flag +struct Group20Var1 +{ + static GroupVariationID ID() { return GroupVariationID(20,1); } + + Group20Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group20Var1&); + static bool Write(const Group20Var1&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Counter - 16-bit With Flag +struct Group20Var2 +{ + static GroupVariationID ID() { return GroupVariationID(20,2); } + + Group20Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group20Var2&); + static bool Write(const Group20Var2&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Counter - 32-bit Without Flag +struct Group20Var5 +{ + static GroupVariationID ID() { return GroupVariationID(20,5); } + + Group20Var5(); + + static uint32_t Size() { return 4; } + static bool Read(openpal::RSlice&, Group20Var5&); + static bool Write(const Group20Var5&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint32_t value; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Counter - 16-bit Without Flag +struct Group20Var6 +{ + static GroupVariationID ID() { return GroupVariationID(20,6); } + + Group20Var6(); + + static uint32_t Size() { return 2; } + static bool Read(openpal::RSlice&, Group20Var6&); + static bool Write(const Group20Var6&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint16_t value; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.cpp new file mode 100644 index 0000000..4895d99 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.cpp @@ -0,0 +1,237 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group21.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group21Var1 ------- + +Group21Var1::Group21Var1() : flags(0), value(0) +{} + +bool Group21Var1::Read(RSlice& buffer, Group21Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group21Var1::Write(const Group21Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group21Var1::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group21Var1 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group21Var1::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group21Var1::Write(ConvertGroup21Var1::Apply(value), buff); +} + +// ------- Group21Var2 ------- + +Group21Var2::Group21Var2() : flags(0), value(0) +{} + +bool Group21Var2::Read(RSlice& buffer, Group21Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group21Var2::Write(const Group21Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group21Var2::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group21Var2 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group21Var2::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group21Var2::Write(ConvertGroup21Var2::Apply(value), buff); +} + +// ------- Group21Var5 ------- + +Group21Var5::Group21Var5() : flags(0), value(0), time(0) +{} + +bool Group21Var5::Read(RSlice& buffer, Group21Var5& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group21Var5::Write(const Group21Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group21Var5::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group21Var5 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group21Var5::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group21Var5::Write(ConvertGroup21Var5::Apply(value), buff); +} + +// ------- Group21Var6 ------- + +Group21Var6::Group21Var6() : flags(0), value(0), time(0) +{} + +bool Group21Var6::Read(RSlice& buffer, Group21Var6& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group21Var6::Write(const Group21Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group21Var6::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group21Var6 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group21Var6::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group21Var6::Write(ConvertGroup21Var6::Apply(value), buff); +} + +// ------- Group21Var9 ------- + +Group21Var9::Group21Var9() : value(0) +{} + +bool Group21Var9::Read(RSlice& buffer, Group21Var9& output) +{ + return Parse::Many(buffer, output.value); +} + +bool Group21Var9::Write(const Group21Var9& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value); +} + +bool Group21Var9::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group21Var9 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.value); + return true; + } + else + { + return false; + } +} + +bool Group21Var9::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group21Var9::Write(ConvertGroup21Var9::Apply(value), buff); +} + +// ------- Group21Var10 ------- + +Group21Var10::Group21Var10() : value(0) +{} + +bool Group21Var10::Read(RSlice& buffer, Group21Var10& output) +{ + return Parse::Many(buffer, output.value); +} + +bool Group21Var10::Write(const Group21Var10& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value); +} + +bool Group21Var10::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group21Var10 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.value); + return true; + } + else + { + return false; + } +} + +bool Group21Var10::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group21Var10::Write(ConvertGroup21Var10::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.h new file mode 100644 index 0000000..a0c0f77 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group21.h @@ -0,0 +1,174 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP21_H +#define OPENDNP3_GROUP21_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Frozen Counter - Any Variation +struct Group21Var0 +{ + static GroupVariationID ID() { return GroupVariationID(21,0); } +}; + +// Frozen Counter - 32-bit With Flag +struct Group21Var1 +{ + static GroupVariationID ID() { return GroupVariationID(21,1); } + + Group21Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group21Var1&); + static bool Write(const Group21Var1&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter - 16-bit With Flag +struct Group21Var2 +{ + static GroupVariationID ID() { return GroupVariationID(21,2); } + + Group21Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group21Var2&); + static bool Write(const Group21Var2&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter - 32-bit With Flag and Time +struct Group21Var5 +{ + static GroupVariationID ID() { return GroupVariationID(21,5); } + + Group21Var5(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group21Var5&); + static bool Write(const Group21Var5&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + DNPTime time; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter - 16-bit With Flag and Time +struct Group21Var6 +{ + static GroupVariationID ID() { return GroupVariationID(21,6); } + + Group21Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group21Var6&); + static bool Write(const Group21Var6&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + DNPTime time; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter - 32-bit Without Flag +struct Group21Var9 +{ + static GroupVariationID ID() { return GroupVariationID(21,9); } + + Group21Var9(); + + static uint32_t Size() { return 4; } + static bool Read(openpal::RSlice&, Group21Var9&); + static bool Write(const Group21Var9&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint32_t value; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter - 16-bit Without Flag +struct Group21Var10 +{ + static GroupVariationID ID() { return GroupVariationID(21,10); } + + Group21Var10(); + + static uint32_t Size() { return 2; } + static bool Read(openpal::RSlice&, Group21Var10&); + static bool Write(const Group21Var10&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint16_t value; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.cpp new file mode 100644 index 0000000..b0f5335 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.cpp @@ -0,0 +1,169 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group22.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group22Var1 ------- + +Group22Var1::Group22Var1() : flags(0), value(0) +{} + +bool Group22Var1::Read(RSlice& buffer, Group22Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group22Var1::Write(const Group22Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group22Var1::ReadTarget(RSlice& buff, Counter& output) +{ + Group22Var1 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group22Var1::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group22Var1::Write(ConvertGroup22Var1::Apply(value), buff); +} + +// ------- Group22Var2 ------- + +Group22Var2::Group22Var2() : flags(0), value(0) +{} + +bool Group22Var2::Read(RSlice& buffer, Group22Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group22Var2::Write(const Group22Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group22Var2::ReadTarget(RSlice& buff, Counter& output) +{ + Group22Var2 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group22Var2::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group22Var2::Write(ConvertGroup22Var2::Apply(value), buff); +} + +// ------- Group22Var5 ------- + +Group22Var5::Group22Var5() : flags(0), value(0), time(0) +{} + +bool Group22Var5::Read(RSlice& buffer, Group22Var5& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group22Var5::Write(const Group22Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group22Var5::ReadTarget(RSlice& buff, Counter& output) +{ + Group22Var5 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group22Var5::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group22Var5::Write(ConvertGroup22Var5::Apply(value), buff); +} + +// ------- Group22Var6 ------- + +Group22Var6::Group22Var6() : flags(0), value(0), time(0) +{} + +bool Group22Var6::Read(RSlice& buffer, Group22Var6& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group22Var6::Write(const Group22Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group22Var6::ReadTarget(RSlice& buff, Counter& output) +{ + Group22Var6 value; + if(Read(buff, value)) + { + output = CounterFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group22Var6::WriteTarget(const Counter& value, openpal::WSlice& buff) +{ + return Group22Var6::Write(ConvertGroup22Var6::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.h new file mode 100644 index 0000000..0649b0e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group22.h @@ -0,0 +1,132 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP22_H +#define OPENDNP3_GROUP22_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Counter Event - Any Variation +struct Group22Var0 +{ + static GroupVariationID ID() { return GroupVariationID(22,0); } +}; + +// Counter Event - 32-bit With Flag +struct Group22Var1 +{ + static GroupVariationID ID() { return GroupVariationID(22,1); } + + Group22Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group22Var1&); + static bool Write(const Group22Var1&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Counter Event - 16-bit With Flag +struct Group22Var2 +{ + static GroupVariationID ID() { return GroupVariationID(22,2); } + + Group22Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group22Var2&); + static bool Write(const Group22Var2&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Counter Event - 32-bit With Flag and Time +struct Group22Var5 +{ + static GroupVariationID ID() { return GroupVariationID(22,5); } + + Group22Var5(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group22Var5&); + static bool Write(const Group22Var5&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + DNPTime time; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Counter Event - 16-bit With Flag and Time +struct Group22Var6 +{ + static GroupVariationID ID() { return GroupVariationID(22,6); } + + Group22Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group22Var6&); + static bool Write(const Group22Var6&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + DNPTime time; + + typedef Counter Target; + typedef CounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, Counter&); + static bool WriteTarget(const Counter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.cpp new file mode 100644 index 0000000..c0997d3 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.cpp @@ -0,0 +1,169 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group23.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group23Var1 ------- + +Group23Var1::Group23Var1() : flags(0), value(0) +{} + +bool Group23Var1::Read(RSlice& buffer, Group23Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group23Var1::Write(const Group23Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group23Var1::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group23Var1 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group23Var1::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group23Var1::Write(ConvertGroup23Var1::Apply(value), buff); +} + +// ------- Group23Var2 ------- + +Group23Var2::Group23Var2() : flags(0), value(0) +{} + +bool Group23Var2::Read(RSlice& buffer, Group23Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group23Var2::Write(const Group23Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group23Var2::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group23Var2 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group23Var2::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group23Var2::Write(ConvertGroup23Var2::Apply(value), buff); +} + +// ------- Group23Var5 ------- + +Group23Var5::Group23Var5() : flags(0), value(0), time(0) +{} + +bool Group23Var5::Read(RSlice& buffer, Group23Var5& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group23Var5::Write(const Group23Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group23Var5::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group23Var5 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group23Var5::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group23Var5::Write(ConvertGroup23Var5::Apply(value), buff); +} + +// ------- Group23Var6 ------- + +Group23Var6::Group23Var6() : flags(0), value(0), time(0) +{} + +bool Group23Var6::Read(RSlice& buffer, Group23Var6& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group23Var6::Write(const Group23Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group23Var6::ReadTarget(RSlice& buff, FrozenCounter& output) +{ + Group23Var6 value; + if(Read(buff, value)) + { + output = FrozenCounterFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group23Var6::WriteTarget(const FrozenCounter& value, openpal::WSlice& buff) +{ + return Group23Var6::Write(ConvertGroup23Var6::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.h new file mode 100644 index 0000000..6fb7077 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group23.h @@ -0,0 +1,132 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP23_H +#define OPENDNP3_GROUP23_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Frozen Counter Event - Any Variation +struct Group23Var0 +{ + static GroupVariationID ID() { return GroupVariationID(23,0); } +}; + +// Frozen Counter Event - 32-bit With Flag +struct Group23Var1 +{ + static GroupVariationID ID() { return GroupVariationID(23,1); } + + Group23Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group23Var1&); + static bool Write(const Group23Var1&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter Event - 16-bit With Flag +struct Group23Var2 +{ + static GroupVariationID ID() { return GroupVariationID(23,2); } + + Group23Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group23Var2&); + static bool Write(const Group23Var2&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter Event - 32-bit With Flag and Time +struct Group23Var5 +{ + static GroupVariationID ID() { return GroupVariationID(23,5); } + + Group23Var5(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group23Var5&); + static bool Write(const Group23Var5&, openpal::WSlice&); + + typedef uint32_t ValueType; + uint8_t flags; + uint32_t value; + DNPTime time; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Frozen Counter Event - 16-bit With Flag and Time +struct Group23Var6 +{ + static GroupVariationID ID() { return GroupVariationID(23,6); } + + Group23Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group23Var6&); + static bool Write(const Group23Var6&, openpal::WSlice&); + + typedef uint16_t ValueType; + uint8_t flags; + uint16_t value; + DNPTime time; + + typedef FrozenCounter Target; + typedef FrozenCounterSpec Spec; + static bool ReadTarget(openpal::RSlice&, FrozenCounter&); + static bool WriteTarget(const FrozenCounter&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.cpp new file mode 100644 index 0000000..dc64482 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.cpp @@ -0,0 +1,67 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group3.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group3Var2 ------- + +Group3Var2::Group3Var2() : flags(0) +{} + +bool Group3Var2::Read(RSlice& buffer, Group3Var2& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group3Var2::Write(const Group3Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group3Var2::ReadTarget(RSlice& buff, DoubleBitBinary& output) +{ + Group3Var2 value; + if(Read(buff, value)) + { + output = DoubleBitBinaryFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group3Var2::WriteTarget(const DoubleBitBinary& value, openpal::WSlice& buff) +{ + return Group3Var2::Write(ConvertGroup3Var2::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.h new file mode 100644 index 0000000..b6d275d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group3.h @@ -0,0 +1,68 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP3_H +#define OPENDNP3_GROUP3_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Double-bit Binary Input - Any Variation +struct Group3Var0 +{ + static GroupVariationID ID() { return GroupVariationID(3,0); } +}; + +// Double-bit Binary Input - Packed Format +struct Group3Var1 +{ + static GroupVariationID ID() { return GroupVariationID(3,1); } +}; + +// Double-bit Binary Input - With Flags +struct Group3Var2 +{ + static GroupVariationID ID() { return GroupVariationID(3,2); } + + Group3Var2(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group3Var2&); + static bool Write(const Group3Var2&, openpal::WSlice&); + + uint8_t flags; + + typedef DoubleBitBinary Target; + typedef DoubleBitBinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, DoubleBitBinary&); + static bool WriteTarget(const DoubleBitBinary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.cpp new file mode 100644 index 0000000..7adc2b1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.cpp @@ -0,0 +1,237 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group30.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group30Var1 ------- + +Group30Var1::Group30Var1() : flags(0), value(0) +{} + +bool Group30Var1::Read(RSlice& buffer, Group30Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group30Var1::Write(const Group30Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group30Var1::ReadTarget(RSlice& buff, Analog& output) +{ + Group30Var1 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group30Var1::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group30Var1::Write(ConvertGroup30Var1::Apply(value), buff); +} + +// ------- Group30Var2 ------- + +Group30Var2::Group30Var2() : flags(0), value(0) +{} + +bool Group30Var2::Read(RSlice& buffer, Group30Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group30Var2::Write(const Group30Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group30Var2::ReadTarget(RSlice& buff, Analog& output) +{ + Group30Var2 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group30Var2::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group30Var2::Write(ConvertGroup30Var2::Apply(value), buff); +} + +// ------- Group30Var3 ------- + +Group30Var3::Group30Var3() : value(0) +{} + +bool Group30Var3::Read(RSlice& buffer, Group30Var3& output) +{ + return Parse::Many(buffer, output.value); +} + +bool Group30Var3::Write(const Group30Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value); +} + +bool Group30Var3::ReadTarget(RSlice& buff, Analog& output) +{ + Group30Var3 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.value); + return true; + } + else + { + return false; + } +} + +bool Group30Var3::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group30Var3::Write(ConvertGroup30Var3::Apply(value), buff); +} + +// ------- Group30Var4 ------- + +Group30Var4::Group30Var4() : value(0) +{} + +bool Group30Var4::Read(RSlice& buffer, Group30Var4& output) +{ + return Parse::Many(buffer, output.value); +} + +bool Group30Var4::Write(const Group30Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value); +} + +bool Group30Var4::ReadTarget(RSlice& buff, Analog& output) +{ + Group30Var4 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.value); + return true; + } + else + { + return false; + } +} + +bool Group30Var4::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group30Var4::Write(ConvertGroup30Var4::Apply(value), buff); +} + +// ------- Group30Var5 ------- + +Group30Var5::Group30Var5() : flags(0), value(0.0) +{} + +bool Group30Var5::Read(RSlice& buffer, Group30Var5& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group30Var5::Write(const Group30Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group30Var5::ReadTarget(RSlice& buff, Analog& output) +{ + Group30Var5 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group30Var5::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group30Var5::Write(ConvertGroup30Var5::Apply(value), buff); +} + +// ------- Group30Var6 ------- + +Group30Var6::Group30Var6() : flags(0), value(0.0) +{} + +bool Group30Var6::Read(RSlice& buffer, Group30Var6& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group30Var6::Write(const Group30Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group30Var6::ReadTarget(RSlice& buff, Analog& output) +{ + Group30Var6 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group30Var6::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group30Var6::Write(ConvertGroup30Var6::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.h new file mode 100644 index 0000000..00d1858 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group30.h @@ -0,0 +1,172 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP30_H +#define OPENDNP3_GROUP30_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Analog Input - Any Variation +struct Group30Var0 +{ + static GroupVariationID ID() { return GroupVariationID(30,0); } +}; + +// Analog Input - 32-bit With Flag +struct Group30Var1 +{ + static GroupVariationID ID() { return GroupVariationID(30,1); } + + Group30Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group30Var1&); + static bool Write(const Group30Var1&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t flags; + int32_t value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input - 16-bit With Flag +struct Group30Var2 +{ + static GroupVariationID ID() { return GroupVariationID(30,2); } + + Group30Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group30Var2&); + static bool Write(const Group30Var2&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t flags; + int16_t value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input - 32-bit Without Flag +struct Group30Var3 +{ + static GroupVariationID ID() { return GroupVariationID(30,3); } + + Group30Var3(); + + static uint32_t Size() { return 4; } + static bool Read(openpal::RSlice&, Group30Var3&); + static bool Write(const Group30Var3&, openpal::WSlice&); + + typedef int32_t ValueType; + int32_t value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input - 16-bit Without Flag +struct Group30Var4 +{ + static GroupVariationID ID() { return GroupVariationID(30,4); } + + Group30Var4(); + + static uint32_t Size() { return 2; } + static bool Read(openpal::RSlice&, Group30Var4&); + static bool Write(const Group30Var4&, openpal::WSlice&); + + typedef int16_t ValueType; + int16_t value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input - Single-precision With Flag +struct Group30Var5 +{ + static GroupVariationID ID() { return GroupVariationID(30,5); } + + Group30Var5(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group30Var5&); + static bool Write(const Group30Var5&, openpal::WSlice&); + + typedef float ValueType; + uint8_t flags; + float value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input - Double-precision With Flag +struct Group30Var6 +{ + static GroupVariationID ID() { return GroupVariationID(30,6); } + + Group30Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group30Var6&); + static bool Write(const Group30Var6&, openpal::WSlice&); + + typedef double ValueType; + uint8_t flags; + double value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.cpp new file mode 100644 index 0000000..d8762e0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.cpp @@ -0,0 +1,305 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group32.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group32Var1 ------- + +Group32Var1::Group32Var1() : flags(0), value(0) +{} + +bool Group32Var1::Read(RSlice& buffer, Group32Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group32Var1::Write(const Group32Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group32Var1::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var1 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group32Var1::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var1::Write(ConvertGroup32Var1::Apply(value), buff); +} + +// ------- Group32Var2 ------- + +Group32Var2::Group32Var2() : flags(0), value(0) +{} + +bool Group32Var2::Read(RSlice& buffer, Group32Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group32Var2::Write(const Group32Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group32Var2::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var2 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group32Var2::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var2::Write(ConvertGroup32Var2::Apply(value), buff); +} + +// ------- Group32Var3 ------- + +Group32Var3::Group32Var3() : flags(0), value(0), time(0) +{} + +bool Group32Var3::Read(RSlice& buffer, Group32Var3& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group32Var3::Write(const Group32Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group32Var3::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var3 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group32Var3::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var3::Write(ConvertGroup32Var3::Apply(value), buff); +} + +// ------- Group32Var4 ------- + +Group32Var4::Group32Var4() : flags(0), value(0), time(0) +{} + +bool Group32Var4::Read(RSlice& buffer, Group32Var4& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group32Var4::Write(const Group32Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group32Var4::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var4 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group32Var4::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var4::Write(ConvertGroup32Var4::Apply(value), buff); +} + +// ------- Group32Var5 ------- + +Group32Var5::Group32Var5() : flags(0), value(0.0) +{} + +bool Group32Var5::Read(RSlice& buffer, Group32Var5& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group32Var5::Write(const Group32Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group32Var5::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var5 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group32Var5::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var5::Write(ConvertGroup32Var5::Apply(value), buff); +} + +// ------- Group32Var6 ------- + +Group32Var6::Group32Var6() : flags(0), value(0.0) +{} + +bool Group32Var6::Read(RSlice& buffer, Group32Var6& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group32Var6::Write(const Group32Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group32Var6::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var6 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group32Var6::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var6::Write(ConvertGroup32Var6::Apply(value), buff); +} + +// ------- Group32Var7 ------- + +Group32Var7::Group32Var7() : flags(0), value(0.0), time(0) +{} + +bool Group32Var7::Read(RSlice& buffer, Group32Var7& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group32Var7::Write(const Group32Var7& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group32Var7::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var7 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group32Var7::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var7::Write(ConvertGroup32Var7::Apply(value), buff); +} + +// ------- Group32Var8 ------- + +Group32Var8::Group32Var8() : flags(0), value(0.0), time(0) +{} + +bool Group32Var8::Read(RSlice& buffer, Group32Var8& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group32Var8::Write(const Group32Var8& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group32Var8::ReadTarget(RSlice& buff, Analog& output) +{ + Group32Var8 value; + if(Read(buff, value)) + { + output = AnalogFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group32Var8::WriteTarget(const Analog& value, openpal::WSlice& buff) +{ + return Group32Var8::Write(ConvertGroup32Var8::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.h new file mode 100644 index 0000000..78ea5a0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group32.h @@ -0,0 +1,222 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP32_H +#define OPENDNP3_GROUP32_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Analog Input Event - Any Variation +struct Group32Var0 +{ + static GroupVariationID ID() { return GroupVariationID(32,0); } +}; + +// Analog Input Event - 32-bit With Flag +struct Group32Var1 +{ + static GroupVariationID ID() { return GroupVariationID(32,1); } + + Group32Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group32Var1&); + static bool Write(const Group32Var1&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t flags; + int32_t value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - 16-bit With Flag +struct Group32Var2 +{ + static GroupVariationID ID() { return GroupVariationID(32,2); } + + Group32Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group32Var2&); + static bool Write(const Group32Var2&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t flags; + int16_t value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - 32-bit With Flag and Time +struct Group32Var3 +{ + static GroupVariationID ID() { return GroupVariationID(32,3); } + + Group32Var3(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group32Var3&); + static bool Write(const Group32Var3&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t flags; + int32_t value; + DNPTime time; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - 16-bit With Flag and Time +struct Group32Var4 +{ + static GroupVariationID ID() { return GroupVariationID(32,4); } + + Group32Var4(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group32Var4&); + static bool Write(const Group32Var4&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t flags; + int16_t value; + DNPTime time; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - Single-precision With Flag +struct Group32Var5 +{ + static GroupVariationID ID() { return GroupVariationID(32,5); } + + Group32Var5(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group32Var5&); + static bool Write(const Group32Var5&, openpal::WSlice&); + + typedef float ValueType; + uint8_t flags; + float value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - Double-precision With Flag +struct Group32Var6 +{ + static GroupVariationID ID() { return GroupVariationID(32,6); } + + Group32Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group32Var6&); + static bool Write(const Group32Var6&, openpal::WSlice&); + + typedef double ValueType; + uint8_t flags; + double value; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - Single-precision With Flag and Time +struct Group32Var7 +{ + static GroupVariationID ID() { return GroupVariationID(32,7); } + + Group32Var7(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group32Var7&); + static bool Write(const Group32Var7&, openpal::WSlice&); + + typedef float ValueType; + uint8_t flags; + float value; + DNPTime time; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Input Event - Double-precision With Flag and Time +struct Group32Var8 +{ + static GroupVariationID ID() { return GroupVariationID(32,8); } + + Group32Var8(); + + static uint32_t Size() { return 15; } + static bool Read(openpal::RSlice&, Group32Var8&); + static bool Write(const Group32Var8&, openpal::WSlice&); + + typedef double ValueType; + uint8_t flags; + double value; + DNPTime time; + + typedef Analog Target; + typedef AnalogSpec Spec; + static bool ReadTarget(openpal::RSlice&, Analog&); + static bool WriteTarget(const Analog&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.cpp new file mode 100644 index 0000000..c33581f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.cpp @@ -0,0 +1,135 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group4.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group4Var1 ------- + +Group4Var1::Group4Var1() : flags(0) +{} + +bool Group4Var1::Read(RSlice& buffer, Group4Var1& output) +{ + return Parse::Many(buffer, output.flags); +} + +bool Group4Var1::Write(const Group4Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags); +} + +bool Group4Var1::ReadTarget(RSlice& buff, DoubleBitBinary& output) +{ + Group4Var1 value; + if(Read(buff, value)) + { + output = DoubleBitBinaryFactory::From(value.flags); + return true; + } + else + { + return false; + } +} + +bool Group4Var1::WriteTarget(const DoubleBitBinary& value, openpal::WSlice& buff) +{ + return Group4Var1::Write(ConvertGroup4Var1::Apply(value), buff); +} + +// ------- Group4Var2 ------- + +Group4Var2::Group4Var2() : flags(0), time(0) +{} + +bool Group4Var2::Read(RSlice& buffer, Group4Var2& output) +{ + return Parse::Many(buffer, output.flags, output.time); +} + +bool Group4Var2::Write(const Group4Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.time); +} + +bool Group4Var2::ReadTarget(RSlice& buff, DoubleBitBinary& output) +{ + Group4Var2 value; + if(Read(buff, value)) + { + output = DoubleBitBinaryFactory::From(value.flags, value.time); + return true; + } + else + { + return false; + } +} + +bool Group4Var2::WriteTarget(const DoubleBitBinary& value, openpal::WSlice& buff) +{ + return Group4Var2::Write(ConvertGroup4Var2::Apply(value), buff); +} + +// ------- Group4Var3 ------- + +Group4Var3::Group4Var3() : flags(0), time(0) +{} + +bool Group4Var3::Read(RSlice& buffer, Group4Var3& output) +{ + return Parse::Many(buffer, output.flags, output.time); +} + +bool Group4Var3::Write(const Group4Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.time); +} + +bool Group4Var3::ReadTarget(RSlice& buff, DoubleBitBinary& output) +{ + Group4Var3 value; + if(Read(buff, value)) + { + output = DoubleBitBinaryFactory::From(value.flags, value.time); + return true; + } + else + { + return false; + } +} + +bool Group4Var3::WriteTarget(const DoubleBitBinary& value, openpal::WSlice& buff) +{ + return Group4Var3::Write(ConvertGroup4Var3::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.h new file mode 100644 index 0000000..54ff64c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group4.h @@ -0,0 +1,104 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP4_H +#define OPENDNP3_GROUP4_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Double-bit Binary Input Event - Any Variation +struct Group4Var0 +{ + static GroupVariationID ID() { return GroupVariationID(4,0); } +}; + +// Double-bit Binary Input Event - Without Time +struct Group4Var1 +{ + static GroupVariationID ID() { return GroupVariationID(4,1); } + + Group4Var1(); + + static uint32_t Size() { return 1; } + static bool Read(openpal::RSlice&, Group4Var1&); + static bool Write(const Group4Var1&, openpal::WSlice&); + + uint8_t flags; + + typedef DoubleBitBinary Target; + typedef DoubleBitBinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, DoubleBitBinary&); + static bool WriteTarget(const DoubleBitBinary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Double-bit Binary Input Event - With Absolute Time +struct Group4Var2 +{ + static GroupVariationID ID() { return GroupVariationID(4,2); } + + Group4Var2(); + + static uint32_t Size() { return 7; } + static bool Read(openpal::RSlice&, Group4Var2&); + static bool Write(const Group4Var2&, openpal::WSlice&); + + uint8_t flags; + DNPTime time; + + typedef DoubleBitBinary Target; + typedef DoubleBitBinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, DoubleBitBinary&); + static bool WriteTarget(const DoubleBitBinary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Double-bit Binary Input Event - With Relative Time +struct Group4Var3 +{ + static GroupVariationID ID() { return GroupVariationID(4,3); } + + Group4Var3(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group4Var3&); + static bool Write(const Group4Var3&, openpal::WSlice&); + + uint8_t flags; + uint16_t time; + + typedef DoubleBitBinary Target; + typedef DoubleBitBinarySpec Spec; + static bool ReadTarget(openpal::RSlice&, DoubleBitBinary&); + static bool WriteTarget(const DoubleBitBinary&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.cpp new file mode 100644 index 0000000..ffe36d6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.cpp @@ -0,0 +1,169 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group40.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group40Var1 ------- + +Group40Var1::Group40Var1() : flags(0), value(0) +{} + +bool Group40Var1::Read(RSlice& buffer, Group40Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group40Var1::Write(const Group40Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group40Var1::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group40Var1 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group40Var1::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group40Var1::Write(ConvertGroup40Var1::Apply(value), buff); +} + +// ------- Group40Var2 ------- + +Group40Var2::Group40Var2() : flags(0), value(0) +{} + +bool Group40Var2::Read(RSlice& buffer, Group40Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group40Var2::Write(const Group40Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group40Var2::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group40Var2 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group40Var2::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group40Var2::Write(ConvertGroup40Var2::Apply(value), buff); +} + +// ------- Group40Var3 ------- + +Group40Var3::Group40Var3() : flags(0), value(0.0) +{} + +bool Group40Var3::Read(RSlice& buffer, Group40Var3& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group40Var3::Write(const Group40Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group40Var3::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group40Var3 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group40Var3::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group40Var3::Write(ConvertGroup40Var3::Apply(value), buff); +} + +// ------- Group40Var4 ------- + +Group40Var4::Group40Var4() : flags(0), value(0.0) +{} + +bool Group40Var4::Read(RSlice& buffer, Group40Var4& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group40Var4::Write(const Group40Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group40Var4::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group40Var4 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group40Var4::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group40Var4::Write(ConvertGroup40Var4::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.h new file mode 100644 index 0000000..64d60fb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group40.h @@ -0,0 +1,130 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP40_H +#define OPENDNP3_GROUP40_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Analog Output Status - Any Variation +struct Group40Var0 +{ + static GroupVariationID ID() { return GroupVariationID(40,0); } +}; + +// Analog Output Status - 32-bit With Flag +struct Group40Var1 +{ + static GroupVariationID ID() { return GroupVariationID(40,1); } + + Group40Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group40Var1&); + static bool Write(const Group40Var1&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t flags; + int32_t value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Status - 16-bit With Flag +struct Group40Var2 +{ + static GroupVariationID ID() { return GroupVariationID(40,2); } + + Group40Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group40Var2&); + static bool Write(const Group40Var2&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t flags; + int16_t value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Status - Single-precision With Flag +struct Group40Var3 +{ + static GroupVariationID ID() { return GroupVariationID(40,3); } + + Group40Var3(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group40Var3&); + static bool Write(const Group40Var3&, openpal::WSlice&); + + typedef float ValueType; + uint8_t flags; + float value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Status - Double-precision With Flag +struct Group40Var4 +{ + static GroupVariationID ID() { return GroupVariationID(40,4); } + + Group40Var4(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group40Var4&); + static bool Write(const Group40Var4&, openpal::WSlice&); + + typedef double ValueType; + uint8_t flags; + double value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.cpp new file mode 100644 index 0000000..22d6150 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.cpp @@ -0,0 +1,169 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group41.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group41Var1 ------- + +Group41Var1::Group41Var1() : value(0), status(0) +{} + +bool Group41Var1::Read(RSlice& buffer, Group41Var1& output) +{ + return Parse::Many(buffer, output.value, output.status); +} + +bool Group41Var1::Write(const Group41Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value, arg.status); +} + +bool Group41Var1::ReadTarget(RSlice& buff, AnalogOutputInt32& output) +{ + Group41Var1 value; + if(Read(buff, value)) + { + output = AnalogOutputInt32Factory::From(value.value, value.status); + return true; + } + else + { + return false; + } +} + +bool Group41Var1::WriteTarget(const AnalogOutputInt32& value, openpal::WSlice& buff) +{ + return Group41Var1::Write(ConvertGroup41Var1::Apply(value), buff); +} + +// ------- Group41Var2 ------- + +Group41Var2::Group41Var2() : value(0), status(0) +{} + +bool Group41Var2::Read(RSlice& buffer, Group41Var2& output) +{ + return Parse::Many(buffer, output.value, output.status); +} + +bool Group41Var2::Write(const Group41Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value, arg.status); +} + +bool Group41Var2::ReadTarget(RSlice& buff, AnalogOutputInt16& output) +{ + Group41Var2 value; + if(Read(buff, value)) + { + output = AnalogOutputInt16Factory::From(value.value, value.status); + return true; + } + else + { + return false; + } +} + +bool Group41Var2::WriteTarget(const AnalogOutputInt16& value, openpal::WSlice& buff) +{ + return Group41Var2::Write(ConvertGroup41Var2::Apply(value), buff); +} + +// ------- Group41Var3 ------- + +Group41Var3::Group41Var3() : value(0.0), status(0) +{} + +bool Group41Var3::Read(RSlice& buffer, Group41Var3& output) +{ + return Parse::Many(buffer, output.value, output.status); +} + +bool Group41Var3::Write(const Group41Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value, arg.status); +} + +bool Group41Var3::ReadTarget(RSlice& buff, AnalogOutputFloat32& output) +{ + Group41Var3 value; + if(Read(buff, value)) + { + output = AnalogOutputFloat32Factory::From(value.value, value.status); + return true; + } + else + { + return false; + } +} + +bool Group41Var3::WriteTarget(const AnalogOutputFloat32& value, openpal::WSlice& buff) +{ + return Group41Var3::Write(ConvertGroup41Var3::Apply(value), buff); +} + +// ------- Group41Var4 ------- + +Group41Var4::Group41Var4() : value(0.0), status(0) +{} + +bool Group41Var4::Read(RSlice& buffer, Group41Var4& output) +{ + return Parse::Many(buffer, output.value, output.status); +} + +bool Group41Var4::Write(const Group41Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.value, arg.status); +} + +bool Group41Var4::ReadTarget(RSlice& buff, AnalogOutputDouble64& output) +{ + Group41Var4 value; + if(Read(buff, value)) + { + output = AnalogOutputDouble64Factory::From(value.value, value.status); + return true; + } + else + { + return false; + } +} + +bool Group41Var4::WriteTarget(const AnalogOutputDouble64& value, openpal::WSlice& buff) +{ + return Group41Var4::Write(ConvertGroup41Var4::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.h new file mode 100644 index 0000000..165efa1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group41.h @@ -0,0 +1,126 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP41_H +#define OPENDNP3_GROUP41_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/AnalogOutput.h" + +namespace opendnp3 { + +// Analog Output - Any Variation +struct Group41Var0 +{ + static GroupVariationID ID() { return GroupVariationID(41,0); } +}; + +// Analog Output - 32-bit With Flag +struct Group41Var1 +{ + static GroupVariationID ID() { return GroupVariationID(41,1); } + + Group41Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group41Var1&); + static bool Write(const Group41Var1&, openpal::WSlice&); + + typedef int32_t ValueType; + int32_t value; + uint8_t status; + + typedef AnalogOutputInt32 Target; + static bool ReadTarget(openpal::RSlice&, AnalogOutputInt32&); + static bool WriteTarget(const AnalogOutputInt32&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output - 16-bit With Flag +struct Group41Var2 +{ + static GroupVariationID ID() { return GroupVariationID(41,2); } + + Group41Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group41Var2&); + static bool Write(const Group41Var2&, openpal::WSlice&); + + typedef int16_t ValueType; + int16_t value; + uint8_t status; + + typedef AnalogOutputInt16 Target; + static bool ReadTarget(openpal::RSlice&, AnalogOutputInt16&); + static bool WriteTarget(const AnalogOutputInt16&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output - Single-precision +struct Group41Var3 +{ + static GroupVariationID ID() { return GroupVariationID(41,3); } + + Group41Var3(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group41Var3&); + static bool Write(const Group41Var3&, openpal::WSlice&); + + typedef float ValueType; + float value; + uint8_t status; + + typedef AnalogOutputFloat32 Target; + static bool ReadTarget(openpal::RSlice&, AnalogOutputFloat32&); + static bool WriteTarget(const AnalogOutputFloat32&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output - Double-precision +struct Group41Var4 +{ + static GroupVariationID ID() { return GroupVariationID(41,4); } + + Group41Var4(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group41Var4&); + static bool Write(const Group41Var4&, openpal::WSlice&); + + typedef double ValueType; + double value; + uint8_t status; + + typedef AnalogOutputDouble64 Target; + static bool ReadTarget(openpal::RSlice&, AnalogOutputDouble64&); + static bool WriteTarget(const AnalogOutputDouble64&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.cpp new file mode 100644 index 0000000..816a495 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.cpp @@ -0,0 +1,305 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group42.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group42Var1 ------- + +Group42Var1::Group42Var1() : flags(0), value(0) +{} + +bool Group42Var1::Read(RSlice& buffer, Group42Var1& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group42Var1::Write(const Group42Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group42Var1::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var1 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group42Var1::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var1::Write(ConvertGroup42Var1::Apply(value), buff); +} + +// ------- Group42Var2 ------- + +Group42Var2::Group42Var2() : flags(0), value(0) +{} + +bool Group42Var2::Read(RSlice& buffer, Group42Var2& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group42Var2::Write(const Group42Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group42Var2::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var2 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group42Var2::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var2::Write(ConvertGroup42Var2::Apply(value), buff); +} + +// ------- Group42Var3 ------- + +Group42Var3::Group42Var3() : flags(0), value(0), time(0) +{} + +bool Group42Var3::Read(RSlice& buffer, Group42Var3& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group42Var3::Write(const Group42Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group42Var3::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var3 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group42Var3::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var3::Write(ConvertGroup42Var3::Apply(value), buff); +} + +// ------- Group42Var4 ------- + +Group42Var4::Group42Var4() : flags(0), value(0), time(0) +{} + +bool Group42Var4::Read(RSlice& buffer, Group42Var4& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group42Var4::Write(const Group42Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group42Var4::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var4 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group42Var4::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var4::Write(ConvertGroup42Var4::Apply(value), buff); +} + +// ------- Group42Var5 ------- + +Group42Var5::Group42Var5() : flags(0), value(0.0) +{} + +bool Group42Var5::Read(RSlice& buffer, Group42Var5& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group42Var5::Write(const Group42Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group42Var5::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var5 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group42Var5::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var5::Write(ConvertGroup42Var5::Apply(value), buff); +} + +// ------- Group42Var6 ------- + +Group42Var6::Group42Var6() : flags(0), value(0.0) +{} + +bool Group42Var6::Read(RSlice& buffer, Group42Var6& output) +{ + return Parse::Many(buffer, output.flags, output.value); +} + +bool Group42Var6::Write(const Group42Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value); +} + +bool Group42Var6::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var6 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value); + return true; + } + else + { + return false; + } +} + +bool Group42Var6::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var6::Write(ConvertGroup42Var6::Apply(value), buff); +} + +// ------- Group42Var7 ------- + +Group42Var7::Group42Var7() : flags(0), value(0.0), time(0) +{} + +bool Group42Var7::Read(RSlice& buffer, Group42Var7& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group42Var7::Write(const Group42Var7& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group42Var7::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var7 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group42Var7::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var7::Write(ConvertGroup42Var7::Apply(value), buff); +} + +// ------- Group42Var8 ------- + +Group42Var8::Group42Var8() : flags(0), value(0.0), time(0) +{} + +bool Group42Var8::Read(RSlice& buffer, Group42Var8& output) +{ + return Parse::Many(buffer, output.flags, output.value, output.time); +} + +bool Group42Var8::Write(const Group42Var8& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.flags, arg.value, arg.time); +} + +bool Group42Var8::ReadTarget(RSlice& buff, AnalogOutputStatus& output) +{ + Group42Var8 value; + if(Read(buff, value)) + { + output = AnalogOutputStatusFactory::From(value.flags, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group42Var8::WriteTarget(const AnalogOutputStatus& value, openpal::WSlice& buff) +{ + return Group42Var8::Write(ConvertGroup42Var8::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.h new file mode 100644 index 0000000..ed7c498 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group42.h @@ -0,0 +1,222 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP42_H +#define OPENDNP3_GROUP42_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Analog Output Event - Any Variation +struct Group42Var0 +{ + static GroupVariationID ID() { return GroupVariationID(42,0); } +}; + +// Analog Output Event - 32-bit With Flag +struct Group42Var1 +{ + static GroupVariationID ID() { return GroupVariationID(42,1); } + + Group42Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group42Var1&); + static bool Write(const Group42Var1&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t flags; + int32_t value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - 16-bit With Flag +struct Group42Var2 +{ + static GroupVariationID ID() { return GroupVariationID(42,2); } + + Group42Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group42Var2&); + static bool Write(const Group42Var2&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t flags; + int16_t value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - 32-bit With Flag and Time +struct Group42Var3 +{ + static GroupVariationID ID() { return GroupVariationID(42,3); } + + Group42Var3(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group42Var3&); + static bool Write(const Group42Var3&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t flags; + int32_t value; + DNPTime time; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - 16-bit With Flag and Time +struct Group42Var4 +{ + static GroupVariationID ID() { return GroupVariationID(42,4); } + + Group42Var4(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group42Var4&); + static bool Write(const Group42Var4&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t flags; + int16_t value; + DNPTime time; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - Single-precision With Flag +struct Group42Var5 +{ + static GroupVariationID ID() { return GroupVariationID(42,5); } + + Group42Var5(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group42Var5&); + static bool Write(const Group42Var5&, openpal::WSlice&); + + typedef float ValueType; + uint8_t flags; + float value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - Double-precision With Flag +struct Group42Var6 +{ + static GroupVariationID ID() { return GroupVariationID(42,6); } + + Group42Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group42Var6&); + static bool Write(const Group42Var6&, openpal::WSlice&); + + typedef double ValueType; + uint8_t flags; + double value; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - Single-precision With Flag and Time +struct Group42Var7 +{ + static GroupVariationID ID() { return GroupVariationID(42,7); } + + Group42Var7(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group42Var7&); + static bool Write(const Group42Var7&, openpal::WSlice&); + + typedef float ValueType; + uint8_t flags; + float value; + DNPTime time; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Output Event - Double-precision With Flag and Time +struct Group42Var8 +{ + static GroupVariationID ID() { return GroupVariationID(42,8); } + + Group42Var8(); + + static uint32_t Size() { return 15; } + static bool Read(openpal::RSlice&, Group42Var8&); + static bool Write(const Group42Var8&, openpal::WSlice&); + + typedef double ValueType; + uint8_t flags; + double value; + DNPTime time; + + typedef AnalogOutputStatus Target; + typedef AnalogOutputStatusSpec Spec; + static bool ReadTarget(openpal::RSlice&, AnalogOutputStatus&); + static bool WriteTarget(const AnalogOutputStatus&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.cpp new file mode 100644 index 0000000..4887940 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.cpp @@ -0,0 +1,305 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group43.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group43Var1 ------- + +Group43Var1::Group43Var1() : status(0), value(0) +{} + +bool Group43Var1::Read(RSlice& buffer, Group43Var1& output) +{ + return Parse::Many(buffer, output.status, output.value); +} + +bool Group43Var1::Write(const Group43Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value); +} + +bool Group43Var1::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var1 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value); + return true; + } + else + { + return false; + } +} + +bool Group43Var1::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var1::Write(ConvertGroup43Var1::Apply(value), buff); +} + +// ------- Group43Var2 ------- + +Group43Var2::Group43Var2() : status(0), value(0) +{} + +bool Group43Var2::Read(RSlice& buffer, Group43Var2& output) +{ + return Parse::Many(buffer, output.status, output.value); +} + +bool Group43Var2::Write(const Group43Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value); +} + +bool Group43Var2::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var2 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value); + return true; + } + else + { + return false; + } +} + +bool Group43Var2::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var2::Write(ConvertGroup43Var2::Apply(value), buff); +} + +// ------- Group43Var3 ------- + +Group43Var3::Group43Var3() : status(0), value(0), time(0) +{} + +bool Group43Var3::Read(RSlice& buffer, Group43Var3& output) +{ + return Parse::Many(buffer, output.status, output.value, output.time); +} + +bool Group43Var3::Write(const Group43Var3& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value, arg.time); +} + +bool Group43Var3::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var3 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group43Var3::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var3::Write(ConvertGroup43Var3::Apply(value), buff); +} + +// ------- Group43Var4 ------- + +Group43Var4::Group43Var4() : status(0), value(0), time(0) +{} + +bool Group43Var4::Read(RSlice& buffer, Group43Var4& output) +{ + return Parse::Many(buffer, output.status, output.value, output.time); +} + +bool Group43Var4::Write(const Group43Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value, arg.time); +} + +bool Group43Var4::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var4 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group43Var4::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var4::Write(ConvertGroup43Var4::Apply(value), buff); +} + +// ------- Group43Var5 ------- + +Group43Var5::Group43Var5() : status(0), value(0.0) +{} + +bool Group43Var5::Read(RSlice& buffer, Group43Var5& output) +{ + return Parse::Many(buffer, output.status, output.value); +} + +bool Group43Var5::Write(const Group43Var5& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value); +} + +bool Group43Var5::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var5 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value); + return true; + } + else + { + return false; + } +} + +bool Group43Var5::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var5::Write(ConvertGroup43Var5::Apply(value), buff); +} + +// ------- Group43Var6 ------- + +Group43Var6::Group43Var6() : status(0), value(0.0) +{} + +bool Group43Var6::Read(RSlice& buffer, Group43Var6& output) +{ + return Parse::Many(buffer, output.status, output.value); +} + +bool Group43Var6::Write(const Group43Var6& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value); +} + +bool Group43Var6::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var6 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value); + return true; + } + else + { + return false; + } +} + +bool Group43Var6::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var6::Write(ConvertGroup43Var6::Apply(value), buff); +} + +// ------- Group43Var7 ------- + +Group43Var7::Group43Var7() : status(0), value(0.0), time(0) +{} + +bool Group43Var7::Read(RSlice& buffer, Group43Var7& output) +{ + return Parse::Many(buffer, output.status, output.value, output.time); +} + +bool Group43Var7::Write(const Group43Var7& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value, arg.time); +} + +bool Group43Var7::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var7 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group43Var7::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var7::Write(ConvertGroup43Var7::Apply(value), buff); +} + +// ------- Group43Var8 ------- + +Group43Var8::Group43Var8() : status(0), value(0.0), time(0) +{} + +bool Group43Var8::Read(RSlice& buffer, Group43Var8& output) +{ + return Parse::Many(buffer, output.status, output.value, output.time); +} + +bool Group43Var8::Write(const Group43Var8& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.status, arg.value, arg.time); +} + +bool Group43Var8::ReadTarget(RSlice& buff, AnalogCommandEvent& output) +{ + Group43Var8 value; + if(Read(buff, value)) + { + output = AnalogCommandEventFactory::From(value.status, value.value, value.time); + return true; + } + else + { + return false; + } +} + +bool Group43Var8::WriteTarget(const AnalogCommandEvent& value, openpal::WSlice& buff) +{ + return Group43Var8::Write(ConvertGroup43Var8::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.h new file mode 100644 index 0000000..5437aa1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group43.h @@ -0,0 +1,208 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP43_H +#define OPENDNP3_GROUP43_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/AnalogCommandEvent.h" + +namespace opendnp3 { + +// Analog Command Event - 32-bit +struct Group43Var1 +{ + static GroupVariationID ID() { return GroupVariationID(43,1); } + + Group43Var1(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group43Var1&); + static bool Write(const Group43Var1&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t status; + int32_t value; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - 16-bit +struct Group43Var2 +{ + static GroupVariationID ID() { return GroupVariationID(43,2); } + + Group43Var2(); + + static uint32_t Size() { return 3; } + static bool Read(openpal::RSlice&, Group43Var2&); + static bool Write(const Group43Var2&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t status; + int16_t value; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - 32-bit With Time +struct Group43Var3 +{ + static GroupVariationID ID() { return GroupVariationID(43,3); } + + Group43Var3(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group43Var3&); + static bool Write(const Group43Var3&, openpal::WSlice&); + + typedef int32_t ValueType; + uint8_t status; + int32_t value; + DNPTime time; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - 16-bit With Time +struct Group43Var4 +{ + static GroupVariationID ID() { return GroupVariationID(43,4); } + + Group43Var4(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group43Var4&); + static bool Write(const Group43Var4&, openpal::WSlice&); + + typedef int16_t ValueType; + uint8_t status; + int16_t value; + DNPTime time; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - Single-precision +struct Group43Var5 +{ + static GroupVariationID ID() { return GroupVariationID(43,5); } + + Group43Var5(); + + static uint32_t Size() { return 5; } + static bool Read(openpal::RSlice&, Group43Var5&); + static bool Write(const Group43Var5&, openpal::WSlice&); + + typedef float ValueType; + uint8_t status; + float value; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - Double-precision +struct Group43Var6 +{ + static GroupVariationID ID() { return GroupVariationID(43,6); } + + Group43Var6(); + + static uint32_t Size() { return 9; } + static bool Read(openpal::RSlice&, Group43Var6&); + static bool Write(const Group43Var6&, openpal::WSlice&); + + typedef double ValueType; + uint8_t status; + double value; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - Single-precision With Time +struct Group43Var7 +{ + static GroupVariationID ID() { return GroupVariationID(43,7); } + + Group43Var7(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group43Var7&); + static bool Write(const Group43Var7&, openpal::WSlice&); + + typedef float ValueType; + uint8_t status; + float value; + DNPTime time; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + +// Analog Command Event - Double-precision With Time +struct Group43Var8 +{ + static GroupVariationID ID() { return GroupVariationID(43,8); } + + Group43Var8(); + + static uint32_t Size() { return 15; } + static bool Read(openpal::RSlice&, Group43Var8&); + static bool Write(const Group43Var8&, openpal::WSlice&); + + typedef double ValueType; + uint8_t status; + double value; + DNPTime time; + + typedef AnalogCommandEvent Target; + static bool ReadTarget(openpal::RSlice&, AnalogCommandEvent&); + static bool WriteTarget(const AnalogCommandEvent&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.cpp new file mode 100644 index 0000000..398f61b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.cpp @@ -0,0 +1,82 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group50.h" + +#include +#include +#include "opendnp3/app/MeasurementFactory.h" +#include "opendnp3/app/WriteConversions.h" + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group50Var1 ------- + +Group50Var1::Group50Var1() : time(0) +{} + +bool Group50Var1::Read(RSlice& buffer, Group50Var1& output) +{ + return Parse::Many(buffer, output.time); +} + +bool Group50Var1::Write(const Group50Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.time); +} + +// ------- Group50Var4 ------- + +Group50Var4::Group50Var4() : time(0), interval(0), units(0) +{} + +bool Group50Var4::Read(RSlice& buffer, Group50Var4& output) +{ + return Parse::Many(buffer, output.time, output.interval, output.units); +} + +bool Group50Var4::Write(const Group50Var4& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.time, arg.interval, arg.units); +} + +bool Group50Var4::ReadTarget(RSlice& buff, TimeAndInterval& output) +{ + Group50Var4 value; + if(Read(buff, value)) + { + output = TimeAndIntervalFactory::From(value.time, value.interval, value.units); + return true; + } + else + { + return false; + } +} + +bool Group50Var4::WriteTarget(const TimeAndInterval& value, openpal::WSlice& buff) +{ + return Group50Var4::Write(ConvertGroup50Var4::Apply(value), buff); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.h new file mode 100644 index 0000000..e27e21b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group50.h @@ -0,0 +1,72 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP50_H +#define OPENDNP3_GROUP50_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" +#include "opendnp3/app/DNP3Serializer.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" + +namespace opendnp3 { + +// Time and Date - Absolute Time +struct Group50Var1 +{ + static GroupVariationID ID() { return GroupVariationID(50,1); } + + Group50Var1(); + + static uint32_t Size() { return 6; } + static bool Read(openpal::RSlice&, Group50Var1&); + static bool Write(const Group50Var1&, openpal::WSlice&); + + DNPTime time; +}; + +// Time and Date - Indexed absolute time and long interval +struct Group50Var4 +{ + static GroupVariationID ID() { return GroupVariationID(50,4); } + + Group50Var4(); + + static uint32_t Size() { return 11; } + static bool Read(openpal::RSlice&, Group50Var4&); + static bool Write(const Group50Var4&, openpal::WSlice&); + + DNPTime time; + uint32_t interval; + uint8_t units; + + typedef TimeAndInterval Target; + typedef TimeAndIntervalSpec Spec; + static bool ReadTarget(openpal::RSlice&, TimeAndInterval&); + static bool WriteTarget(const TimeAndInterval&, openpal::WSlice&); + static DNP3Serializer Inst() { return DNP3Serializer(ID(), Size(), &ReadTarget, &WriteTarget); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.cpp new file mode 100644 index 0000000..61b7f2d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.cpp @@ -0,0 +1,61 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group51.h" + +#include +#include + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group51Var1 ------- + +Group51Var1::Group51Var1() : time(0) +{} + +bool Group51Var1::Read(RSlice& buffer, Group51Var1& output) +{ + return Parse::Many(buffer, output.time); +} + +bool Group51Var1::Write(const Group51Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.time); +} + +// ------- Group51Var2 ------- + +Group51Var2::Group51Var2() : time(0) +{} + +bool Group51Var2::Read(RSlice& buffer, Group51Var2& output) +{ + return Parse::Many(buffer, output.time); +} + +bool Group51Var2::Write(const Group51Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.time); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.h new file mode 100644 index 0000000..016dc98 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group51.h @@ -0,0 +1,62 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP51_H +#define OPENDNP3_GROUP51_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" + +namespace opendnp3 { + +// Time and Date CTO - Absolute time, synchronized +struct Group51Var1 +{ + static GroupVariationID ID() { return GroupVariationID(51,1); } + + Group51Var1(); + + static uint32_t Size() { return 6; } + static bool Read(openpal::RSlice&, Group51Var1&); + static bool Write(const Group51Var1&, openpal::WSlice&); + + DNPTime time; +}; + +// Time and Date CTO - Absolute time, unsynchronized +struct Group51Var2 +{ + static GroupVariationID ID() { return GroupVariationID(51,2); } + + Group51Var2(); + + static uint32_t Size() { return 6; } + static bool Read(openpal::RSlice&, Group51Var2&); + static bool Write(const Group51Var2&, openpal::WSlice&); + + DNPTime time; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.cpp new file mode 100644 index 0000000..2e9e90c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.cpp @@ -0,0 +1,61 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Group52.h" + +#include +#include + +using namespace openpal; + +namespace opendnp3 { + +// ------- Group52Var1 ------- + +Group52Var1::Group52Var1() : time(0) +{} + +bool Group52Var1::Read(RSlice& buffer, Group52Var1& output) +{ + return Parse::Many(buffer, output.time); +} + +bool Group52Var1::Write(const Group52Var1& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.time); +} + +// ------- Group52Var2 ------- + +Group52Var2::Group52Var2() : time(0) +{} + +bool Group52Var2::Read(RSlice& buffer, Group52Var2& output) +{ + return Parse::Many(buffer, output.time); +} + +bool Group52Var2::Write(const Group52Var2& arg, openpal::WSlice& buffer) +{ + return Format::Many(buffer, arg.time); +} + + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.h new file mode 100644 index 0000000..b051d05 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group52.h @@ -0,0 +1,62 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP52_H +#define OPENDNP3_GROUP52_H + +#include "opendnp3/app/GroupVariationID.h" +#include +#include +#include "opendnp3/app/DNPTime.h" + +namespace opendnp3 { + +// Time Delay - Coarse +struct Group52Var1 +{ + static GroupVariationID ID() { return GroupVariationID(52,1); } + + Group52Var1(); + + static uint32_t Size() { return 2; } + static bool Read(openpal::RSlice&, Group52Var1&); + static bool Write(const Group52Var1&, openpal::WSlice&); + + uint16_t time; +}; + +// Time Delay - Fine +struct Group52Var2 +{ + static GroupVariationID ID() { return GroupVariationID(52,2); } + + Group52Var2(); + + static uint32_t Size() { return 2; } + static bool Read(openpal::RSlice&, Group52Var2&); + static bool Write(const Group52Var2&, openpal::WSlice&); + + uint16_t time; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group60.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group60.h new file mode 100644 index 0000000..c2c31e5 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group60.h @@ -0,0 +1,55 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP60_H +#define OPENDNP3_GROUP60_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// Class Data - Class 0 +struct Group60Var1 +{ + static GroupVariationID ID() { return GroupVariationID(60,1); } +}; + +// Class Data - Class 1 +struct Group60Var2 +{ + static GroupVariationID ID() { return GroupVariationID(60,2); } +}; + +// Class Data - Class 2 +struct Group60Var3 +{ + static GroupVariationID ID() { return GroupVariationID(60,3); } +}; + +// Class Data - Class 3 +struct Group60Var4 +{ + static GroupVariationID ID() { return GroupVariationID(60,4); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group70.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group70.h new file mode 100644 index 0000000..0e549bb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group70.h @@ -0,0 +1,79 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP70_H +#define OPENDNP3_GROUP70_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// File-control - File identifier +struct Group70Var1 +{ + static GroupVariationID ID() { return GroupVariationID(70,1); } +}; + +// File-control - Authentication +struct Group70Var2 +{ + static GroupVariationID ID() { return GroupVariationID(70,2); } +}; + +// File-control - File command +struct Group70Var3 +{ + static GroupVariationID ID() { return GroupVariationID(70,3); } +}; + +// File-control - File command status +struct Group70Var4 +{ + static GroupVariationID ID() { return GroupVariationID(70,4); } +}; + +// File-control - File transport +struct Group70Var5 +{ + static GroupVariationID ID() { return GroupVariationID(70,5); } +}; + +// File-control - File transport status +struct Group70Var6 +{ + static GroupVariationID ID() { return GroupVariationID(70,6); } +}; + +// File-control - File descriptor +struct Group70Var7 +{ + static GroupVariationID ID() { return GroupVariationID(70,7); } +}; + +// File-control - File specification string +struct Group70Var8 +{ + static GroupVariationID ID() { return GroupVariationID(70,8); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group80.h b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group80.h new file mode 100644 index 0000000..1888217 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/objects/Group80.h @@ -0,0 +1,37 @@ +// +// _ _ ______ _ _ _ _ _ _ _ +// | \ | | | ____| | (_) | (_) | | | | +// | \| | ___ | |__ __| |_| |_ _ _ __ __ _| | | | +// | . ` |/ _ \ | __| / _` | | __| | '_ \ / _` | | | | +// | |\ | (_) | | |___| (_| | | |_| | | | | (_| |_|_|_| +// |_| \_|\___/ |______\__,_|_|\__|_|_| |_|\__, (_|_|_) +// __/ | +// |___/ +// +// This file is auto-generated. Do not edit manually +// +// Copyright 2013 Automatak LLC +// +// Automatak LLC (www.automatak.com) licenses this file +// to you under the the Apache License Version 2.0 (the "License"): +// +// http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef OPENDNP3_GROUP80_H +#define OPENDNP3_GROUP80_H + +#include "opendnp3/app/GroupVariationID.h" + +namespace opendnp3 { + +// Internal Indications - Packed Format +struct Group80Var1 +{ + static GroupVariationID ID() { return GroupVariationID(80,1); } +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ApplicationIIN.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ApplicationIIN.cpp new file mode 100644 index 0000000..3547dc0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ApplicationIIN.cpp @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/outstation/ApplicationIIN.h" + +namespace opendnp3 +{ + +ApplicationIIN::ApplicationIIN() : needTime(false), localControl(false), deviceTrouble(false), configCorrupt(false) +{} + +IINField ApplicationIIN::ToIIN() const +{ + IINField ret; + ret.SetBitToValue(IINBit::NEED_TIME, needTime); + ret.SetBitToValue(IINBit::LOCAL_CONTROL, localControl); + ret.SetBitToValue(IINBit::CONFIG_CORRUPT, configCorrupt); + ret.SetBitToValue(IINBit::DEVICE_TROUBLE, deviceTrouble); + return ret; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.cpp new file mode 100644 index 0000000..0742a48 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.cpp @@ -0,0 +1,177 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "AssignClassHandler.h" + +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/outstation/IOutstationApplication.h" + +#include + +namespace opendnp3 +{ + +AssignClassHandler::AssignClassHandler(openpal::IExecutor& executor, IOutstationApplication& application, IClassAssigner& assigner) : + classHeader(-1), + clazz(PointClass::Class0), + pExecutor(&executor), + pApplication(&application), + pAssigner(&assigner) +{ + +} + +IINField AssignClassHandler::ProcessHeader(const AllObjectsHeader& header) +{ + if (IsExpectingAssignment()) + { + switch (header.enumeration) + { + case(GroupVariation::Group1Var0) : + return this->ProcessAssignAll(AssignClassType::BinaryInput, clazz); + case(GroupVariation::Group3Var0) : + return this->ProcessAssignAll(AssignClassType::DoubleBinaryInput, clazz); + case(GroupVariation::Group10Var0) : + return this->ProcessAssignAll(AssignClassType::BinaryOutputStatus, clazz); + case(GroupVariation::Group20Var0) : + return this->ProcessAssignAll(AssignClassType::Counter, clazz); + case(GroupVariation::Group21Var0) : + return this->ProcessAssignAll(AssignClassType::FrozenCounter, clazz); + case(GroupVariation::Group30Var0) : + return this->ProcessAssignAll(AssignClassType::AnalogInput, clazz); + case(GroupVariation::Group40Var0) : + return this->ProcessAssignAll(AssignClassType::AnalogOutputStatus, clazz); + default: + return IINBit::FUNC_NOT_SUPPORTED; + } + } + else + { + return this->RecordClass(header.enumeration); + } +} + + + +IINField AssignClassHandler::ProcessHeader(const RangeHeader& header) +{ + if (IsExpectingAssignment()) + { + switch (header.enumeration) + { + + case(GroupVariation::Group1Var0) : + return ProcessAssignRange(AssignClassType::BinaryInput, clazz, header.range); + case(GroupVariation::Group3Var0) : + return ProcessAssignRange(AssignClassType::DoubleBinaryInput, clazz, header.range); + case(GroupVariation::Group10Var0) : + return ProcessAssignRange(AssignClassType::BinaryOutputStatus, clazz, header.range); + case(GroupVariation::Group20Var0) : + return ProcessAssignRange(AssignClassType::Counter, clazz, header.range); + case(GroupVariation::Group21Var0) : + return ProcessAssignRange(AssignClassType::FrozenCounter, clazz, header.range); + case(GroupVariation::Group30Var0) : + return ProcessAssignRange(AssignClassType::AnalogInput, clazz, header.range); + case(GroupVariation::Group40Var0) : + return ProcessAssignRange(AssignClassType::AnalogOutputStatus, clazz, header.range); + default: + return IINBit::FUNC_NOT_SUPPORTED; + } + } + else + { + return IINBit::PARAM_ERROR; + } +} + +bool AssignClassHandler::IsExpectingAssignment() +{ + int32_t current = static_cast(this->GetCurrentHeader()); + + if (current > 0 && ((current - 1) == this->classHeader)) + { + this->classHeader = -1; + return true; + } + else + { + return false; + } +} + +IINField AssignClassHandler::ProcessAssignRange(AssignClassType type, PointClass clazz, const Range& range) +{ + auto actual = pAssigner->AssignClassToRange(type, clazz, range); + + this->NotifyApplicationOfAssignment(type, clazz, actual); + + // if the range was clipped or invalid return parameter error + return actual.Equals(range) ? IINField() : IINBit::PARAM_ERROR; +} + +IINField AssignClassHandler::ProcessAssignAll(AssignClassType type, PointClass clazz) +{ + auto full = pAssigner->AssignClassToAll(type, clazz); + + this->NotifyApplicationOfAssignment(type, clazz, full); + + return full.IsValid() ? IINField() : IINBit::PARAM_ERROR; +} + +void AssignClassHandler::NotifyApplicationOfAssignment(AssignClassType type, PointClass clazz, const Range& range) +{ + if (range.IsValid() && pApplication) + { + auto pApplication = this->pApplication; + auto callback = [pApplication, range, clazz, type]() + { + pApplication->RecordClassAssignment(type, clazz, range.start, range.stop); + }; + + pExecutor->Post(callback); + } +} + +IINField AssignClassHandler::RecordClass(GroupVariation gv) +{ + classHeader = this->GetCurrentHeader(); + + switch (gv) + { + case(GroupVariation::Group60Var1) : + clazz = PointClass::Class0; + return IINField(); + case(GroupVariation::Group60Var2) : + clazz = PointClass::Class1; + return IINField(); + case(GroupVariation::Group60Var3) : + clazz = PointClass::Class2; + return IINField(); + case(GroupVariation::Group60Var4) : + clazz = PointClass::Class3; + return IINField(); + default: + classHeader = -1; + return IINBit::PARAM_ERROR; + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.h new file mode 100644 index 0000000..41657a6 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/AssignClassHandler.h @@ -0,0 +1,75 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ASSIGNCLASSHANDLER_H +#define OPENDNP3_ASSIGNCLASSHANDLER_H + +#include "opendnp3/app/parsing/IAPDUHandler.h" + +#include "opendnp3/gen/AssignClassType.h" + +#include "opendnp3/outstation/IClassAssigner.h" +#include "opendnp3/outstation/IOutstationApplication.h" + +#include +#include + +namespace opendnp3 +{ + +class AssignClassHandler : public IAPDUHandler +{ +public: + + AssignClassHandler(openpal::IExecutor& executor, IOutstationApplication& application, IClassAssigner& assigner); + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final + { + return true; + } + +private: + + virtual IINField ProcessHeader(const AllObjectsHeader& header) override final; + + virtual IINField ProcessHeader(const RangeHeader& header) override final; + + IINField RecordClass(GroupVariation gv); + + bool IsExpectingAssignment(); + + IINField ProcessAssignAll(AssignClassType type, PointClass clazz); + + IINField ProcessAssignRange(AssignClassType type, PointClass clazz, const Range& range); + + void NotifyApplicationOfAssignment(AssignClassType type, PointClass clazz, const Range& range); + + int32_t classHeader; + PointClass clazz; + + openpal::IExecutor* pExecutor; + IOutstationApplication* pApplication; + IClassAssigner* pAssigner; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.cpp new file mode 100644 index 0000000..62b381a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ClassBasedRequestHandler.h" + +namespace opendnp3 +{ + +IINField ClassBasedRequestHandler::ProcessHeader(const AllObjectsHeader& header) +{ + switch (header.enumeration) + { + case(GroupVariation::Group60Var2) : + classField.Set(PointClass::Class1); + return IINField::Empty(); + case(GroupVariation::Group60Var3) : + classField.Set(PointClass::Class2); + return IINField::Empty(); + case(GroupVariation::Group60Var4) : + classField.Set(PointClass::Class3); + return IINField::Empty(); + default: + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.h new file mode 100644 index 0000000..886284d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ClassBasedRequestHandler.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CLASSBASEDREQUESTHANDLER_H +#define OPENDNP3_CLASSBASEDREQUESTHANDLER_H + +#include "opendnp3/app/parsing/IAPDUHandler.h" + +#include "opendnp3/app/IINField.h" +#include "opendnp3/app/ClassField.h" + +#include + +namespace opendnp3 +{ + +class ClassBasedRequestHandler : public IAPDUHandler +{ +public: + + ClassBasedRequestHandler() {} + + ClassField GetClassField() const + { + return classField; + } + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final + { + return true; + } + +private: + + virtual IINField ProcessHeader(const AllObjectsHeader& header) override final; + + ClassField classField; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.cpp new file mode 100644 index 0000000..1ed5bf4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.cpp @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CommandActionAdapter.h" + +#include "opendnp3/app/ITransactable.h" + +namespace opendnp3 +{ + +CommandActionAdapter::CommandActionAdapter(ICommandHandler* handler, bool isSelect, OperateType opType) : + m_handler(handler), + m_isSelect(isSelect), + m_opType(opType), + m_isStarted(false) +{} + +CommandActionAdapter::~CommandActionAdapter() +{ + if (m_isStarted) + { + Transaction::End(m_handler); + } +} + +void CommandActionAdapter::CheckStart() +{ + if (!m_isStarted) + { + m_isStarted = true; + Transaction::Start(m_handler); + } +} + +CommandStatus CommandActionAdapter::Action(const ControlRelayOutputBlock& command, uint16_t index) +{ + return this->ActionT(command, index); +} + +CommandStatus CommandActionAdapter::Action(const AnalogOutputInt16& command, uint16_t index) +{ + return this->ActionT(command, index); +} + +CommandStatus CommandActionAdapter::Action(const AnalogOutputInt32& command, uint16_t index) +{ + return this->ActionT(command, index); +} + +CommandStatus CommandActionAdapter::Action(const AnalogOutputFloat32& command, uint16_t index) +{ + return this->ActionT(command, index); +} + +CommandStatus CommandActionAdapter::Action(const AnalogOutputDouble64& command, uint16_t index) +{ + return this->ActionT(command, index); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.h new file mode 100644 index 0000000..ba24c8e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandActionAdapter.h @@ -0,0 +1,74 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COMMANDACTIONADAPTER_H +#define OPENDNP3_COMMANDACTIONADAPTER_H + +#include "ICommandAction.h" + +#include "opendnp3/outstation/ICommandHandler.h" + +namespace opendnp3 +{ + +/** +* Interface used to dispatch an abstract action using a command +*/ +class CommandActionAdapter : public ICommandAction +{ + +public: + + CommandActionAdapter(ICommandHandler* handler, bool isSelect, OperateType opType); + + ~CommandActionAdapter(); + + virtual CommandStatus Action(const ControlRelayOutputBlock& command, uint16_t index) final; + + virtual CommandStatus Action(const AnalogOutputInt16& command, uint16_t index) final; + + virtual CommandStatus Action(const AnalogOutputInt32& command, uint16_t index) final; + + virtual CommandStatus Action(const AnalogOutputFloat32& command, uint16_t index) final; + + virtual CommandStatus Action(const AnalogOutputDouble64& command, uint16_t index) final; + +private: + + template + CommandStatus ActionT(const T& command, uint16_t index) + { + this->CheckStart(); + return m_isSelect ? m_handler->Select(command, index) : m_handler->Operate(command, index, m_opType); + } + + void CheckStart(); + + ICommandHandler* m_handler; + bool m_isSelect; + OperateType m_opType; + bool m_isStarted; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.cpp new file mode 100644 index 0000000..1dd230e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.cpp @@ -0,0 +1,136 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CommandResponseHandler.h" + +#include + +#include "opendnp3/objects/Group12.h" +#include "opendnp3/objects/Group41.h" + +namespace opendnp3 +{ + +CommandResponseHandler::CommandResponseHandler(uint8_t maxCommands_, ICommandAction* pCommandAction_, HeaderWriter* pWriter_) : + pCommandAction(pCommandAction_), + numRequests(0), + numSuccess(0), + maxCommands(maxCommands_), + pWriter(pWriter_) +{ + +} + +bool CommandResponseHandler::IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) +{ + if (!(qc == QualifierCode::UINT8_CNT_UINT8_INDEX || qc == QualifierCode::UINT16_CNT_UINT16_INDEX)) + { + return false; + } + + switch (gv) + { + case(GroupVariation::Group12Var1) : // CROB + case(GroupVariation::Group41Var1) : // 4 kinds of AO + case(GroupVariation::Group41Var2) : + case(GroupVariation::Group41Var3) : + case(GroupVariation::Group41Var4) : + return true; + default: + return false; + } +} + +IINField CommandResponseHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& meas) +{ + return this->ProcessAny(header, meas); +} + +IINField CommandResponseHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& meas) +{ + return this->ProcessAny(header, meas); +} + +IINField CommandResponseHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& meas) +{ + return this->ProcessAny(header, meas); +} + +IINField CommandResponseHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& meas) +{ + return this->ProcessAny(header, meas); +} + +IINField CommandResponseHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& meas) +{ + return this->ProcessAny(header, meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixTwoByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT16_CNT_UINT16_INDEX, Group12Var1::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixTwoByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT16_CNT_UINT16_INDEX, Group41Var2::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixTwoByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT16_CNT_UINT16_INDEX, Group41Var1::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixTwoByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT16_CNT_UINT16_INDEX, Group41Var3::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixTwoByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT16_CNT_UINT16_INDEX, Group41Var4::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixOneByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT8_CNT_UINT8_INDEX, Group12Var1::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixOneByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT8_CNT_UINT8_INDEX, Group41Var2::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixOneByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT8_CNT_UINT8_INDEX, Group41Var1::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixOneByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT8_CNT_UINT8_INDEX, Group41Var3::Inst(), meas); +} + +IINField CommandResponseHandler::ProcessIndexPrefixOneByte(const HeaderRecord&, const ICollection>& meas) +{ + return this->RespondToHeader(QualifierCode::UINT8_CNT_UINT8_INDEX, Group41Var4::Inst(), meas); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.h new file mode 100644 index 0000000..a9b4e11 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/CommandResponseHandler.h @@ -0,0 +1,163 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_COMMANDRESPONSEHANDLER_H +#define OPENDNP3_COMMANDRESPONSEHANDLER_H + +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/APDUResponse.h" +#include "opendnp3/outstation/ICommandAction.h" + +#include + +namespace opendnp3 +{ + +class CommandResponseHandler : public IAPDUHandler +{ +public: + + CommandResponseHandler(uint8_t maxCommands_, ICommandAction* pCommandAction_, HeaderWriter* pWriter_); + + bool AllCommandsSuccessful() const + { + return numRequests == numSuccess; + } + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final; + +private: + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final; + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final; + + IINField ProcessIndexPrefixTwoByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixTwoByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixTwoByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixTwoByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixTwoByte(const HeaderRecord& record, const ICollection>& meas); + + IINField ProcessIndexPrefixOneByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixOneByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixOneByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixOneByte(const HeaderRecord& record, const ICollection>& meas); + IINField ProcessIndexPrefixOneByte(const HeaderRecord& record, const ICollection>& meas); + + ICommandAction* pCommandAction; + uint32_t numRequests; + uint32_t numSuccess; + const uint8_t maxCommands; + HeaderWriter* pWriter; + + template + IINField ProcessAny(const HeaderRecord& record, const ICollection>& meas); + + template + IINField RespondToHeader(QualifierCode qualifier, const DNP3Serializer& serializer, const ICollection>& values); + + template + IINField RespondToHeaderWithIterator(QualifierCode qualifier, const DNP3Serializer& serializer, const ICollection>& values, PrefixedWriteIterator* pIterator = nullptr); + + template + CommandStatus ProcessCommand(const Target& command, uint16_t index); +}; + +template +IINField CommandResponseHandler::ProcessAny(const HeaderRecord& record, const ICollection>& meas) +{ + if (record.GetQualifierCode() == QualifierCode::UINT8_CNT_UINT8_INDEX) + { + return ProcessIndexPrefixOneByte(record, meas); + } + else + { + return ProcessIndexPrefixTwoByte(record, meas); + } +} + + +template +IINField CommandResponseHandler::RespondToHeaderWithIterator(QualifierCode qualifier, const DNP3Serializer& serializer, const ICollection>& values, PrefixedWriteIterator* pIterator) +{ + IINField ret; + + auto process = [this, pIterator, &ret](const Indexed& pair) + { + Target response(pair.value); + response.status = this->ProcessCommand(pair.value, pair.index); + + switch (response.status) + { + case(CommandStatus::SUCCESS) : + ++this->numSuccess; + break; + case(CommandStatus::NOT_SUPPORTED) : + ret.SetBit(IINBit::PARAM_ERROR); + break; + default: + break; + } + + if (pIterator) + { + pIterator->Write(response, static_cast(pair.index)); + } + }; + + values.ForeachItem(process); + + return ret; +} + +template +CommandStatus CommandResponseHandler::ProcessCommand(const Target& command, uint16_t index) +{ + if (numRequests < maxCommands) + { + ++numRequests; + return pCommandAction->Action(command, index); + } + else + { + return CommandStatus::TOO_MANY_OPS; + } +} + +template +IINField CommandResponseHandler::RespondToHeader(QualifierCode qualifier, const DNP3Serializer& serializer, const ICollection>& values) +{ + if (pWriter) + { + auto iter = pWriter->IterateOverCountWithPrefix(qualifier, serializer); + return this->RespondToHeaderWithIterator(qualifier, serializer, values, &iter); + } + else + { + return this->RespondToHeaderWithIterator(qualifier, serializer, values); + } +} + +} + + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ConstantCommandAction.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ConstantCommandAction.h new file mode 100644 index 0000000..759073f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ConstantCommandAction.h @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CONSTANTCOMMANDACTION_H +#define OPENDNP3_CONSTANTCOMMANDACTION_H + +#include "ICommandAction.h" + +namespace opendnp3 +{ + +/** +* Interface used to dispatch an abstract action using a command +*/ +class ConstantCommandAction : public ICommandAction +{ + +public: + + ConstantCommandAction(CommandStatus status_) : status(status_) + {} + + virtual CommandStatus Action(const ControlRelayOutputBlock& command, uint16_t aIndex) final { return status; } + + virtual CommandStatus Action(const AnalogOutputInt16& command, uint16_t aIndex) final { return status; } + + virtual CommandStatus Action(const AnalogOutputInt32& command, uint16_t aIndex) final { return status; } + + virtual CommandStatus Action(const AnalogOutputFloat32& command, uint16_t aIndex) final { return status; } + + virtual CommandStatus Action(const AnalogOutputDouble64& command, uint16_t aIndex) final { return status; } + +private: + + CommandStatus status; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ControlState.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ControlState.h new file mode 100644 index 0000000..0dda21e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ControlState.h @@ -0,0 +1,100 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_CONTROLSTATE_H +#define OPENDNP3_CONTROLSTATE_H + + +#include + +#include "opendnp3/gen/CommandStatus.h" +#include "opendnp3/link/CRC.h" +#include "opendnp3/app/AppSeqNum.h" + + +namespace opendnp3 +{ + +/// +/// Represent all of the mutable state for SBO controls +/// +class ControlState +{ + +public: + + ControlState() : digest(0), length(0) + {} + + CommandStatus ValidateSelection(const AppSeqNum& seq, const openpal::MonotonicTimestamp& now, const openpal::TimeDuration& timeout, const openpal::RSlice& objects) const + { + if (expectedSeq.Equals(seq)) + { + if (selectTime.milliseconds <= now.milliseconds) + { + auto elapsed = now.milliseconds - selectTime.milliseconds; + if (elapsed < timeout) + { + if (length == objects.Size() && digest == CRC::CalcCrc(objects)) + { + return CommandStatus::SUCCESS; + } + else + { + return CommandStatus::NO_SELECT; + } + } + else + { + return CommandStatus::TIMEOUT; + } + } + else + { + return CommandStatus::TIMEOUT; + } + } + else + { + return CommandStatus::NO_SELECT; + } + } + + void Select(const AppSeqNum& currentSeqN, const openpal::MonotonicTimestamp& now, const openpal::RSlice& objects) + { + selectTime = now; + expectedSeq = currentSeqN.Next(); + digest = CRC::CalcCrc(objects); + length = objects.Size(); + } + +private: + + AppSeqNum expectedSeq; + openpal::MonotonicTimestamp selectTime; + uint16_t digest; + uint32_t length; + +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.cpp new file mode 100644 index 0000000..eac07bc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.cpp @@ -0,0 +1,221 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "Database.h" + +#include + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +Database::Database(const DatabaseSizes& dbSizes, IEventReceiver& eventReceiver, IndexMode indexMode, StaticTypeBitField allowedClass0Types) : + eventReceiver(&eventReceiver), + indexMode(indexMode), + buffers(dbSizes, allowedClass0Types, indexMode) +{ + +} + +bool Database::Update(const Binary& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const DoubleBitBinary& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const Analog& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const Counter& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const FrozenCounter& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const BinaryOutputStatus& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const AnalogOutputStatus& value, uint16_t index, EventMode mode) +{ + return this->UpdateEvent(value, index, mode); +} + +bool Database::Update(const TimeAndInterval& value, uint16_t index) +{ + auto rawIndex = GetRawIndex(index); + auto view = buffers.buffers.GetArrayView(); + + if (view.Contains(rawIndex)) + { + view[rawIndex].value = value; + return true; + } + else + { + return false; + } +} + +bool Database::Modify(FlagsType type, uint16_t start, uint16_t stop, uint8_t flags) +{ + switch (type) + { + case(FlagsType::BinaryInput): + return Modify(start, stop, flags); + case(FlagsType::DoubleBinaryInput): + return Modify(start, stop, flags); + case(FlagsType::AnalogInput): + return Modify(start, stop, flags); + case(FlagsType::Counter): + return Modify(start, stop, flags); + case(FlagsType::FrozenCounter): + return Modify(start, stop, flags); + case(FlagsType::BinaryOutputStatus): + return Modify(start, stop, flags); + case(FlagsType::AnalogOutputStatus): + return Modify(start, stop, flags); + } + + return false; +} + +bool Database::ConvertToEventClass(PointClass pc, EventClass& ec) +{ + switch (pc) + { + case(PointClass::Class1) : + ec = EventClass::EC1; + return true; + case(PointClass::Class2) : + ec = EventClass::EC2; + return true; + case(PointClass::Class3) : + ec = EventClass::EC3; + return true; + default: + return false; + } +} + +template +uint16_t Database::GetRawIndex(uint16_t index) +{ + if (indexMode == IndexMode::Contiguous) + { + return index; + } + else + { + auto view = buffers.buffers.GetArrayView(); + auto result = IndexSearch::FindClosestRawIndex(view, index); + return result.match ? result.index : openpal::MaxValue(); + } +} + +template +bool Database::UpdateEvent(const typename Spec::meas_t& value, uint16_t index, EventMode mode) +{ + auto rawIndex = GetRawIndex(index); + auto view = buffers.buffers.GetArrayView(); + + if (view.Contains(rawIndex)) + { + this->UpdateAny(view[rawIndex], value, mode); + return true; + } + else + { + return false; + } +} + +template +bool Database::UpdateAny(Cell& cell, const typename Spec::meas_t& value, EventMode mode) +{ + EventClass ec; + if (ConvertToEventClass(cell.config.clazz, ec)) + { + bool createEvent = false; + + switch (mode) + { + case(EventMode::Force): + createEvent = true; + break; + case(EventMode::Detect): + createEvent = cell.event.IsEvent(cell.config, value); + break; + default: + break; + } + + if (createEvent) + { + cell.event.lastEvent = value; + eventReceiver->Update(Event(value, cell.config.vIndex, ec, cell.config.evariation)); + } + } + + cell.value = value; + return true; +} + +template +bool Database::Modify(uint16_t start, uint16_t stop, uint8_t flags) +{ + auto rawStart = GetRawIndex(start); + auto rawStop = GetRawIndex(stop); + + auto view = buffers.buffers.GetArrayView(); + + if (view.Contains(rawStart) && view.Contains(rawStop) && (rawStart <= rawStop)) + { + for (uint16_t i = rawStart; i <= rawStop; ++i) + { + auto copy = view[i].value; + copy.flags = flags; + this->UpdateAny(view[i], copy, EventMode::Detect); + } + + return true; + } + else + { + return false; + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.h new file mode 100644 index 0000000..89d9639 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Database.h @@ -0,0 +1,106 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DATABASE_H +#define OPENDNP3_DATABASE_H + +#include "opendnp3/gen/IndexMode.h" +#include "opendnp3/gen/AssignClassType.h" + +#include "opendnp3/outstation/IDatabase.h" +#include "opendnp3/outstation/IEventReceiver.h" +#include "opendnp3/outstation/DatabaseBuffers.h" + +namespace opendnp3 +{ + +/** +The database coordinates all updates of measurement data +*/ +class Database final : public IDatabase, private openpal::Uncopyable +{ +public: + + Database(const DatabaseSizes&, IEventReceiver& eventReceiver, IndexMode indexMode, StaticTypeBitField allowedClass0Types); + + // ------- IDatabase -------------- + + virtual bool Update(const Binary&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const DoubleBitBinary&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const Analog&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const Counter&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const FrozenCounter&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const BinaryOutputStatus&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const AnalogOutputStatus&, uint16_t, EventMode = EventMode::Detect) override; + virtual bool Update(const TimeAndInterval&, uint16_t) override; + virtual bool Modify(FlagsType type, uint16_t start, uint16_t stop, uint8_t flags) override; + + // ------- Misc --------------- + + IResponseLoader& GetResponseLoader() override final + { + return buffers; + } + IStaticSelector& GetStaticSelector() override final + { + return buffers; + } + IClassAssigner& GetClassAssigner() override final + { + return buffers; + } + + /** + * @return A view of all the static data for configuration purposes + */ + DatabaseConfigView GetConfigView() + { + return buffers.buffers.GetView(); + } + +private: + + template + uint16_t GetRawIndex(uint16_t index); + + IEventReceiver* eventReceiver; + IndexMode indexMode; + + static bool ConvertToEventClass(PointClass pc, EventClass& ec); + + template + bool UpdateEvent(const typename Spec::meas_t& value, uint16_t index, EventMode mode); + + template + bool UpdateAny(Cell& cell, const typename Spec::meas_t& value, EventMode mode); + + template + bool Modify(uint16_t start, uint16_t stop, uint8_t flags); + + // stores the most recent values, selected values, and metadata + DatabaseBuffers buffers; +}; + + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.cpp new file mode 100644 index 0000000..6f1484c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.cpp @@ -0,0 +1,326 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "DatabaseBuffers.h" + +#include "openpal/logging/LogMacros.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +DatabaseBuffers::DatabaseBuffers(const DatabaseSizes& dbSizes, StaticTypeBitField allowedClass0Types, IndexMode indexMode) : + buffers(dbSizes), + class0(allowedClass0Types), + indexMode(indexMode) +{ + +} + +void DatabaseBuffers::Unselect() +{ + this->Deselect(); + this->Deselect(); + this->Deselect(); + this->Deselect(); + this->Deselect(); + this->Deselect(); + this->Deselect(); + this->Deselect(); +} + +IINField DatabaseBuffers::SelectAll(GroupVariation gv) +{ + if (gv == GroupVariation::Group60Var1) + { + this->SelectAllClass0(); + this->SelectAllClass0(); + this->SelectAllClass0(); + this->SelectAllClass0(); + this->SelectAllClass0(); + this->SelectAllClass0(); + this->SelectAllClass0(); + this->SelectAllClass0(); + + return IINField::Empty(); + } + else + { + switch (gv) + { + case(GroupVariation::Group1Var0): + return this->SelectAll(); + case(GroupVariation::Group1Var1) : + return this->SelectAllUsing(StaticBinaryVariation::Group1Var1); + case(GroupVariation::Group1Var2) : + return this->SelectAllUsing(StaticBinaryVariation::Group1Var2); + + case(GroupVariation::Group3Var0) : + return this->SelectAll(); + case(GroupVariation::Group3Var2) : + return this->SelectAllUsing(StaticDoubleBinaryVariation::Group3Var2); + + case(GroupVariation::Group10Var0) : + return this->SelectAll(); + case(GroupVariation::Group10Var2) : + return this->SelectAllUsing(StaticBinaryOutputStatusVariation::Group10Var2); + + case(GroupVariation::Group20Var0): + return this->SelectAll(); + case(GroupVariation::Group20Var1): + return this->SelectAllUsing(StaticCounterVariation::Group20Var1); + case(GroupVariation::Group20Var2) : + return this->SelectAllUsing(StaticCounterVariation::Group20Var2); + case(GroupVariation::Group20Var5) : + return this->SelectAllUsing(StaticCounterVariation::Group20Var5); + case(GroupVariation::Group20Var6) : + return this->SelectAllUsing(StaticCounterVariation::Group20Var6); + + case(GroupVariation::Group21Var0) : + return this->SelectAll(); + case(GroupVariation::Group21Var1) : + return this->SelectAllUsing(StaticFrozenCounterVariation::Group21Var1); + case(GroupVariation::Group21Var2) : + return this->SelectAllUsing(StaticFrozenCounterVariation::Group21Var2); + case(GroupVariation::Group21Var5) : + return this->SelectAllUsing(StaticFrozenCounterVariation::Group21Var5); + case(GroupVariation::Group21Var6) : + return this->SelectAllUsing(StaticFrozenCounterVariation::Group21Var6); + case(GroupVariation::Group21Var9) : + return this->SelectAllUsing(StaticFrozenCounterVariation::Group21Var9); + case(GroupVariation::Group21Var10) : + return this->SelectAllUsing(StaticFrozenCounterVariation::Group21Var10); + + case(GroupVariation::Group30Var0) : + return this->SelectAll(); + case(GroupVariation::Group30Var1) : + return this->SelectAllUsing(StaticAnalogVariation::Group30Var1); + case(GroupVariation::Group30Var2) : + return this->SelectAllUsing(StaticAnalogVariation::Group30Var2); + case(GroupVariation::Group30Var3) : + return this->SelectAllUsing(StaticAnalogVariation::Group30Var3); + case(GroupVariation::Group30Var4) : + return this->SelectAllUsing(StaticAnalogVariation::Group30Var4); + case(GroupVariation::Group30Var5) : + return this->SelectAllUsing(StaticAnalogVariation::Group30Var5); + case(GroupVariation::Group30Var6) : + return this->SelectAllUsing(StaticAnalogVariation::Group30Var6); + + case(GroupVariation::Group40Var0) : + return this->SelectAll(); + case(GroupVariation::Group40Var1) : + return this->SelectAllUsing(StaticAnalogOutputStatusVariation::Group40Var1); + case(GroupVariation::Group40Var2) : + return this->SelectAllUsing(StaticAnalogOutputStatusVariation::Group40Var2); + case(GroupVariation::Group40Var3) : + return this->SelectAllUsing(StaticAnalogOutputStatusVariation::Group40Var3); + case(GroupVariation::Group40Var4) : + return this->SelectAllUsing(StaticAnalogOutputStatusVariation::Group40Var4); + + case(GroupVariation::Group50Var4) : + return this->SelectAllUsing(StaticTimeAndIntervalVariation::Group50Var4); + + default: + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } + } +} + +IINField DatabaseBuffers::SelectRange(GroupVariation gv, const Range& range) +{ + switch (gv) + { + case(GroupVariation::Group1Var0) : + return this->SelectRange(range); + case(GroupVariation::Group1Var1) : + return this->SelectRangeUsing(range, StaticBinaryVariation::Group1Var1); + case(GroupVariation::Group1Var2) : + return this->SelectRangeUsing(range, StaticBinaryVariation::Group1Var2); + + case(GroupVariation::Group3Var0) : + return this->SelectRange(range); + case(GroupVariation::Group3Var2) : + return this->SelectRangeUsing(range, StaticDoubleBinaryVariation::Group3Var2); + + case(GroupVariation::Group10Var0) : + return this->SelectRange(range); + case(GroupVariation::Group10Var2) : + return this->SelectRangeUsing(range, StaticBinaryOutputStatusVariation::Group10Var2); + + case(GroupVariation::Group20Var0) : + return this->SelectRange(range); + case(GroupVariation::Group20Var1) : + return this->SelectRangeUsing(range, StaticCounterVariation::Group20Var1); + case(GroupVariation::Group20Var2) : + return this->SelectRangeUsing(range, StaticCounterVariation::Group20Var2); + case(GroupVariation::Group20Var5) : + return this->SelectRangeUsing(range, StaticCounterVariation::Group20Var5); + case(GroupVariation::Group20Var6) : + return this->SelectRangeUsing(range, StaticCounterVariation::Group20Var6); + + case(GroupVariation::Group21Var0) : + return this->SelectRange(range); + case(GroupVariation::Group21Var1) : + return this->SelectRangeUsing(range, StaticFrozenCounterVariation::Group21Var1); + case(GroupVariation::Group21Var2) : + return this->SelectRangeUsing(range, StaticFrozenCounterVariation::Group21Var2); + case(GroupVariation::Group21Var5) : + return this->SelectRangeUsing(range, StaticFrozenCounterVariation::Group21Var5); + case(GroupVariation::Group21Var6) : + return this->SelectRangeUsing(range, StaticFrozenCounterVariation::Group21Var6); + case(GroupVariation::Group21Var9) : + return this->SelectRangeUsing(range, StaticFrozenCounterVariation::Group21Var9); + case(GroupVariation::Group21Var10) : + return this->SelectRangeUsing(range, StaticFrozenCounterVariation::Group21Var10); + + case(GroupVariation::Group30Var0) : + return this->SelectRange(range); + case(GroupVariation::Group30Var1) : + return this->SelectRangeUsing(range, StaticAnalogVariation::Group30Var1); + case(GroupVariation::Group30Var2) : + return this->SelectRangeUsing(range, StaticAnalogVariation::Group30Var2); + case(GroupVariation::Group30Var3) : + return this->SelectRangeUsing(range, StaticAnalogVariation::Group30Var3); + case(GroupVariation::Group30Var4) : + return this->SelectRangeUsing(range, StaticAnalogVariation::Group30Var4); + case(GroupVariation::Group30Var5) : + return this->SelectRangeUsing(range, StaticAnalogVariation::Group30Var5); + case(GroupVariation::Group30Var6) : + return this->SelectRangeUsing(range, StaticAnalogVariation::Group30Var6); + + case(GroupVariation::Group40Var0) : + return this->SelectRange(range); + case(GroupVariation::Group40Var1) : + return this->SelectRangeUsing(range, StaticAnalogOutputStatusVariation::Group40Var1); + case(GroupVariation::Group40Var2) : + return this->SelectRangeUsing(range, StaticAnalogOutputStatusVariation::Group40Var2); + case(GroupVariation::Group40Var3) : + return this->SelectRangeUsing(range, StaticAnalogOutputStatusVariation::Group40Var3); + case(GroupVariation::Group40Var4) : + return this->SelectRangeUsing(range, StaticAnalogOutputStatusVariation::Group40Var4); + + case(GroupVariation::Group50Var4) : + return this->SelectRangeUsing(range, StaticTimeAndIntervalVariation::Group50Var4); + + default: + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } +} + +bool DatabaseBuffers::Load(HeaderWriter& writer) +{ + typedef bool (DatabaseBuffers::*LoadFun)(HeaderWriter & writer); + + const int NUM_TYPE = 8; + + LoadFun functions[NUM_TYPE] = + { + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType, + &DatabaseBuffers::LoadType + }; + + for (int i = 0; i < NUM_TYPE; ++i) + { + if (!(this->*functions[i])(writer)) + { + // return early because the APDU is full + return false; + } + } + + return true; +} + +Range DatabaseBuffers::AssignClassToAll(AssignClassType type, PointClass clazz) +{ + switch (type) + { + case(AssignClassType::BinaryInput) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + case(AssignClassType::DoubleBinaryInput) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + case(AssignClassType::Counter) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + case(AssignClassType::FrozenCounter) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + case(AssignClassType::AnalogInput) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + case(AssignClassType::BinaryOutputStatus) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + case(AssignClassType::AnalogOutputStatus) : + return AssignClassToRange(type, clazz, RangeOf(buffers.GetArrayView().Size())); + default: + return Range::Invalid(); + } +} + +Range DatabaseBuffers::AssignClassToRange(AssignClassType type, PointClass clazz, const Range& range) +{ + switch (type) + { + case(AssignClassType::BinaryInput) : + return AssignClassTo(clazz, range); + case(AssignClassType::DoubleBinaryInput) : + return AssignClassTo(clazz, range); + case(AssignClassType::Counter) : + return AssignClassTo(clazz, range); + case(AssignClassType::FrozenCounter) : + return AssignClassTo(clazz, range); + case(AssignClassType::AnalogInput) : + return AssignClassTo(clazz, range); + case(AssignClassType::BinaryOutputStatus) : + return AssignClassTo(clazz, range); + case(AssignClassType::AnalogOutputStatus) : + return AssignClassTo(clazz, range); + default: + return Range::Invalid(); + } +} + +template <> +StaticBinaryVariation DatabaseBuffers::CheckForPromotion(const Binary& value, StaticBinaryVariation variation) +{ + if (variation == StaticBinaryVariation::Group1Var1) + { + return BinarySpec::IsQualityOnlineOnly(value) ? variation : StaticBinaryVariation::Group1Var2; + } + else + { + return variation; + } +} + +Range DatabaseBuffers::RangeOf(uint16_t size) +{ + return size > 0 ? Range::From(0, size - 1) : Range::Invalid(); +} + + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.h new file mode 100644 index 0000000..6f0c533 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseBuffers.h @@ -0,0 +1,280 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DATABASEBUFFERS_H +#define OPENDNP3_DATABASEBUFFERS_H + +#include "opendnp3/app/Range.h" + +#include "opendnp3/gen/IndexMode.h" + +#include "opendnp3/outstation/IndexSearch.h" +#include "opendnp3/outstation/DatabaseSizes.h" +#include "opendnp3/outstation/StaticBuffers.h" +#include "opendnp3/outstation/SelectedRanges.h" +#include "opendnp3/outstation/StaticTypeBitfield.h" + +#include "opendnp3/outstation/IResponseLoader.h" +#include "opendnp3/outstation/IStaticSelector.h" +#include "opendnp3/outstation/IClassAssigner.h" +#include "opendnp3/outstation/StaticLoadFunctions.h" + +namespace opendnp3 +{ + +/** +The database coordinates all updates of measurement data +*/ +class DatabaseBuffers : public IStaticSelector, public IResponseLoader, public IClassAssigner, private openpal::Uncopyable +{ +public: + + DatabaseBuffers(const DatabaseSizes&, StaticTypeBitField allowedClass0Types, IndexMode indexMode); + + // ------- IStaticSelector ------------- + + virtual IINField SelectAll(GroupVariation gv) override final; + virtual IINField SelectRange(GroupVariation gv, const Range& range) override final; + + // ------- IResponseLoader ------------- + + virtual bool Load(HeaderWriter& writer) override final; + virtual bool HasAnySelection() const override final + { + return ranges.HasAnySelection(); + } + + // ------- IClassAssigner ------------- + + virtual Range AssignClassToAll(AssignClassType type, PointClass clazz) override final; + virtual Range AssignClassToRange(AssignClassType type, PointClass clazz, const Range& range) override final; + + //used to unselect selected points + void Unselect(); + + // stores the most revent values and event information + StaticBuffers buffers; + +private: + + StaticTypeBitField class0; + IndexMode indexMode; + + SelectedRanges ranges; + + template + bool LoadType(HeaderWriter& writer); + + template + void Deselect() + { + auto range = ranges.Get(); + if (range.IsValid()) + { + auto view = buffers.GetArrayView(); + for (uint16_t i = range.start; i <= range.stop; ++i) + { + view[i].selection.selected = false; + } + ranges.Clear(); + } + } + + //specialization for binary in cpp file + template + static typename Spec::static_variation_t CheckForPromotion(const typename Spec::meas_t& value, typename Spec::static_variation_t variation) + { + return variation; + } + + static Range RangeOf(uint16_t size); + + template + IINField GenericSelect( + Range range, + openpal::ArrayView, uint16_t> view, + bool useDefault, + typename T::static_variation_t variation + ); + + template + Range AssignClassTo(PointClass clazz, const Range& range); + + template + void SelectAllClass0() + { + if (class0.IsSet(T::StaticTypeEnum)) + { + this->SelectAll(); + } + } + + template + IINField SelectAll() + { + auto view = buffers.GetArrayView(); + return GenericSelect(RangeOf(view.Size()), view, true, typename T::static_variation_t()); + } + + template + IINField SelectAllUsing(typename T::static_variation_t variation) + { + auto view = buffers.GetArrayView(); + return GenericSelect(RangeOf(view.Size()), view, false, variation); + } + + template + IINField SelectVirtualRange(const Range& range, bool usedefault, typename T::static_variation_t variation) + { + if (indexMode == IndexMode::Discontiguous) + { + auto view = buffers.GetArrayView(); + auto mapped = IndexSearch::FindRawRange(view, range); + if (mapped.IsValid()) + { + // detect if any values were requested that aren't actually there + IINField clipped = (range.Count() == mapped.Count()) ? IINField() : IINField(IINBit::PARAM_ERROR); + return clipped | GenericSelect(mapped, buffers.GetArrayView(), usedefault, variation); + } + else + { + return IINField(IINBit::PARAM_ERROR); + } + } + else + { + return GenericSelect(range, buffers.GetArrayView(), usedefault, variation); + } + } + + template + IINField SelectRange(const Range& range) + { + return SelectVirtualRange(range, true, typename T::static_variation_t()); + } + + template + IINField SelectRangeUsing(const Range& range, typename T::static_variation_t variation) + { + return SelectVirtualRange(range, false, variation); + } +}; + +template +IINField DatabaseBuffers::GenericSelect( + Range range, + openpal::ArrayView, uint16_t> view, + bool useDefault, + typename T::static_variation_t variation) +{ + if (range.IsValid()) + { + auto allowed = range.Intersection(RangeOf(view.Size())); + + if (allowed.IsValid()) + { + // return code depends on if the range was truncated to match the database + IINField ret = allowed.Equals(range) ? IINField() : IINBit::PARAM_ERROR; + + for (uint16_t i = allowed.start; i <= allowed.stop; ++i) + { + if (view[i].selection.selected) + { + ret |= IINBit::PARAM_ERROR; + } + else + { + view[i].selection.selected = true; + view[i].selection.value = view[i].value; + auto var = useDefault ? view[i].config.svariation : variation; + view[i].selection.variation = CheckForPromotion(view[i].selection.value, var); + } + } + + ranges.Merge(allowed); + + return ret; + } + else + { + return IINField(IINBit::PARAM_ERROR); + } + } + else + { + return IINField(); + } +} + +template +bool DatabaseBuffers::LoadType(HeaderWriter& writer) +{ + auto range = ranges.Get(); + if (range.IsValid()) + { + auto view = buffers.GetArrayView(); + + bool spaceRemaining = true; + + // ... load values, manipulate the range + while (spaceRemaining && range.IsValid()) + { + if (view[range.start].selection.selected) + { + /// lookup the specific write function based on the reporting variation + auto writeFun = GetStaticWriter(view[range.start].selection.variation); + + // start writing a header, the invoked function will advance the range appropriately + spaceRemaining = writeFun(view, writer, range); + } + else + { + // just skip over values that are not selected + range.Advance(); + } + } + + ranges.Set(range); + + return spaceRemaining; + } + else + { + // no data to load + return true; + } +} + +template +Range DatabaseBuffers::AssignClassTo(PointClass clazz, const Range& range) +{ + auto view = buffers.GetArrayView(); + auto clipped = range.Intersection(RangeOf(view.Size())); + for (auto i = clipped.start; i <= clipped.stop; ++i) + { + view[i].config.clazz = clazz; + } + return clipped; +} + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.cpp new file mode 100644 index 0000000..e82d4dd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.cpp @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/outstation/DatabaseConfigView.h" + +namespace opendnp3 +{ + +DatabaseConfigView::DatabaseConfigView( + openpal::ArrayView, uint16_t> binaries, + openpal::ArrayView, uint16_t> doubleBinaries, + openpal::ArrayView, uint16_t> analogs, + openpal::ArrayView, uint16_t> counters, + openpal::ArrayView, uint16_t> frozenCounters, + openpal::ArrayView, uint16_t> binaryOutputStatii, + openpal::ArrayView, uint16_t> analogOutputStatii, + openpal::ArrayView, uint16_t> timeAndIntervals +) : + binaries(binaries), + doubleBinaries(doubleBinaries), + analogs(analogs), + counters(counters), + frozenCounters(frozenCounters), + binaryOutputStatii(binaryOutputStatii), + analogOutputStatii(analogOutputStatii), + timeAndIntervals(timeAndIntervals) +{} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.h new file mode 100644 index 0000000..82cdfe2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DatabaseConfigView.h @@ -0,0 +1,74 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DATABASECONFIGVIEW_H +#define OPENDNP3_DATABASECONFIGVIEW_H + +#include "opendnp3/app/MeasurementTypeSpecs.h" + +#include "opendnp3/outstation/Cell.h" + +#include + +namespace opendnp3 +{ + +/** +* DatabaseConfigView provides abstracted access to the raw buffers in outstation database. +* +* Use this object to congfigure: +* +* 1) Inital values if you want something besides false/zero with 0x02 restart quality +* 2) Default static/event reporting variations for each point +* 3) Class assignments (0,1,2,3) for each point +* 4) deadbands for analogs / counters / etc +* +*/ +class DatabaseConfigView +{ + +public: + + DatabaseConfigView( + openpal::ArrayView, uint16_t> binaries, + openpal::ArrayView, uint16_t> doubleBinaries, + openpal::ArrayView, uint16_t> analogs, + openpal::ArrayView, uint16_t> counters, + openpal::ArrayView, uint16_t> frozenCounters, + openpal::ArrayView, uint16_t> binaryOutputStatii, + openpal::ArrayView, uint16_t> analogOutputStatii, + openpal::ArrayView, uint16_t> timeAndIntervals + ); + + // ----------- Views of the underlying storage --------- + + openpal::ArrayView, uint16_t> binaries; + openpal::ArrayView, uint16_t> doubleBinaries; + openpal::ArrayView, uint16_t> analogs; + openpal::ArrayView, uint16_t> counters; + openpal::ArrayView, uint16_t> frozenCounters; + openpal::ArrayView, uint16_t> binaryOutputStatii; + openpal::ArrayView, uint16_t> analogOutputStatii; + openpal::ArrayView, uint16_t> timeAndIntervals; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.cpp new file mode 100644 index 0000000..47996b2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "DeferredRequest.h" + +namespace opendnp3 +{ + +DeferredRequest::DeferredRequest(uint32_t maxAPDUSize) : isSet(false), buffer(maxAPDUSize) +{} + +void DeferredRequest::Reset() +{ + isSet = false; +} + +bool DeferredRequest::IsSet() const +{ + return isSet; +} + +FunctionCode DeferredRequest::GetFunction() const +{ + return header.function; +} + +void DeferredRequest::Set(APDUHeader header_, openpal::RSlice objects_) +{ + this->isSet = true; + this->header = header_; + auto dest = buffer.GetWSlice(); + this->objects = objects_.CopyTo(dest); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.h new file mode 100644 index 0000000..7a5de96 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/DeferredRequest.h @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_DEFERREDREQUEST_H +#define OPENDNP3_DEFERREDREQUEST_H + +#include "opendnp3/app/APDUHeader.h" + +#include +#include + +namespace opendnp3 +{ + +/** +* Records metadata about deferred requests +*/ +class DeferredRequest : private openpal::Uncopyable +{ + +public: + + explicit DeferredRequest(uint32_t maxAPDUSize); + + void Reset(); + + bool IsSet() const; + + FunctionCode GetFunction() const; + + void Set(APDUHeader header, openpal::RSlice objects); + + template + bool Process(const Handler& handler); + +private: + + DeferredRequest() = delete; + + bool isSet; + APDUHeader header; + openpal::RSlice objects; + openpal::Buffer buffer; + +}; + +template +bool DeferredRequest::Process(const Handler& handler) +{ + if (isSet) + { + bool processed = handler(header, objects); + isSet = !processed; + return processed; + } + else + { + return false; + } +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Event.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Event.h new file mode 100644 index 0000000..3b5d5df --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/Event.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENT_H +#define OPENDNP3_EVENT_H + +#include "opendnp3/app/EventType.h" + +namespace opendnp3 +{ + +struct Evented +{ + Evented(uint16_t index_, EventClass clazz_) : index(index_), clazz(clazz_) + {} + + Evented() : clazz(EventClass::EC1) + {} + + uint16_t index; + EventClass clazz; // class of the event (CLASS<1-3>) +}; + +/** + * Record of an event that includes value, index, and class + */ +template +struct Event : public Evented +{ + typedef typename Spec::meas_t meas_type_t; + + Event(const meas_type_t& value, uint16_t index, EventClass clazz, typename Spec::event_variation_t variation) : + Evented(index, clazz), + value(value), + variation(variation) + {} + + Event() : Evented(), value(), variation() + {} + + meas_type_t value; + typename Spec::event_variation_t variation; +}; + +} //end namespace + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.cpp new file mode 100644 index 0000000..3b47da2 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.cpp @@ -0,0 +1,318 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "EventBuffer.h" + +#include "EventWriter.h" + +namespace opendnp3 +{ + +EventBuffer::EventBuffer(const EventBufferConfig& config_) : + overflow(false), + config(config_), + events(config_.TotalEvents()) +{ + +} + +void EventBuffer::Unselect() +{ + auto unselect = [this](SOERecord & record) + { + if (record.selected) + { + selectedCounts.Decrement(record.clazz, record.type); + record.selected = false; + } + + if (record.written) + { + writtenCounts.Decrement(record.clazz, record.type); + record.written = false; + } + + return this->selectedCounts.TotatCount() > 0; + }; + + events.While(unselect); +} + +IINField EventBuffer::SelectAll(GroupVariation gv) +{ + return SelectMaxCount(gv, openpal::MaxValue()); +} + +IINField EventBuffer::SelectCount(GroupVariation gv, uint16_t count) +{ + return SelectMaxCount(gv, count); +} + +IINField EventBuffer::SelectMaxCount(GroupVariation gv, uint32_t maximum) +{ + switch (gv) + { + case(GroupVariation::Group2Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group2Var1) : + return this->SelectByType(maximum, EventBinaryVariation::Group2Var1); + case(GroupVariation::Group2Var2) : + return this->SelectByType(maximum, EventBinaryVariation::Group2Var2); + case(GroupVariation::Group2Var3) : + return this->SelectByType(maximum, EventBinaryVariation::Group2Var3); + + case(GroupVariation::Group4Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group4Var1) : + return this->SelectByType(maximum, EventDoubleBinaryVariation::Group4Var1); + case(GroupVariation::Group4Var2) : + return this->SelectByType(maximum, EventDoubleBinaryVariation::Group4Var2); + case(GroupVariation::Group4Var3) : + return this->SelectByType(maximum, EventDoubleBinaryVariation::Group4Var3); + + case(GroupVariation::Group11Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group11Var1) : + return this->SelectByType(maximum, EventBinaryOutputStatusVariation::Group11Var1); + case(GroupVariation::Group11Var2) : + return this->SelectByType(maximum, EventBinaryOutputStatusVariation::Group11Var2); + + case(GroupVariation::Group22Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group22Var1) : + return this->SelectByType(maximum, EventCounterVariation::Group22Var1); + case(GroupVariation::Group22Var2) : + return this->SelectByType(maximum, EventCounterVariation::Group22Var2); + case(GroupVariation::Group22Var5) : + return this->SelectByType(maximum, EventCounterVariation::Group22Var5); + case(GroupVariation::Group22Var6) : + return this->SelectByType(maximum, EventCounterVariation::Group22Var6); + + case(GroupVariation::Group23Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group23Var1) : + return this->SelectByType(maximum, EventFrozenCounterVariation::Group23Var1); + case(GroupVariation::Group23Var2) : + return this->SelectByType(maximum, EventFrozenCounterVariation::Group23Var2); + case(GroupVariation::Group23Var5) : + return this->SelectByType(maximum, EventFrozenCounterVariation::Group23Var5); + case(GroupVariation::Group23Var6) : + return this->SelectByType(maximum, EventFrozenCounterVariation::Group23Var6); + + case(GroupVariation::Group32Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group32Var1) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var1); + case(GroupVariation::Group32Var2) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var2); + case(GroupVariation::Group32Var3) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var3); + case(GroupVariation::Group32Var4) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var4); + case(GroupVariation::Group32Var5) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var5); + case(GroupVariation::Group32Var6) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var6); + case(GroupVariation::Group32Var7) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var7); + case(GroupVariation::Group32Var8) : + return this->SelectByType(maximum, EventAnalogVariation::Group32Var8); + + case(GroupVariation::Group42Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group42Var1) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var1); + case(GroupVariation::Group42Var2) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var2); + case(GroupVariation::Group42Var3) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var3); + case(GroupVariation::Group42Var4) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var4); + case(GroupVariation::Group42Var5) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var5); + case(GroupVariation::Group42Var6) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var6); + case(GroupVariation::Group42Var7) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var7); + case(GroupVariation::Group42Var8) : + return this->SelectByType(maximum, EventAnalogOutputStatusVariation::Group42Var8); + + + case(GroupVariation::Group60Var2) : + return this->SelectByClass(ClassField(PointClass::Class1), maximum); + case(GroupVariation::Group60Var3): + return this->SelectByClass(ClassField(PointClass::Class2), maximum); + case(GroupVariation::Group60Var4): + return this->SelectByClass(ClassField(PointClass::Class3), maximum); + + case(GroupVariation::Group122Var0) : + return this->SelectByType(maximum); + case(GroupVariation::Group122Var1) : + return this->SelectByType(maximum, EventSecurityStatVariation::Group122Var1); + case(GroupVariation::Group122Var2) : + return this->SelectByType(maximum, EventSecurityStatVariation::Group122Var2); + + default: + return IINBit::FUNC_NOT_SUPPORTED; + } +} + +bool EventBuffer::HasAnySelection() const +{ + // are there any selected, but unwritten, events + return selectedCounts.TotatCount() > writtenCounts.TotatCount(); +} + +bool EventBuffer::Load(HeaderWriter& writer) +{ + return EventWriter::Write(writer, *this, events.Iterate()); +} + +bool EventBuffer::HasMoreUnwrittenEvents() const +{ + return HasAnySelection(); +} + +void EventBuffer::RecordWritten(EventClass ec, EventType et) +{ + writtenCounts.Increment(ec, et); +} + +ClassField EventBuffer::UnwrittenClassField() const +{ + return ClassField(false, + HasUnwrittenEvents(EventClass::EC1), + HasUnwrittenEvents(EventClass::EC2), + HasUnwrittenEvents(EventClass::EC3) + ); +} + +bool EventBuffer::IsOverflown() +{ + if (overflow && HasEnoughSpaceToClearOverflow()) + { + overflow = false; + } + + return overflow; +} + +IINField EventBuffer::SelectByClass(const ClassField& field, uint32_t max) +{ + uint32_t num = 0; + auto iter = events.Iterate(); + const uint32_t remaining = totalCounts.NumOfClass(field) - selectedCounts.NumOfClass(field); + + while (iter.HasNext() && (num < remaining) && (num < max)) + { + auto pNode = iter.Next(); + if (field.HasEventType(pNode->value.clazz)) + { + pNode->value.SelectDefault(); + selectedCounts.Increment(pNode->value.clazz, pNode->value.type); + ++num; + } + } + + return IINField(); +} + +void EventBuffer::RemoveFromCounts(const SOERecord& record) +{ + totalCounts.Decrement(record.clazz, record.type); + + if (record.selected) + { + selectedCounts.Decrement(record.clazz, record.type); + } + + if (record.written) + { + writtenCounts.Decrement(record.clazz, record.type); + } +} + +bool EventBuffer::RemoveOldestEventOfType(EventType type) +{ + // find the first event of this type in the SOE, and discard it + auto isMatch = [type](const SOERecord & rec) + { + return rec.type == type; + }; + auto pNode = events.RemoveFirst(isMatch); + + if (pNode) + { + this->RemoveFromCounts(pNode->value); + pNode->value.Reset(); + return true; + } + else + { + return false; + } +} + +void EventBuffer::SelectAllByClass(const ClassField& field) +{ + this->SelectByClass(field, openpal::MaxValue()); +} + +void EventBuffer::ClearWritten() +{ + auto written = [this](const SOERecord & record) + { + if (record.written) + { + this->RemoveFromCounts(record); + return true; + } + else + { + return false; + } + }; + + events.RemoveAll(written); +} + +bool EventBuffer::IsTypeOverflown(EventType type) const +{ + auto max = config.GetMaxEventsForType(type); + return (max > 0) ? (totalCounts.NumOfType(type) >= max) : false; +} + +bool EventBuffer::IsAnyTypeOverflown() const +{ + return IsTypeOverflown(EventType::Binary) || + IsTypeOverflown(EventType::DoubleBitBinary) || + IsTypeOverflown(EventType::BinaryOutputStatus) || + IsTypeOverflown(EventType::Counter) || + IsTypeOverflown(EventType::FrozenCounter) || + IsTypeOverflown(EventType::Analog) || + IsTypeOverflown(EventType::AnalogOutputStatus); +} + +bool EventBuffer::HasEnoughSpaceToClearOverflow() const +{ + return !(events.IsFull() || IsAnyTypeOverflown()); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.h new file mode 100644 index 0000000..0ac7265 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBuffer.h @@ -0,0 +1,223 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTBUFFER_H +#define OPENDNP3_EVENTBUFFER_H + +#include "opendnp3/outstation/IEventReceiver.h" +#include "opendnp3/outstation/IEventSelector.h" +#include "opendnp3/outstation/IResponseLoader.h" +#include "opendnp3/outstation/IEventRecorder.h" +#include "opendnp3/outstation/EventCount.h" +#include "opendnp3/outstation/EventBufferConfig.h" +#include "opendnp3/outstation/SOERecord.h" + +#include + +namespace opendnp3 +{ + +/* + The sequence of events list is a doubly linked-list implemented + in a finite array. The list is desired for O(1) remove operations from + arbitrary parts of the list depending on what the user asks for in terms + of event type or Class1/2/3. + + At worst, selection is O(n) in the SOE length but it has some type/class + tracking to avoid looping over the SOE list when there are no more events matching + the selection criteria. +*/ + +class EventBuffer : public IEventReceiver, public IEventSelector, public IResponseLoader, private IEventRecorder +{ + +public: + + explicit EventBuffer(const EventBufferConfig& config); + + // ------- IEventReceiver ------ + + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + virtual void Update(const Event& evt) override final + { + this->UpdateAny(evt); + } + + // ------- IEventSelector ------ + + virtual void Unselect(); + + virtual IINField SelectAll(GroupVariation gv) override final; + + virtual IINField SelectCount(GroupVariation gv, uint16_t count) override final; + + // ------- IResponseLoader ------- + + virtual bool HasAnySelection() const override final; + + virtual bool Load(HeaderWriter& writer) override final; + + // ------- IEventRecorder------- + + virtual bool HasMoreUnwrittenEvents() const override final; + + virtual void RecordWritten(EventClass ec, EventType et) override final; + + // ------- Misc ------- + + void SelectAllByClass(const ClassField& field); + + void ClearWritten(); // called when a transmission succeeds + + ClassField UnwrittenClassField() const; + + bool IsOverflown(); + +private: + + inline bool HasUnwrittenEvents(EventClass ec) const + { + return (totalCounts.NumOfClass(ec) - writtenCounts.NumOfClass(ec)) > 0; + } + + IINField SelectMaxCount(GroupVariation gv, uint32_t maximum); + + IINField SelectByClass(const ClassField& field, uint32_t max); + + template + uint32_t GenericSelectByType(uint32_t max, bool useDefault, typename Spec::event_variation_t var); + + template + IINField SelectByType(int32_t max) + { + GenericSelectByType(max, true, typename Spec::event_variation_t()); + return IINField(); + } + + template + IINField SelectByType(int32_t max, typename Spec::event_variation_t var) + { + GenericSelectByType(max, false, var); + return IINField(); + } + + void RemoveFromCounts(const SOERecord& record); + + bool RemoveOldestEventOfType(EventType type); + + template + void UpdateAny(const Event& evt); + + bool IsAnyTypeOverflown() const; + bool IsTypeOverflown(EventType type) const; + + bool overflow; + + EventBufferConfig config; + + openpal::LinkedList events; + + // ---- trakcers + + EventCount totalCounts; + EventCount selectedCounts; + EventCount writtenCounts; + + bool HasEnoughSpaceToClearOverflow() const; +}; + +template +void EventBuffer::UpdateAny(const Event& evt) +{ + auto maxForType = config.GetMaxEventsForType(Spec::EventTypeEnum); + + if (maxForType > 0) + { + auto currentCount = totalCounts.NumOfType(Spec::EventTypeEnum); + + if (currentCount >= maxForType || events.IsFull()) + { + this->overflow = true; + RemoveOldestEventOfType(Spec::EventTypeEnum); + } + + // Add the event, the Reset() ensures that selected/written == false + events.Add(SOERecord(evt.value, evt.index, evt.clazz, evt.variation))->value.Reset(); + totalCounts.Increment(evt.clazz, Spec::EventTypeEnum); + } +} + +template +uint32_t EventBuffer::GenericSelectByType(uint32_t max, bool useDefault, typename Spec::event_variation_t var) +{ + uint32_t num = 0; + auto iter = events.Iterate(); + const uint32_t remaining = totalCounts.NumOfType(Spec::EventTypeEnum) - selectedCounts.NumOfType(Spec::EventTypeEnum); + + while (iter.HasNext() && (num < remaining) && (num < max)) + { + auto pNode = iter.Next(); + + if (pNode->value.type == Spec::EventTypeEnum) + { + if (useDefault) + { + pNode->value.SelectDefault(); + } + else + { + pNode->value.Select(var); + } + + selectedCounts.Increment(pNode->value.clazz, pNode->value.type); + ++num; + } + } + + return num; +} + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBufferConfig.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBufferConfig.cpp new file mode 100644 index 0000000..b4ebb03 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventBufferConfig.cpp @@ -0,0 +1,92 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/outstation/EventBufferConfig.h" + +namespace opendnp3 +{ + +EventBufferConfig EventBufferConfig::AllTypes(uint16_t sizes) +{ + return EventBufferConfig(sizes, sizes, sizes, sizes, sizes, sizes, sizes, sizes); +} + +uint16_t EventBufferConfig::GetMaxEventsForType(EventType type) const +{ + switch (type) + { + case(EventType::Binary) : + return maxBinaryEvents; + case(EventType::DoubleBitBinary) : + return maxDoubleBinaryEvents; + case(EventType::BinaryOutputStatus) : + return maxBinaryOutputStatusEvents; + case(EventType::Counter) : + return maxCounterEvents; + case(EventType::FrozenCounter) : + return maxFrozenCounterEvents; + case(EventType::Analog) : + return maxAnalogEvents; + case(EventType::AnalogOutputStatus) : + return maxAnalogOutputStatusEvents; + case(EventType::SecurityStat) : + return maxSecurityStatisticEvents; + default: + return 0; + } +} + +EventBufferConfig::EventBufferConfig( + uint16_t maxBinaryEvents_, + uint16_t maxDoubleBinaryEvents_, + uint16_t maxAnalogEvents_, + uint16_t maxCounterEvents_, + uint16_t maxFrozenCounterEvents_, + uint16_t maxBinaryOutputStatusEvents_, + uint16_t maxAnalogOutputStatusEvents_, + uint16_t maxSecurityStatisticEvents_) : + + maxBinaryEvents(maxBinaryEvents_), + maxDoubleBinaryEvents(maxDoubleBinaryEvents_), + maxAnalogEvents(maxAnalogEvents_), + maxCounterEvents(maxCounterEvents_), + maxFrozenCounterEvents(maxFrozenCounterEvents_), + maxBinaryOutputStatusEvents(maxBinaryOutputStatusEvents_), + maxAnalogOutputStatusEvents(maxAnalogOutputStatusEvents_), + maxSecurityStatisticEvents(maxSecurityStatisticEvents_) +{ + +} + +uint32_t EventBufferConfig::TotalEvents() const +{ + return maxBinaryEvents + + maxDoubleBinaryEvents + + maxAnalogEvents + + maxCounterEvents + + maxFrozenCounterEvents + + maxBinaryOutputStatusEvents + + maxAnalogOutputStatusEvents + + maxSecurityStatisticEvents; +} + + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.cpp new file mode 100644 index 0000000..64d4451 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.cpp @@ -0,0 +1,133 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "EventCount.h" + +#include "opendnp3/gen/PointClass.h" + +namespace opendnp3 +{ + +EventCount::EventCount() : total(0) +{ + this->Clear(); +} + +EventCount::EventCount(const EventCount& ec) : total(ec.total) +{ + for (uint16_t clazz = 0; clazz < NUM_CLASSES; ++clazz) + { + numOfClass[clazz] = ec.numOfClass[clazz]; + } + + + for (uint16_t type = 0; type < NUM_TYPES; ++type) + { + numOfType[type] = ec.numOfType[type]; + } +} + +EventCount& EventCount::operator=(const EventCount& ec) +{ + if (this != &ec) + { + this->total = ec.total; + + for (uint16_t clazz = 0; clazz < NUM_CLASSES; ++clazz) + { + numOfClass[clazz] = ec.numOfClass[clazz]; + } + + + for (uint16_t type = 0; type < NUM_TYPES; ++type) + { + numOfType[type] = ec.numOfType[type]; + } + } + + return *this; +} + +void EventCount::Clear() +{ + total = 0; + + for (uint16_t clazz = 0; clazz < NUM_CLASSES; ++clazz) + { + numOfClass[clazz] = 0; + } + + + for (uint16_t type = 0; type < NUM_TYPES; ++type) + { + numOfType[type] = 0; + } +} + +ClassField EventCount::ToClassField() const +{ + bool class1 = this->NumOfClass(EventClass::EC1) > 0; + bool class2 = this->NumOfClass(EventClass::EC2) > 0; + bool class3 = this->NumOfClass(EventClass::EC3) > 0; + + return ClassField(false, class1, class2, class3); +} + +uint32_t EventCount::NumOfClass(ClassField field) const +{ + uint32_t ret = 0; + + if (field.HasClass1()) ret += NumOfClass(EventClass::EC1); + if (field.HasClass2()) ret += NumOfClass(EventClass::EC2); + if (field.HasClass3()) ret += NumOfClass(EventClass::EC3); + + return ret; +} + +uint32_t EventCount::NumOfClass(EventClass clazz) const +{ + return numOfClass[static_cast(clazz)]; +} + +uint32_t EventCount::NumOfType(EventType type) const +{ + return numOfType[static_cast(type)]; +} + +bool EventCount::IsEmpty() const +{ + return ToClassField().IsEmpty(); +} + +void EventCount::Increment(EventClass clazz, EventType type) +{ + ++total; + ++numOfClass[static_cast(clazz)]; + ++numOfType[static_cast(type)]; +} + +void EventCount::Decrement(EventClass clazz, EventType type) +{ + --total; + --numOfType[static_cast(type)]; + --numOfClass[static_cast(clazz)]; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.h new file mode 100644 index 0000000..6dbe1f8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventCount.h @@ -0,0 +1,76 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTCOUNT_H +#define OPENDNP3_EVENTCOUNT_H + +#include + +#include + +#include "opendnp3/app/ClassField.h" +#include "opendnp3/app/EventType.h" + +namespace opendnp3 +{ + +class EventCount +{ + static const uint16_t NUM_CLASSES = 3; + static const uint16_t NUM_TYPES = 8; + +public: + + EventCount(); + + EventCount(const EventCount& ec); + + EventCount& operator=(const EventCount& ec); + + ClassField ToClassField() const; + + uint32_t NumOfClass(EventClass clazz) const; + uint32_t NumOfClass(ClassField field) const; + uint32_t NumOfType(EventType type) const; + + uint32_t TotatCount() const + { + return total; + } + + void Increment(EventClass clazz, EventType type); + void Decrement(EventClass clazz, EventType type); + + bool IsEmpty() const; + + void Clear(); + +private: + + bool SameNumberForClass(const EventCount& rhs, EventClass clazz) const; + + uint32_t total; + uint32_t numOfType[NUM_TYPES]; + uint32_t numOfClass[NUM_CLASSES]; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.cpp new file mode 100644 index 0000000..10557c0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.cpp @@ -0,0 +1,239 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "EventWriter.h" + +#include "opendnp3/objects/Group2.h" +#include "opendnp3/objects/Group4.h" +#include "opendnp3/objects/Group11.h" +#include "opendnp3/objects/Group22.h" +#include "opendnp3/objects/Group23.h" +#include "opendnp3/objects/Group32.h" +#include "opendnp3/objects/Group42.h" +#include "opendnp3/objects/Group51.h" +#include "opendnp3/objects/Group122.h" + +using namespace openpal; + +namespace opendnp3 +{ +bool EventWriter::Write(HeaderWriter& writer, IEventRecorder& recorder, openpal::LinkedListIterator iterator) +{ + while (iterator.HasNext() && recorder.HasMoreUnwrittenEvents()) + { + auto pCurrent = iterator.Next(); + + if (IsWritable(pCurrent->value)) + { + auto result = LoadHeader(writer, recorder, pCurrent); + iterator = result.location; + + if (result.isFragmentFull) + { + return false; + } + } + } + + return true; +} + +EventWriter::Result EventWriter::LoadHeader(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + switch (pLocation->value.type) + { + case(EventType::Binary) : + return LoadHeaderBinary(writer, recorder, pLocation); + case(EventType::DoubleBitBinary) : + return LoadHeaderDoubleBinary(writer, recorder, pLocation); + case(EventType::Counter): + return LoadHeaderCounter(writer, recorder, pLocation); + case(EventType::FrozenCounter): + return LoadHeaderFrozenCounter(writer, recorder, pLocation); + case(EventType::Analog): + return LoadHeaderAnalog(writer, recorder, pLocation); + case(EventType::BinaryOutputStatus): + return LoadHeaderBinaryOutputStatus(writer, recorder, pLocation); + case(EventType::AnalogOutputStatus) : + return LoadHeaderAnalogOutputStatus(writer, recorder, pLocation); + case(EventType::SecurityStat) : + return LoadHeaderSecurityStat(writer, recorder, pLocation); + default: + return Result(false, LinkedListIterator::Undefined()); + } +} + +EventWriter::Result EventWriter::LoadHeaderBinary(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventBinaryVariation::Group2Var1): + return WriteTypeWithSerializer(writer, recorder, pLocation, Group2Var1::Inst(), variation); + case(EventBinaryVariation::Group2Var2): + return WriteTypeWithSerializer(writer, recorder, pLocation, Group2Var2::Inst(), variation); + case(EventBinaryVariation::Group2Var3) : + return WriteCTOTypeWithSerializer(writer, recorder, pLocation, Group2Var3::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group2Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderDoubleBinary(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventDoubleBinaryVariation::Group4Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group4Var1::Inst(), variation); + case(EventDoubleBinaryVariation::Group4Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group4Var2::Inst(), variation); + case(EventDoubleBinaryVariation::Group4Var3) : + return WriteCTOTypeWithSerializer(writer, recorder, pLocation, Group4Var3::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group4Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderCounter(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventCounterVariation::Group22Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group22Var1::Inst(), variation); + case(EventCounterVariation::Group22Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group22Var2::Inst(), variation); + case(EventCounterVariation::Group22Var5) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group22Var5::Inst(), variation); + case(EventCounterVariation::Group22Var6) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group22Var6::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group22Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderFrozenCounter(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventFrozenCounterVariation::Group23Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group23Var1::Inst(), variation); + case(EventFrozenCounterVariation::Group23Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group23Var2::Inst(), variation); + case(EventFrozenCounterVariation::Group23Var5) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group23Var5::Inst(), variation); + case(EventFrozenCounterVariation::Group23Var6) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group23Var6::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group23Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderAnalog(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventAnalogVariation::Group32Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var1::Inst(), variation); + case(EventAnalogVariation::Group32Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var2::Inst(), variation); + case(EventAnalogVariation::Group32Var3) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var3::Inst(), variation); + case(EventAnalogVariation::Group32Var4) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var4::Inst(), variation); + case(EventAnalogVariation::Group32Var5) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var5::Inst(), variation); + case(EventAnalogVariation::Group32Var6) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var6::Inst(), variation); + case(EventAnalogVariation::Group32Var7) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var7::Inst(), variation); + case(EventAnalogVariation::Group32Var8) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var8::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group32Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderBinaryOutputStatus(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventBinaryOutputStatusVariation::Group11Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group11Var1::Inst(), variation); + case(EventBinaryOutputStatusVariation::Group11Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group11Var2::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group11Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderAnalogOutputStatus(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventAnalogOutputStatusVariation::Group42Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var1::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var2::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var3) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var3::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var4) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var4::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var5) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var5::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var6) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var6::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var7) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var7::Inst(), variation); + case(EventAnalogOutputStatusVariation::Group42Var8) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var8::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group42Var1::Inst(), variation); + } +} + +EventWriter::Result EventWriter::LoadHeaderSecurityStat(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation) +{ + auto variation = pLocation->value.GetValue().selectedVariation; + + switch (variation) + { + case(EventSecurityStatVariation::Group122Var1) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group122Var1::Inst(), variation); + case(EventSecurityStatVariation::Group122Var2) : + return WriteTypeWithSerializer(writer, recorder, pLocation, Group122Var2::Inst(), variation); + default: + return WriteTypeWithSerializer(writer, recorder, pLocation, Group122Var1::Inst(), variation); + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.h new file mode 100644 index 0000000..ff8a0bf --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/EventWriter.h @@ -0,0 +1,182 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_EVENTWRITER_H +#define OPENDNP3_EVENTWRITER_H + +#include +#include + +#include "opendnp3/app/HeaderWriter.h" +#include "opendnp3/outstation/SOERecord.h" +#include "opendnp3/outstation/IEventRecorder.h" + +namespace opendnp3 +{ + +class EventWriter : openpal::StaticOnly +{ +public: + + static bool Write(HeaderWriter& writer, IEventRecorder& recorder, openpal::LinkedListIterator iterator); + +private: + + class Result + { + public: + + Result(bool isFragmentFull_, openpal::LinkedListIterator location_) : isFragmentFull(isFragmentFull_), location(location_) + {} + + bool isFragmentFull; + openpal::LinkedListIterator location; + + + private: + + Result() = delete; + }; + + static Result LoadHeader(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + + static Result LoadHeaderBinary(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderDoubleBinary(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderCounter(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderFrozenCounter(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderAnalog(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderBinaryOutputStatus(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderAnalogOutputStatus(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + static Result LoadHeaderSecurityStat(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation); + + inline static bool IsWritable(const SOERecord& record) + { + return record.selected && !record.written; + } + + template + static Result WriteTypeWithSerializer(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation, opendnp3::DNP3Serializer serializer, typename Spec::event_variation_t variation) + { + auto iter = openpal::LinkedListIterator::From(pLocation); + + auto header = writer.IterateOverCountWithPrefix(QualifierCode::UINT16_CNT_UINT16_INDEX, serializer); + + openpal::ListNode* pCurrent = nullptr; + + while (recorder.HasMoreUnwrittenEvents() && (pCurrent = iter.Next())) + { + auto& record = pCurrent->value; + + if (IsWritable(record)) + { + if ((record.type == Spec::EventTypeEnum) && (record.GetValue().selectedVariation == variation)) + { + auto evt = record.ReadEvent(); + if (header.Write(evt.value, evt.index)) + { + record.written = true; + recorder.RecordWritten(record.clazz, record.type); + } + else + { + auto location = openpal::LinkedListIterator::From(pCurrent); + return Result(true, location); + } + } + else + { + + // drop out and return from current location + break; + } + } + } + + auto location = openpal::LinkedListIterator::From(pCurrent); + return Result(false, location); + } + + template + static Result WriteCTOTypeWithSerializer(HeaderWriter& writer, IEventRecorder& recorder, openpal::ListNode* pLocation, opendnp3::DNP3Serializer serializer, typename Spec::event_variation_t variation) + { + auto iter = openpal::LinkedListIterator::From(pLocation); + + CTOType cto; + cto.time = pLocation->value.GetTime(); + + auto header = writer.IterateOverCountWithPrefixAndCTO(QualifierCode::UINT16_CNT_UINT16_INDEX, serializer, cto); + + openpal::ListNode* pCurrent = nullptr; + + while (recorder.HasMoreUnwrittenEvents() && (pCurrent = iter.Next())) + { + auto& record = pCurrent->value; + + if (IsWritable(record)) + { + if ((record.type == Spec::EventTypeEnum) && (record.GetValue().selectedVariation == variation)) + { + if (record.GetTime() < cto.time) + { + // drop out and return from current location + break; + } + else + { + auto diff = record.GetTime() - cto.time; + if (diff > openpal::UInt16::Max) + { + // drop out and return from current location + break; + } + else + { + auto evt = record.ReadEvent(); + evt.value.time = DNPTime(diff); + if (header.Write(evt.value, evt.index)) + { + record.written = true; + recorder.RecordWritten(record.clazz, record.type); + } + else + { + auto location = openpal::LinkedListIterator::From(pCurrent); + return Result(true, location); + } + } + } + } + else + { + // drop out and return from current location + break; + } + } + } + + auto location = openpal::LinkedListIterator::From(pCurrent); + return Result(false, location); + } + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IClassAssigner.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IClassAssigner.h new file mode 100644 index 0000000..b371302 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IClassAssigner.h @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICLASSASSIGNER_H +#define OPENDNP3_ICLASSASSIGNER_H + +#include "opendnp3/app/Range.h" +#include "opendnp3/app/GroupVariationRecord.h" + +#include "opendnp3/gen/PointClass.h" +#include "opendnp3/gen/AssignClassType.h" + +namespace opendnp3 +{ + +/** +* An interface used to process assign class requests +*/ +class IClassAssigner +{ +public: + + /** + * @return the full range for the actual type, an invalid range if the type doesn't exist + */ + virtual Range AssignClassToAll(AssignClassType type, PointClass clazz) = 0; + + /** + * @return the portion of the requested range that is valid, an invalid range if the type doesn't exist + */ + virtual Range AssignClassToRange(AssignClassType type, PointClass clazz, const Range& range) = 0; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ICommandAction.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ICommandAction.h new file mode 100644 index 0000000..cb9d076 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ICommandAction.h @@ -0,0 +1,53 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ICOMMANDACTION_H +#define OPENDNP3_ICOMMANDACTION_H + +#include "opendnp3/app/ControlRelayOutputBlock.h" +#include "opendnp3/app/AnalogOutput.h" + +namespace opendnp3 +{ + +/** +* Interface used to dispatch an abstract action using a command +*/ +class ICommandAction +{ +public: + virtual ~ICommandAction() {} + + virtual CommandStatus Action(const ControlRelayOutputBlock& arCommand, uint16_t aIndex) = 0; + + virtual CommandStatus Action(const AnalogOutputInt16& arCommand, uint16_t aIndex) = 0; + + virtual CommandStatus Action(const AnalogOutputInt32& arCommand, uint16_t aIndex) = 0; + + virtual CommandStatus Action(const AnalogOutputFloat32& arCommand, uint16_t aIndex) = 0; + + virtual CommandStatus Action(const AnalogOutputDouble64& arCommand, uint16_t aIndex) = 0; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IDatabase.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IDatabase.h new file mode 100644 index 0000000..655743c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IDatabase.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IDATABASE_H +#define OPENDNP3_IDATABASE_H + +#include "opendnp3/outstation/IUpdateHandler.h" +#include "opendnp3/outstation/IResponseLoader.h" +#include "opendnp3/outstation/IStaticSelector.h" +#include "opendnp3/outstation/IClassAssigner.h" + +namespace opendnp3 +{ +/** +* Extends IUpdateHandler with accessors for other required sub-interfaces related to +* handling various request types +*/ +class IDatabase : public IUpdateHandler +{ +public: + + virtual ~IDatabase() {} + + virtual IResponseLoader& GetResponseLoader() = 0; + + virtual IStaticSelector& GetStaticSelector() = 0; + + virtual IClassAssigner& GetClassAssigner() = 0; + + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventReceiver.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventReceiver.h new file mode 100644 index 0000000..e9ee53a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventReceiver.h @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IEVENTRECEIVER_H +#define OPENDNP3_IEVENTRECEIVER_H + +#include "opendnp3/outstation/Event.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" +#include "opendnp3/app/SecurityStat.h" + +namespace opendnp3 +{ + +/** +* Transactional interface that receives events +*/ +class IEventReceiver +{ +public: + + virtual ~IEventReceiver() {} + + virtual void Update(const Event& evt) = 0; + + virtual void Update(const Event& evt) = 0; + + virtual void Update(const Event& evt) = 0; + + virtual void Update(const Event& evt) = 0; + + virtual void Update(const Event& evt) = 0; + + virtual void Update(const Event& evt) = 0; + + virtual void Update(const Event& evt) = 0; + +}; + +} + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventRecorder.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventRecorder.h new file mode 100644 index 0000000..f52330b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventRecorder.h @@ -0,0 +1,40 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IEVENTRECORDER_H +#define OPENDNP3_IEVENTRECORDER_H + +#include "opendnp3/app/EventType.h" + +namespace opendnp3 +{ + +class IEventRecorder +{ +public: + + virtual bool HasMoreUnwrittenEvents() const = 0; + + virtual void RecordWritten(EventClass ec, EventType et) = 0; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventSelector.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventSelector.h new file mode 100644 index 0000000..9744bdb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IEventSelector.h @@ -0,0 +1,42 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IEVENTSELECTOR_H +#define OPENDNP3_IEVENTSELECTOR_H + +#include "opendnp3/app/IINField.h" +#include "opendnp3/app/GroupVariationRecord.h" + +namespace opendnp3 +{ + +class IEventSelector +{ +public: + + virtual IINField SelectAll(GroupVariation gv) = 0; + + virtual IINField SelectCount(GroupVariation gv, uint16_t count) = 0; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.cpp new file mode 100644 index 0000000..d6e2085 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.cpp @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/outstation/IINHelpers.h" + +namespace opendnp3 +{ + +IINField IINFromParseResult(ParseResult result) +{ + switch(result) + { + case(ParseResult::OK): + return IINField::Empty(); + case(ParseResult::UNKNOWN_OBJECT): + return IINField(IINBit::OBJECT_UNKNOWN); + default: + return IINField(IINBit::PARAM_ERROR); + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.h new file mode 100644 index 0000000..e9354d1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IINHelpers.h @@ -0,0 +1,34 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IINHELPERS_H +#define OPENDNP3_IINHELPERS_H + +#include "opendnp3/app/IINField.h" +#include "opendnp3/app/parsing/ParseResult.h" + +namespace opendnp3 +{ + +IINField IINFromParseResult(ParseResult result); + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IOutstationApplication.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IOutstationApplication.cpp new file mode 100644 index 0000000..ed44ba4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IOutstationApplication.cpp @@ -0,0 +1,26 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/outstation/IOutstationApplication.h" + +namespace opendnp3 +{ + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IResponseLoader.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IResponseLoader.h new file mode 100644 index 0000000..ba02287 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IResponseLoader.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_IRESPONSELOADER_H +#define OPENDNP3_IRESPONSELOADER_H + +#include "opendnp3/app/HeaderWriter.h" + +namespace opendnp3 +{ + +class IResponseLoader +{ +public: + + /** + * @ return True if there is any data selected for reporting + */ + virtual bool HasAnySelection() const = 0; + + /** + * Loads static data into a response APDU + * + * @param writer The HeaderWriter instance used to place data in the APDU + * @return True if all data was loaded, false if there is no more space + */ + virtual bool Load(HeaderWriter& writer) = 0; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IStaticSelector.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IStaticSelector.h new file mode 100644 index 0000000..e5ba8c7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IStaticSelector.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_ISTATICSELECTOR_H +#define OPENDNP3_ISTATICSELECTOR_H + +#include "opendnp3/app/Range.h" +#include "opendnp3/app/IINField.h" +#include "opendnp3/app/GroupVariationRecord.h" + +namespace opendnp3 +{ + +class IStaticSelector +{ +public: + + virtual IINField SelectAll(GroupVariation gv) = 0; + + virtual IINField SelectRange(GroupVariation gv, const Range& range) = 0; + + virtual void Unselect() = 0; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IndexSearch.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IndexSearch.h new file mode 100644 index 0000000..29a83fb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/IndexSearch.h @@ -0,0 +1,172 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_INDEXSEARCH_H +#define OPENDNP3_INDEXSEARCH_H + +#include "opendnp3/outstation/Cell.h" + +#include "opendnp3/app/Range.h" +#include "opendnp3/app/MeasurementTypes.h" + +#include +#include +#include + +namespace opendnp3 +{ + +/** +* Implements a binary search for virtual indices in a discontiguous database +*/ +class IndexSearch : private openpal::StaticOnly +{ + +public: + + class Result + { + public: + + Result(bool match_, uint16_t index_) : match(match_), index(index_) + {} + + const bool match; + const uint16_t index; + + private: + + Result() = delete; + }; + + template + static Range FindRawRange(const openpal::ArrayView, uint16_t>& view, const Range& range); + + template + static Result FindClosestRawIndex(const openpal::ArrayView, uint16_t>& view, uint16_t vIndex); + +private: + + static uint16_t GetMidpoint(uint16_t lower, uint16_t upper) + { + return ((upper - lower) / 2) + lower; + } +}; + +template +Range IndexSearch::FindRawRange(const openpal::ArrayView, uint16_t>& view, const Range& range) +{ + if (range.IsValid() && view.IsNotEmpty()) + { + uint16_t start = FindClosestRawIndex(view, range.start).index; + uint16_t stop = FindClosestRawIndex(view, range.stop).index; + + if (view[start].config.vIndex < range.start) + { + if (start < openpal::MaxValue()) + { + ++start; + } + else + { + return Range::Invalid(); + } + } + + if (view[stop].config.vIndex > range.stop) + { + if (stop > 0) + { + --stop; + } + else + { + return Range::Invalid(); + } + } + + return (view.Contains(start) && view.Contains(stop)) ? Range::From(start, stop) : Range::Invalid(); + } + else + { + return Range::Invalid(); + } +} + +template +IndexSearch::Result IndexSearch::FindClosestRawIndex(const openpal::ArrayView, uint16_t>& view, uint16_t vIndex) +{ + if (view.IsEmpty()) + { + return Result(false, 0); + } + else + { + uint16_t lower = 0; + uint16_t upper = view.Size() - 1; + + uint16_t midpoint = 0; + + while (lower <= upper) + { + midpoint = GetMidpoint(lower, upper); + + auto index = view[midpoint].config.vIndex; + + if (index == vIndex) + { + return Result(true, midpoint); + } + else + { + if (index < vIndex) // search the upper array + { + if (lower < openpal::MaxValue()) + { + lower = midpoint + 1; + } + else + { + //we're at the upper limit + return Result(false, midpoint); + } + } + else + { + if (upper > 0) + { + upper = midpoint - 1; + } + else + { + //we're at the lower limit + return Result(false, midpoint); + } + } + } + } + + return Result(false, midpoint); + } +} + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationChannelStates.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationChannelStates.h new file mode 100644 index 0000000..e96a988 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationChannelStates.h @@ -0,0 +1,66 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONCHANNEL_STATES_H +#define OPENDNP3_OUTSTATIONCHANNEL_STATES_H + +#include "opendnp3/outstation/OutstationSeqNum.h" +#include "opendnp3/app/TxBuffer.h" + +#include + +namespace opendnp3 +{ + +class OutstationSolState : private openpal::Uncopyable +{ +public: + + OutstationSolState(uint32_t maxTxSize) : tx(maxTxSize) + {} + + void Reset() {} + + OutstationSeqNum seq; + TxBuffer tx; +}; + +class OutstationUnsolState : private openpal::Uncopyable +{ +public: + + OutstationUnsolState(uint32_t maxTxSize) : + completedNull(false), + tx(maxTxSize) + {} + + void Reset() + { + completedNull = false; + } + + bool completedNull; + OutstationSeqNum seq; + TxBuffer tx; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.cpp new file mode 100644 index 0000000..cbce8cd --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.cpp @@ -0,0 +1,736 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "OutstationContext.h" + +#include "opendnp3/LogLevels.h" + +#include "opendnp3/app/parsing/APDUParser.h" +#include "opendnp3/app/parsing/APDUHeaderParser.h" + +#include "opendnp3/app/Functions.h" +#include "opendnp3/app/APDULogging.h" +#include "opendnp3/app/APDUBuilders.h" + +#include "opendnp3/outstation/ReadHandler.h" +#include "opendnp3/outstation/WriteHandler.h" +#include "opendnp3/outstation/IINHelpers.h" +#include "opendnp3/outstation/CommandActionAdapter.h" +#include "opendnp3/outstation/CommandResponseHandler.h" +#include "opendnp3/outstation/ConstantCommandAction.h" +#include "opendnp3/outstation/EventWriter.h" + +#include "opendnp3/outstation/ClassBasedRequestHandler.h" +#include "opendnp3/outstation/AssignClassHandler.h" + +#include + +using namespace openpal; + +namespace opendnp3 +{ + +OContext::OContext( + const OutstationConfig& config, + const DatabaseSizes& dbSizes, + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& lower, + const std::shared_ptr& commandHandler, + const std::shared_ptr& application) : + + logger(logger), + executor(executor), + lower(lower), + commandHandler(commandHandler), + application(application), + eventBuffer(config.eventBufferConfig), + database(dbSizes, eventBuffer, config.params.indexMode, config.params.typesAllowedInClass0), + rspContext(database.GetResponseLoader(), eventBuffer), + params(config.params), + isOnline(false), + isTransmitting(false), + staticIIN(IINBit::DEVICE_RESTART), + confirmTimer(*executor), + deferred(config.params.maxRxFragSize), + sol(config.params.maxTxFragSize), + unsol(config.params.maxTxFragSize) +{ + +} + +bool OContext::OnLowerLayerUp() +{ + if (isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "already online"); + return false; + } + + isOnline = true; + this->CheckForTaskStart(); + return true; +} + +bool OContext::OnLowerLayerDown() +{ + if (!isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "already offline"); + return false; + } + + this->state = &StateIdle::Inst(); + + isOnline = false; + isTransmitting = false; + + sol.Reset(); + unsol.Reset(); + history.Reset(); + deferred.Reset(); + eventBuffer.Unselect(); + rspContext.Reset(); + confirmTimer.Cancel(); + + return true; +} + +bool OContext::OnSendResult(bool isSuccess) +{ + if (!isOnline || !isTransmitting) + { + return false; + } + + this->isTransmitting = false; + this->CheckForTaskStart(); + return true; +} + +bool OContext::OnReceive(const openpal::RSlice& fragment) +{ + if (!this->isOnline) + { + SIMPLE_LOG_BLOCK(this->logger, flags::ERR, "ignoring received data while offline"); + return false; + } + + this->ParseHeader(fragment); + this->CheckForTaskStart(); + return true; +} + +OutstationState& OContext::OnReceiveSolRequest(const APDUHeader& header, const openpal::RSlice& objects) +{ + // analyze this request to see how it compares to the last request + if (this->history.HasLastRequest()) + { + if (this->sol.seq.num.Equals(header.control.SEQ)) + { + if (this->history.FullyEqualsLastRequest(header, objects)) + { + if (header.function == FunctionCode::READ) + { + return this->state->OnRepeatReadRequest(*this, header, objects); + } + else + { + return this->state->OnRepeatNonReadRequest(*this, header, objects); + } + } + else // new operation with same SEQ + { + return this->ProcessNewRequest(header, objects); + } + } + else // completely new sequence # + { + return this->ProcessNewRequest(header, objects); + } + } + else + { + return this->ProcessNewRequest(header, objects); + } +} + +OutstationState& OContext::ProcessNewRequest(const APDUHeader& header, const openpal::RSlice& objects) +{ + this->sol.seq.num = header.control.SEQ; + + if (header.function == FunctionCode::READ) + { + return this->state->OnNewReadRequest(*this, header, objects); + } + else + { + return this->state->OnNewNonReadRequest(*this, header, objects); + } +} + +void OContext::ProcessAPDU(const openpal::RSlice& apdu, const APDUHeader& header, const openpal::RSlice& objects) +{ + if (Functions::IsNoAckFuncCode(header.function)) + { + // this is the only request we process while we are transmitting + // because it doesn't require a response of any kind + this->ProcessRequestNoAck(header, objects); + } + else + { + if (this->isTransmitting) + { + this->deferred.Set(header, objects); + } + else + { + if (header.function == FunctionCode::CONFIRM) + { + this->ProcessConfirm(header); + } + else + { + this->ProcessRequest(header, objects); + } + } + } +} + + +void OContext::ProcessRequest(const APDUHeader& header, const openpal::RSlice& objects) +{ + if (header.control.UNS) + { + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Ignoring unsol with invalid function code: %s", FunctionCodeToString(header.function)); + } + else + { + this->state = &this->OnReceiveSolRequest(header, objects); + } +} + +void OContext::ProcessConfirm(const APDUHeader& header) +{ + this->state = &this->state->OnConfirm(*this, header); +} + +void OContext::BeginResponseTx(const AppControlField& control, const RSlice& response) +{ + this->sol.tx.Record(control, response); + this->BeginTx(response); +} + +void OContext::BeginUnsolTx(const AppControlField& control, const RSlice& response) +{ + this->unsol.tx.Record(control, response); + this->unsol.seq.confirmNum = this->unsol.seq.num; + this->unsol.seq.num.Increment(); + this->BeginTx(response); +} + +void OContext::BeginTx(const openpal::RSlice& response) +{ + logging::ParseAndLogResponseTx(this->logger, response); + this->isTransmitting = true; + this->lower->BeginTransmit(response); +} + +void OContext::CheckForDeferredRequest() +{ + if (this->CanTransmit() && this->deferred.IsSet()) + { + auto handler = [this](const APDUHeader & header, const RSlice & objects) + { + return this->ProcessDeferredRequest(header, objects); + }; + this->deferred.Process(handler); + } +} + +bool OContext::ProcessDeferredRequest(APDUHeader header, openpal::RSlice objects) +{ + if (header.function == FunctionCode::CONFIRM) + { + this->ProcessConfirm(header); + return true; + } + else + { + if (header.function == FunctionCode::READ) + { + if (this->state->IsIdle()) + { + this->ProcessRequest(header, objects); + return true; + } + else + { + return false; + } + } + else + { + this->ProcessRequest(header, objects); + return true; + } + } +} + +void OContext::CheckForUnsolicited() +{ + if (this->CanTransmit() && this->state->IsIdle() && this->params.allowUnsolicited) + { + if (this->unsol.completedNull) + { + // are there events to be reported? + if (this->params.unsolClassMask.Intersects(this->eventBuffer.UnwrittenClassField())) + { + + auto response = this->unsol.tx.Start(); + auto writer = response.GetWriter(); + + this->eventBuffer.Unselect(); + this->eventBuffer.SelectAllByClass(this->params.unsolClassMask); + this->eventBuffer.Load(writer); + + build::NullUnsolicited(response, this->unsol.seq.num, this->GetResponseIIN()); + this->RestartConfirmTimer(); + this->state = &StateUnsolicitedConfirmWait::Inst(); + this->BeginUnsolTx(response.GetControl(), response.ToRSlice()); + } + } + else + { + // send a NULL unsolcited message + auto response = this->unsol.tx.Start(); + build::NullUnsolicited(response, this->unsol.seq.num, this->GetResponseIIN()); + this->RestartConfirmTimer(); + this->state = &StateUnsolicitedConfirmWait::Inst(); + this->BeginUnsolTx(response.GetControl(), response.ToRSlice()); + } + } +} + +void OContext::RestartConfirmTimer() +{ + auto timeout = [&]() + { + this->state = &this->state->OnConfirmTimeout(*this); + this->CheckForTaskStart(); + }; + + this->confirmTimer.Restart(this->params.unsolConfirmTimeout, timeout); +} + +void OContext::RespondToNonReadRequest(const APDUHeader& header, const openpal::RSlice& objects) +{ + this->history.RecordLastProcessedRequest(header, objects); + + auto response = this->sol.tx.Start(); + auto writer = response.GetWriter(); + response.SetFunction(FunctionCode::RESPONSE); + response.SetControl(AppControlField(true, true, false, false, header.control.SEQ)); + auto iin = this->HandleNonReadResponse(header, objects, writer); + response.SetIIN(iin | this->GetResponseIIN()); + this->BeginResponseTx(response.GetControl(), response.ToRSlice()); +} + +OutstationState& OContext::RespondToReadRequest(const APDUHeader& header, const openpal::RSlice& objects) +{ + this->history.RecordLastProcessedRequest(header, objects); + + auto response = this->sol.tx.Start(); + auto writer = response.GetWriter(); + response.SetFunction(FunctionCode::RESPONSE); + auto result = this->HandleRead(objects, writer); + result.second.SEQ = header.control.SEQ; + this->sol.seq.confirmNum = header.control.SEQ; + response.SetControl(result.second); + response.SetIIN(result.first | this->GetResponseIIN()); + this->BeginResponseTx(response.GetControl(), response.ToRSlice()); + + if (result.second.CON) + { + this->RestartConfirmTimer(); + return StateSolicitedConfirmWait::Inst(); + } + else + { + return StateIdle::Inst(); + } +} + +OutstationState& OContext::ContinueMultiFragResponse(const AppSeqNum& seq) +{ + auto response = this->sol.tx.Start(); + auto writer = response.GetWriter(); + response.SetFunction(FunctionCode::RESPONSE); + auto control = this->rspContext.LoadResponse(writer); + control.SEQ = seq; + this->sol.seq.confirmNum = seq; + response.SetControl(control); + response.SetIIN(this->GetResponseIIN()); + this->BeginResponseTx(response.GetControl(), response.ToRSlice()); + + if (control.CON) + { + this->RestartConfirmTimer(); + return StateSolicitedConfirmWait::Inst(); + } + else + { + return StateIdle::Inst(); + } +} + +bool OContext::CanTransmit() const +{ + return isOnline && !isTransmitting; +} + +IINField OContext::GetResponseIIN() +{ + return this->staticIIN | this->GetDynamicIIN() | this->application->GetApplicationIIN().ToIIN(); +} + +IINField OContext::GetDynamicIIN() +{ + auto classField = this->eventBuffer.UnwrittenClassField(); + + IINField ret; + ret.SetBitToValue(IINBit::CLASS1_EVENTS, classField.HasClass1()); + ret.SetBitToValue(IINBit::CLASS2_EVENTS, classField.HasClass2()); + ret.SetBitToValue(IINBit::CLASS3_EVENTS, classField.HasClass3()); + ret.SetBitToValue(IINBit::EVENT_BUFFER_OVERFLOW, this->eventBuffer.IsOverflown()); + + return ret; +} + +void OContext::ParseHeader(const openpal::RSlice& apdu) +{ + FORMAT_HEX_BLOCK(this->logger, flags::APP_HEX_RX, apdu, 18, 18); + + APDUHeader header; + if (!APDUHeaderParser::ParseRequest(apdu, header, &this->logger)) + { + return; + } + + FORMAT_LOG_BLOCK(this->logger, flags::APP_HEADER_RX, + "FIR: %i FIN: %i CON: %i UNS: %i SEQ: %i FUNC: %s", + header.control.FIR, + header.control.FIN, + header.control.CON, + header.control.UNS, + header.control.SEQ, + FunctionCodeToString(header.function)); + + // outstations should only process single fragment messages that don't request confirmation + if (!header.control.IsFirAndFin() || header.control.CON) + { + SIMPLE_LOG_BLOCK(this->logger, flags::WARN, "Ignoring fragment. Request must be FIR/FIN/!CON"); + return; + } + + auto objects = apdu.Skip(APDU_REQUEST_HEADER_SIZE); + + this->ProcessAPDU(apdu, header, objects); +} + +void OContext::CheckForTaskStart() +{ + // do these checks in order of priority + this->CheckForDeferredRequest(); + this->CheckForUnsolicited(); +} + +void OContext::SetRestartIIN() +{ + this->staticIIN.SetBit(IINBit::DEVICE_RESTART); +} + +IUpdateHandler& OContext::GetUpdateHandler() +{ + return this->database; +} + +DatabaseConfigView OContext::GetConfigView() +{ + return this->database.GetConfigView(); +} + +//// ----------------------------- function handlers ----------------------------- + +void OContext::ProcessRequestNoAck(const APDUHeader& header, const openpal::RSlice& objects) +{ + switch (header.function) + { + case(FunctionCode::DIRECT_OPERATE_NR) : + this->HandleDirectOperate(objects, OperateType::DirectOperateNoAck, nullptr); // no object writer, this is a no ack code + break; + default: + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Ignoring NR function code: %s", FunctionCodeToString(header.function)); + break; + } +} + +IINField OContext::HandleNonReadResponse(const APDUHeader& header, const openpal::RSlice& objects, HeaderWriter& writer) +{ + switch (header.function) + { + case(FunctionCode::WRITE) : + return this->HandleWrite(objects); + case(FunctionCode::SELECT) : + return this->HandleSelect(objects, writer); + case(FunctionCode::OPERATE) : + return this->HandleOperate(objects, writer); + case(FunctionCode::DIRECT_OPERATE) : + return this->HandleDirectOperate(objects, OperateType::DirectOperate, &writer); + case(FunctionCode::COLD_RESTART) : + return this->HandleRestart(objects, false, &writer); + case(FunctionCode::WARM_RESTART) : + return this->HandleRestart(objects, true, &writer); + case(FunctionCode::ASSIGN_CLASS) : + return this->HandleAssignClass(objects); + case(FunctionCode::DELAY_MEASURE) : + return this->HandleDelayMeasure(objects, writer); + case(FunctionCode::DISABLE_UNSOLICITED) : + return this->params.allowUnsolicited ? this->HandleDisableUnsolicited(objects, writer) : IINField(IINBit::FUNC_NOT_SUPPORTED); + case(FunctionCode::ENABLE_UNSOLICITED) : + return this->params.allowUnsolicited ? this->HandleEnableUnsolicited(objects, writer) : IINField(IINBit::FUNC_NOT_SUPPORTED); + default: + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } +} + +Pair OContext::HandleRead(const openpal::RSlice& objects, HeaderWriter& writer) +{ + this->rspContext.Reset(); + this->eventBuffer.Unselect(); // always un-select any previously selected points when we start a new read request + this->database.GetStaticSelector().Unselect(); + + ReadHandler handler(this->database.GetStaticSelector(), this->eventBuffer); + auto result = APDUParser::Parse(objects, handler, &this->logger, ParserSettings::NoContents()); // don't expect range/count context on a READ + if (result == ParseResult::OK) + { + auto control = this->rspContext.LoadResponse(writer); + return Pair(handler.Errors(), control); + } + else + { + this->rspContext.Reset(); + return Pair(IINFromParseResult(result), AppControlField(true, true, false, false)); + } +} + +IINField OContext::HandleWrite(const openpal::RSlice& objects) +{ + WriteHandler handler(*this->application, &this->staticIIN); + auto result = APDUParser::Parse(objects, handler, &this->logger); + return (result == ParseResult::OK) ? handler.Errors() : IINFromParseResult(result); +} + +IINField OContext::HandleDirectOperate(const openpal::RSlice& objects, OperateType opType, HeaderWriter* pWriter) +{ + // since we're echoing, make sure there's enough size before beginning + if (pWriter && (objects.Size() > pWriter->Remaining())) + { + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Igonring command request due to oversized payload size of %u", objects.Size()); + return IINField(IINBit::PARAM_ERROR); + } + else + { + CommandActionAdapter adapter(this->commandHandler.get(), false, opType); + CommandResponseHandler handler(this->params.maxControlsPerRequest, &adapter, pWriter); + auto result = APDUParser::Parse(objects, handler, &this->logger); + return (result == ParseResult::OK) ? handler.Errors() : IINFromParseResult(result); + } +} + +IINField OContext::HandleSelect(const openpal::RSlice& objects, HeaderWriter& writer) +{ + // since we're echoing, make sure there's enough size before beginning + if (objects.Size() > writer.Remaining()) + { + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Igonring command request due to oversized payload size of %i", objects.Size()); + return IINField(IINBit::PARAM_ERROR); + } + else + { + // the 'OperateType' is just ignored since it's a select + CommandActionAdapter adapter(this->commandHandler.get(), true, OperateType::DirectOperate); + CommandResponseHandler handler(this->params.maxControlsPerRequest, &adapter, &writer); + auto result = APDUParser::Parse(objects, handler, &this->logger); + if (result == ParseResult::OK) + { + if (handler.AllCommandsSuccessful()) + { + this->control.Select(this->sol.seq.num, this->executor->GetTime(), objects); + } + + return handler.Errors(); + } + else + { + return IINFromParseResult(result); + } + } +} + +IINField OContext::HandleOperate(const openpal::RSlice& objects, HeaderWriter& writer) +{ + // since we're echoing, make sure there's enough size before beginning + if (objects.Size() > writer.Remaining()) + { + FORMAT_LOG_BLOCK(this->logger, flags::WARN, "Igonring command request due to oversized payload size of %i", objects.Size()); + return IINField(IINBit::PARAM_ERROR); + } + else + { + auto now = this->executor->GetTime(); + auto result = this->control.ValidateSelection(this->sol.seq.num, now, this->params.selectTimeout, objects); + + if (result == CommandStatus::SUCCESS) + { + CommandActionAdapter adapter(this->commandHandler.get(), false, OperateType::SelectBeforeOperate); + CommandResponseHandler handler(this->params.maxControlsPerRequest, &adapter, &writer); + auto result = APDUParser::Parse(objects, handler, &this->logger); + return (result == ParseResult::OK) ? handler.Errors() : IINFromParseResult(result); + } + else + { + return this->HandleCommandWithConstant(objects, writer, result); + } + } +} + +IINField OContext::HandleDelayMeasure(const openpal::RSlice& objects, HeaderWriter& writer) +{ + if (objects.IsEmpty()) + { + Group52Var2 value; + value.time = 0; // respond with 0 time delay + writer.WriteSingleValue(QualifierCode::UINT8_CNT, value); + return IINField::Empty(); + } + else + { + // there shouldn't be any trailing headers in delay measure request, no need to even parse + return IINField(IINBit::PARAM_ERROR); + } +} + +IINField OContext::HandleRestart(const openpal::RSlice& objects, bool isWarmRestart, HeaderWriter* pWriter) +{ + if (objects.IsEmpty()) + { + auto mode = isWarmRestart ? this->application->WarmRestartSupport() : this->application->ColdRestartSupport(); + + switch (mode) + { + case(RestartMode::UNSUPPORTED) : + return IINField(IINBit::FUNC_NOT_SUPPORTED); + case(RestartMode::SUPPORTED_DELAY_COARSE) : + { + auto delay = isWarmRestart ? this->application->WarmRestart() : this->application->ColdRestart(); + if (pWriter) + { + Group52Var1 coarse; + coarse.time = delay; + pWriter->WriteSingleValue(QualifierCode::UINT8_CNT, coarse); + } + return IINField::Empty(); + } + default: + { + auto delay = isWarmRestart ? this->application->WarmRestart() : this->application->ColdRestart(); + if (pWriter) + { + Group52Var2 fine; + fine.time = delay; + pWriter->WriteSingleValue(QualifierCode::UINT8_CNT, fine); + } + return IINField::Empty(); + } + } + } + else + { + // there shouldn't be any trailing headers in restart requests, no need to even parse + return IINField(IINBit::PARAM_ERROR); + } +} + +IINField OContext::HandleAssignClass(const openpal::RSlice& objects) +{ + if (this->application->SupportsAssignClass()) + { + AssignClassHandler handler(*this->executor, *this->application, this->database.GetClassAssigner()); + auto result = APDUParser::Parse(objects, handler, &this->logger, ParserSettings::NoContents()); + return (result == ParseResult::OK) ? handler.Errors() : IINFromParseResult(result); + } + else + { + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } +} + +IINField OContext::HandleDisableUnsolicited(const openpal::RSlice& objects, HeaderWriter& writer) +{ + ClassBasedRequestHandler handler; + auto result = APDUParser::Parse(objects, handler, &this->logger); + if (result == ParseResult::OK) + { + this->params.unsolClassMask.Clear(handler.GetClassField()); + return handler.Errors(); + } + else + { + return IINFromParseResult(result); + } +} + +IINField OContext::HandleEnableUnsolicited(const openpal::RSlice& objects, HeaderWriter& writer) +{ + ClassBasedRequestHandler handler; + auto result = APDUParser::Parse(objects, handler, &this->logger); + if (result == ParseResult::OK) + { + this->params.unsolClassMask.Set(handler.GetClassField()); + return handler.Errors(); + } + else + { + return IINFromParseResult(result); + } +} + +IINField OContext::HandleCommandWithConstant(const openpal::RSlice& objects, HeaderWriter& writer, CommandStatus status) +{ + ConstantCommandAction constant(status); + CommandResponseHandler handler(this->params.maxControlsPerRequest, &constant, &writer); + auto result = APDUParser::Parse(objects, handler, &this->logger); + return IINFromParseResult(result); +} + + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.h new file mode 100644 index 0000000..160e154 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationContext.h @@ -0,0 +1,194 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONCONTEXT_H +#define OPENDNP3_OUTSTATIONCONTEXT_H + +#include "opendnp3/LayerInterfaces.h" + +#include "opendnp3/gen/SecurityStatIndex.h" + +#include "opendnp3/outstation/OutstationConfig.h" +#include "opendnp3/outstation/RequestHistory.h" +#include "opendnp3/outstation/DeferredRequest.h" +#include "opendnp3/outstation/OutstationChannelStates.h" +#include "opendnp3/outstation/ControlState.h" +#include "opendnp3/outstation/OutstationSeqNum.h" +#include "opendnp3/outstation/Database.h" +#include "opendnp3/outstation/EventBuffer.h" +#include "opendnp3/outstation/ResponseContext.h" +#include "opendnp3/outstation/ICommandHandler.h" +#include "opendnp3/outstation/IOutstationApplication.h" +#include "opendnp3/outstation/OutstationStates.h" + +#include +#include +#include + +namespace opendnp3 +{ + +/// +/// Represent all of the mutable state in an outstation +/// +class OContext : public IUpperLayer +{ + friend class StateIdle; + friend class StateSolicitedConfirmWait; + friend class StateUnsolicitedConfirmWait; + +public: + + OContext( const OutstationConfig& config, + const DatabaseSizes& dbSizes, + const openpal::Logger& logger, + const std::shared_ptr& executor, + const std::shared_ptr& lower, + const std::shared_ptr& commandHandler, + const std::shared_ptr& application); + + /// ----- Implement IUpperLayer ------ + + virtual bool OnLowerLayerUp() override; + + virtual bool OnLowerLayerDown() override; + + virtual bool OnSendResult(bool isSuccess) override final; + + virtual bool OnReceive(const openpal::RSlice& fragment) override final; + + /// --- Other public members ---- + + void CheckForTaskStart(); + + IUpdateHandler& GetUpdateHandler(); + + DatabaseConfigView GetConfigView(); + + void SetRestartIIN(); + +private: + + /// ---- Helper functions that operate on the current state, and may return a new state ---- + + OutstationState& ContinueMultiFragResponse(const AppSeqNum& seq); + + OutstationState& RespondToReadRequest(const APDUHeader& header, const openpal::RSlice& objects); + + OutstationState& ProcessNewRequest(const APDUHeader& header, const openpal::RSlice& objects); + + OutstationState& OnReceiveSolRequest(const APDUHeader& header, const openpal::RSlice& objects); + + void RespondToNonReadRequest(const APDUHeader& header, const openpal::RSlice& objects); + + /// ---- Processing functions -------- + + void ProcessAPDU(const openpal::RSlice& apdu, const APDUHeader& header, const openpal::RSlice& objects); + + void ProcessRequest(const APDUHeader& header, const openpal::RSlice& objects); + + void ProcessConfirm(const APDUHeader& header); + + /// ---- common helper methods ---- + + void ParseHeader(const openpal::RSlice& apdu); + + void BeginResponseTx(const AppControlField& control, const openpal::RSlice& response); + + void BeginUnsolTx(const AppControlField& control, const openpal::RSlice& response); + + void BeginTx(const openpal::RSlice& response); + + void CheckForDeferredRequest(); + + bool ProcessDeferredRequest(APDUHeader header, openpal::RSlice objects); + + void RestartConfirmTimer(); + + void CheckForUnsolicited(); + + bool CanTransmit() const; + + IINField GetResponseIIN(); + + IINField GetDynamicIIN(); + + /// --- methods for handling app-layer functions --- + + /// Handles non-read function codes that require a response. builds the response using the supplied writer. + /// @return An IIN field indicating the validity of the request, and to be returned in the response. + IINField HandleNonReadResponse(const APDUHeader& header, const openpal::RSlice& objects, HeaderWriter& writer); + + /// Handles read function codes. May trigger an unsolicited response + /// @return an IIN field and a partial AppControlField (missing sequence info) + openpal::Pair HandleRead(const openpal::RSlice& objects, HeaderWriter& writer); + + /// Handles no-response function codes. + void ProcessRequestNoAck(const APDUHeader& header, const openpal::RSlice& objects); + + // ------ Function Handlers ------ + + IINField HandleWrite(const openpal::RSlice& objects); + IINField HandleSelect(const openpal::RSlice& objects, HeaderWriter& writer); + IINField HandleOperate(const openpal::RSlice& objects, HeaderWriter& writer); + IINField HandleDirectOperate(const openpal::RSlice& objects, OperateType opType, HeaderWriter* pWriter); + IINField HandleDelayMeasure(const openpal::RSlice& objects, HeaderWriter& writer); + IINField HandleRestart(const openpal::RSlice& objects, bool isWarmRestart, HeaderWriter* pWriter); + IINField HandleAssignClass(const openpal::RSlice& objects); + IINField HandleDisableUnsolicited(const openpal::RSlice& objects, HeaderWriter& writer); + IINField HandleEnableUnsolicited(const openpal::RSlice& objects, HeaderWriter& writer); + IINField HandleCommandWithConstant(const openpal::RSlice& objects, HeaderWriter& writer, CommandStatus status); + + // ------ resources -------- + openpal::Logger logger; + const std::shared_ptr executor; + const std::shared_ptr lower; + const std::shared_ptr commandHandler; + const std::shared_ptr application; + + // ------ Database, event buffer, and response tracking + EventBuffer eventBuffer; + Database database; + ResponseContext rspContext; + + // ------ Static configuration ------- + OutstationParams params; + + // ------ Shared dynamic state -------- + bool isOnline; + bool isTransmitting; + IINField staticIIN; + openpal::TimerRef confirmTimer; + RequestHistory history; + DeferredRequest deferred; + + // ------ Dynamic state related to controls ------ + ControlState control; + + // ------ Dynamic state related to solicited and unsolicited modes ------ + OutstationSolState sol; + OutstationUnsolState unsol; + OutstationState* state = &StateIdle::Inst(); +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationSeqNum.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationSeqNum.h new file mode 100644 index 0000000..66cd379 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationSeqNum.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONSEQNUM_H +#define OPENDNP3_OUTSTATIONSEQNUM_H + +#include + +#include "opendnp3/app/AppSeqNum.h" + +namespace opendnp3 +{ + +/// +/// Sequence numbers for one channel (sol or unsol) +/// +class OutstationSeqNum +{ +public: + + OutstationSeqNum() + {} + + AppSeqNum num; + AppSeqNum confirmNum; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.cpp new file mode 100644 index 0000000..40eb689 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.cpp @@ -0,0 +1,217 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "opendnp3/outstation/OutstationStates.h" + +#include "opendnp3/outstation/OutstationContext.h" + +#include "opendnp3/LogLevels.h" + +#include "openpal/logging/LogMacros.h" + +namespace opendnp3 +{ + + +// ------------- StateIdle ---------------- + +StateIdle StateIdle::instance; + +OutstationState& StateIdle::OnConfirm(OContext& ctx, const APDUHeader& header) +{ + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "unexpected confirm while IDLE with sequence: %u", header.control.SEQ); + return StateIdle::Inst(); +} + +OutstationState& StateIdle::OnConfirmTimeout(OContext& ctx) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "unexpected confirm timeout"); + return StateIdle::Inst(); +} + +OutstationState& StateIdle::OnNewReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + return ctx.RespondToReadRequest(header, objects); +} + +OutstationState& StateIdle::OnNewNonReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.RespondToNonReadRequest(header, objects); + return *this; +} + +OutstationState& StateIdle::OnRepeatNonReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.BeginResponseTx(ctx.sol.tx.GetLastControl(), ctx.sol.tx.GetLastResponse()); + return *this; +} + +OutstationState& StateIdle::OnRepeatReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.BeginResponseTx(ctx.sol.tx.GetLastControl(), ctx.sol.tx.GetLastResponse()); + return *this; +} + + +// ------------- StateSolicitedConfirmWait ---------------- + +StateSolicitedConfirmWait StateSolicitedConfirmWait::instance; + +OutstationState& StateSolicitedConfirmWait::OnConfirm(OContext& ctx, const APDUHeader& header) +{ + if (header.control.UNS) + { + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "received unsolicited confirm while waiting for solicited confirm (seq: %u)", header.control.SEQ); + return *this; + } + + if (!ctx.sol.seq.confirmNum.Equals(header.control.SEQ)) + { + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "solicited confirm with wrong seq: %u, expected: %u", header.control.SEQ, ctx.sol.seq.confirmNum.Get()); + return *this; + } + + ctx.history.Reset(); // any time we get a confirm we can treat any request as a new request + ctx.confirmTimer.Cancel(); + ctx.eventBuffer.ClearWritten(); + + if (ctx.rspContext.HasSelection()) + { + return ctx.ContinueMultiFragResponse(AppSeqNum(header.control.SEQ).Next()); + } + else + { + return StateIdle::Inst(); + } +} + +OutstationState& StateSolicitedConfirmWait::OnConfirmTimeout(OContext& ctx) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "solicited confirm timeout"); + return StateIdle::Inst(); +} + +OutstationState& StateSolicitedConfirmWait::OnNewReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.confirmTimer.Cancel(); + return ctx.RespondToReadRequest(header, objects); +} + +OutstationState& StateSolicitedConfirmWait::OnNewNonReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.confirmTimer.Cancel(); + ctx.RespondToNonReadRequest(header, objects); + return StateIdle::Inst(); +} + +OutstationState& StateSolicitedConfirmWait::OnRepeatNonReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.confirmTimer.Cancel(); + ctx.BeginResponseTx(ctx.sol.tx.GetLastControl(), ctx.sol.tx.GetLastResponse()); + return *this; +} + +OutstationState& StateSolicitedConfirmWait::OnRepeatReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.RestartConfirmTimer(); + ctx.BeginResponseTx(ctx.sol.tx.GetLastControl(), ctx.sol.tx.GetLastResponse()); + return *this; +} + + +// ------------- StateUnsolicitedConfirmWait ---------------- + +StateUnsolicitedConfirmWait StateUnsolicitedConfirmWait::instance; + +OutstationState& StateUnsolicitedConfirmWait::OnConfirm(OContext& ctx, const APDUHeader& header) +{ + if (!header.control.UNS) + { + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "received solicited confirm while waiting for unsolicited confirm (seq: %u)", header.control.SEQ); + return *this; + } + + if (!ctx.unsol.seq.confirmNum.Equals(header.control.SEQ)) + { + FORMAT_LOG_BLOCK(ctx.logger, flags::WARN, "unsolicited confirm with wrong seq: %u, expected: %u", header.control.SEQ, ctx.unsol.seq.confirmNum.Get()); + return *this; + } + + ctx.history.Reset(); // any time we get a confirm we can treat any request as a new request + ctx.confirmTimer.Cancel(); + + if (ctx.unsol.completedNull) + { + ctx.eventBuffer.ClearWritten(); + } + else + { + ctx.unsol.completedNull = true; + } + + return StateIdle::Inst(); +} + +OutstationState& StateUnsolicitedConfirmWait::OnConfirmTimeout(OContext& ctx) +{ + SIMPLE_LOG_BLOCK(ctx.logger, flags::WARN, "unsolicited confirm timeout"); + + if (ctx.unsol.completedNull) + { + ctx.eventBuffer.Unselect(); + } + + return StateIdle::Inst(); +} + +OutstationState& StateUnsolicitedConfirmWait::OnNewReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.deferred.Set(header, objects); + return *this; +} + +OutstationState& StateUnsolicitedConfirmWait::OnNewNonReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.deferred.Reset(); + ctx.RespondToNonReadRequest(header, objects); + return *this; +} + +OutstationState& StateUnsolicitedConfirmWait::OnRepeatNonReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.BeginResponseTx(ctx.sol.tx.GetLastControl(), ctx.sol.tx.GetLastResponse()); + return *this; +} + +OutstationState& StateUnsolicitedConfirmWait::OnRepeatReadRequest(OContext& ctx, const APDUHeader& header, const openpal::RSlice& objects) +{ + ctx.deferred.Set(header, objects); + return *this; +} + + + +} //end ns + + + + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.h new file mode 100644 index 0000000..47cce0a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/OutstationStates.h @@ -0,0 +1,184 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_OUTSTATIONSTATES_H +#define OPENDNP3_OUTSTATIONSTATES_H + +#include "opendnp3/app/APDUHeader.h" + +#include +#include + +namespace opendnp3 +{ + +class OContext; + +/** + * Base class for the outstation states + */ +class OutstationState : private openpal::Uncopyable +{ +public: + + virtual bool IsIdle() + { + return false; + } + + virtual const char* Name() = 0; + + virtual OutstationState& OnConfirm(OContext&, const APDUHeader& header) = 0; + + virtual OutstationState& OnConfirmTimeout(OContext&) = 0; + + virtual OutstationState& OnNewReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) = 0; + + virtual OutstationState& OnNewNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) = 0; + + virtual OutstationState& OnRepeatNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) = 0; + + virtual OutstationState& OnRepeatReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) = 0; + + + +}; + +class StateIdle final : public OutstationState +{ + +public: + + virtual bool IsIdle() override + { + return true; + } + + virtual const char* Name() override + { + return "Idle"; + } + + inline static OutstationState& Inst() + { + return instance; + } + + virtual OutstationState& OnConfirm(OContext&, const APDUHeader& header) override; + + virtual OutstationState& OnConfirmTimeout(OContext&) override; + + virtual OutstationState& OnNewReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnNewNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnRepeatNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnRepeatReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + +private: + + static StateIdle instance; + + StateIdle() {} + +}; + + +/* +* waiting for a confirm to a solicited read response +*/ +class StateSolicitedConfirmWait final : public OutstationState +{ + +public: + + inline static OutstationState& Inst() + { + return instance; + } + + virtual const char* Name() override + { + return "SolicitedConfirmWait"; + } + + virtual OutstationState& OnConfirm(OContext&, const APDUHeader& header) override; + + virtual OutstationState& OnConfirmTimeout(OContext&) override; + + virtual OutstationState& OnNewReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnNewNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnRepeatNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnRepeatReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + +private: + + static StateSolicitedConfirmWait instance; + + StateSolicitedConfirmWait() {} +}; + +/* +* waiting for a confirm to an unsolicited read response +*/ +class StateUnsolicitedConfirmWait final : public OutstationState +{ + +public: + + inline static OutstationState& Inst() + { + return instance; + } + + virtual const char* Name() override + { + return "UnsolicitedConfirmWait"; + } + + virtual OutstationState& OnConfirm(OContext&, const APDUHeader& header) override; + + virtual OutstationState& OnConfirmTimeout(OContext&) override; + + virtual OutstationState& OnNewReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnNewNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnRepeatNonReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + + virtual OutstationState& OnRepeatReadRequest(OContext&, const APDUHeader& header, const openpal::RSlice& objects) override; + +private: + + static StateUnsolicitedConfirmWait instance; + + StateUnsolicitedConfirmWait() {} +}; + +} //ens ns + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.cpp new file mode 100644 index 0000000..2ffef97 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.cpp @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ReadHandler.h" + +namespace opendnp3 +{ + +ReadHandler::ReadHandler(IStaticSelector& staticSelector, IEventSelector& eventSelector) : + pStaticSelector(&staticSelector), + pEventSelector(&eventSelector) +{ + +} + +IINField ReadHandler::ProcessHeader(const AllObjectsHeader& header) +{ + switch (header.type) + { + case(GroupVariationType::STATIC) : + return pStaticSelector->SelectAll(header.enumeration); + case(GroupVariationType::EVENT) : + return pEventSelector->SelectAll(header.enumeration); + default: + return IINField(IINBit::FUNC_NOT_SUPPORTED); + } +} + +IINField ReadHandler::ProcessHeader(const RangeHeader& header) +{ + return pStaticSelector->SelectRange(header.enumeration, header.range); +} + +IINField ReadHandler::ProcessHeader(const CountHeader& header) +{ + return pEventSelector->SelectCount(header.enumeration, header.count); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.h new file mode 100644 index 0000000..006ed05 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ReadHandler.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_READHANDLER_H +#define OPENDNP3_READHANDLER_H + + +#include "opendnp3/app/parsing/IAPDUHandler.h" + +#include "opendnp3/outstation/IEventSelector.h" +#include "opendnp3/outstation/IStaticSelector.h" +#include "opendnp3/outstation/StaticTypeBitfield.h" + +#include + +namespace opendnp3 +{ + +class ReadHandler : public IAPDUHandler +{ +public: + + ReadHandler(IStaticSelector& staticSelector, IEventSelector& eventSelector); + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final + { + return true; + } + +private: + + virtual IINField ProcessHeader(const AllObjectsHeader& header) override final; + + virtual IINField ProcessHeader(const RangeHeader& header) override final; + + virtual IINField ProcessHeader(const CountHeader& header) override final; + + IStaticSelector* pStaticSelector; + IEventSelector* pEventSelector; + +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.cpp new file mode 100644 index 0000000..a4d1435 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.cpp @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "RequestHistory.h" + +#include "opendnp3/link/CRC.h" + +namespace opendnp3 +{ + +RequestHistory::RequestHistory() : + hasLast(false), + lastDigest(0), + lastObjectsLength(0) +{ + +} + +void RequestHistory::Reset() +{ + hasLast = false; +} + +void RequestHistory::RecordLastProcessedRequest(const APDUHeader& header, const openpal::RSlice& objects) +{ + hasLast = true; + lastHeader = header; + lastObjectsLength = objects.Size(); + lastDigest = CRC::CalcCrc(objects); +} + +bool RequestHistory::FullyEqualsLastRequest(const APDUHeader& header, const openpal::RSlice& objects) const +{ + return lastHeader.Equals(header) && EqualsLastObjects(objects); +} + +APDUHeader RequestHistory::GetLastHeader() const +{ + return hasLast ? lastHeader : APDUHeader(); +} + +bool RequestHistory::EqualsLastObjects(const openpal::RSlice& objects) const +{ + + return hasLast && + (lastObjectsLength == objects.Size()) && + (lastDigest == CRC::CalcCrc(objects)); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.h new file mode 100644 index 0000000..421177c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/RequestHistory.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_REQUESTHISTORY_H +#define OPENDNP3_REQUESTHISTORY_H + +#include + +#include "opendnp3/app/APDUHeader.h" + +#include + + +namespace opendnp3 +{ + +/// Tracks the state of the last request ASDU +class RequestHistory +{ +public: + + RequestHistory(); + + bool HasLastRequest() const + { + return hasLast; + } + + void Reset(); + void RecordLastProcessedRequest(const APDUHeader& header, const openpal::RSlice& objects); + + APDUHeader GetLastHeader() const; + bool EqualsLastObjects(const openpal::RSlice& objects) const; + bool FullyEqualsLastRequest(const APDUHeader& header, const openpal::RSlice& objects) const; + +private: + + bool hasLast; + APDUHeader lastHeader; + uint16_t lastDigest; + uint32_t lastObjectsLength; +}; + + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.cpp new file mode 100644 index 0000000..ab1cd50 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.cpp @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ResponseContext.h" + +namespace opendnp3 +{ + +ResponseContext::ResponseContext(IResponseLoader& staticLoader, IResponseLoader& eventLoader) : + fragmentCount(0), + pStaticLoader(&staticLoader), + pEventLoader(&eventLoader) +{ + +} + +bool ResponseContext::HasSelection() const +{ + return pStaticLoader->HasAnySelection() || pEventLoader->HasAnySelection(); +} + +void ResponseContext::Reset() +{ + fragmentCount = 0; +} + +AppControlField ResponseContext::LoadResponse(HeaderWriter& writer) +{ + bool fir = fragmentCount == 0; + ++fragmentCount; + + uint32_t startingSize = writer.Remaining(); + bool notFull = pEventLoader->Load(writer); + bool someEventsWritten = writer.Remaining() < startingSize; + + if (notFull) + { + auto fin = pStaticLoader->Load(writer); + auto con = !fin || someEventsWritten; + return AppControlField(fir, fin, con, false); + } + else + { + return AppControlField(fir, false, true, false); + } +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.h new file mode 100644 index 0000000..a23bc1f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/ResponseContext.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_RESPONSECONTEXT_H +#define OPENDNP3_RESPONSECONTEXT_H + +#include + +#include "opendnp3/app/Range.h" +#include "opendnp3/app/HeaderWriter.h" +#include "opendnp3/app/AppControlField.h" +#include "opendnp3/outstation/IResponseLoader.h" + + + +namespace opendnp3 +{ + +class Database; + +/** + * Coordinates the event & static response contexts to do multi-fragments responses + */ +class ResponseContext : private openpal::Uncopyable +{ + +public: + + ResponseContext(IResponseLoader& staticLoader, IResponseLoader& eventLoader); + + bool HasSelection() const; + + void Reset(); + + AppControlField LoadResponse(HeaderWriter& writer); + +private: + + static AppControlField GetControl(bool fir, bool fin, bool hasEvents); + + uint16_t fragmentCount; + IResponseLoader* pStaticLoader; + IResponseLoader* pEventLoader; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.cpp new file mode 100644 index 0000000..8e4c477 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.cpp @@ -0,0 +1,220 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "SOERecord.h" + +namespace opendnp3 +{ + +SOERecord::SOERecord() : SOERecord(EventType::Analog, EventClass::EC1, 0, DNPTime(0), 0) +{} + +SOERecord::SOERecord(EventType type, EventClass clazz, uint16_t index, DNPTime time, uint8_t flags) : + type(type), + clazz(clazz), + selected(false), + written(false), + index(index), + time(time), + flags(flags) +{} + +void SOERecord::Reset() +{ + selected = written = false; +} + +void SOERecord::SelectDefault() +{ + selected = true; + switch (type) + { + case(EventType::Binary) : + value.binary.SelectDefaultVariation(); + break; + case(EventType::DoubleBitBinary) : + value.doubleBinary.SelectDefaultVariation(); + break; + case(EventType::Counter) : + value.counter.SelectDefaultVariation(); + break; + case(EventType::FrozenCounter) : + value.frozenCounter.SelectDefaultVariation(); + break; + case(EventType::Analog) : + value.analog.SelectDefaultVariation(); + break; + case(EventType::BinaryOutputStatus) : + value.binaryOutputStatus.SelectDefaultVariation(); + break; + case(EventType::AnalogOutputStatus) : + value.analogOutputStatus.SelectDefaultVariation(); + break; + case(EventType::SecurityStat) : + value.securityStat.SelectDefaultVariation(); + break; + } +} + +SOERecord::SOERecord(const Binary& meas, uint16_t index_, EventClass clazz_, EventBinaryVariation var) : + SOERecord(EventType::Binary, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.binary = ValueAndVariation { meas.value, var, var }; +} + +SOERecord::SOERecord(const DoubleBitBinary& meas, uint16_t index_, EventClass clazz_, EventDoubleBinaryVariation var) : + SOERecord(EventType::DoubleBitBinary, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.doubleBinary = ValueAndVariation { meas.value, var, var }; +} + +SOERecord::SOERecord(const BinaryOutputStatus& meas, uint16_t index_, EventClass clazz_, EventBinaryOutputStatusVariation var) : + SOERecord(EventType::BinaryOutputStatus, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.binaryOutputStatus = ValueAndVariation < BinaryOutputStatusSpec > { meas.value, var, var }; +} + +SOERecord::SOERecord(const Counter& meas, uint16_t index_, EventClass clazz_, EventCounterVariation var) : + SOERecord(EventType::Counter, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.counter = ValueAndVariation < CounterSpec > { meas.value, var, var }; +} + +SOERecord::SOERecord(const FrozenCounter& meas, uint16_t index_, EventClass clazz_, EventFrozenCounterVariation var) : + SOERecord(EventType::FrozenCounter, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.frozenCounter = ValueAndVariation < FrozenCounterSpec > { meas.value, var, var }; +} + +SOERecord::SOERecord(const Analog& meas, uint16_t index_, EventClass clazz_, EventAnalogVariation var) : + SOERecord(EventType::Analog, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.analog = ValueAndVariation < AnalogSpec > { meas.value, var, var }; +} + +SOERecord::SOERecord(const AnalogOutputStatus& meas, uint16_t index_, EventClass clazz_, EventAnalogOutputStatusVariation var) : + SOERecord(EventType::AnalogOutputStatus, clazz_, index_, meas.time, meas.flags.value) +{ + this->value.analogOutputStatus = ValueAndVariation < AnalogOutputStatusSpec > { meas.value, var, var }; +} + +SOERecord::SOERecord(const SecurityStat& meas, uint16_t index_, EventClass clazz_, EventSecurityStatVariation var) : + SOERecord(EventType::SecurityStat, clazz_, index_, meas.time, meas.quality) +{ + this->value.securityStat = ValueAndVariation < SecurityStatSpec > { meas.value, var, var }; +} + +void SOERecord::Select(EventBinaryVariation var) +{ + this->selected = true; + value.binary.selectedVariation = var; +} + +void SOERecord::Select(EventDoubleBinaryVariation var) +{ + this->selected = true; + value.doubleBinary.selectedVariation = var; +} + +void SOERecord::Select(EventBinaryOutputStatusVariation var) +{ + this->selected = true; + value.binaryOutputStatus.selectedVariation = var; +} + +void SOERecord::Select(EventCounterVariation var) +{ + this->selected = true; + value.counter.selectedVariation = var; +} + +void SOERecord::Select(EventFrozenCounterVariation var) +{ + this->selected = true; + value.frozenCounter.selectedVariation = var; +} + +void SOERecord::Select(EventAnalogVariation var) +{ + this->selected = true; + value.analog.selectedVariation = var; +} + +void SOERecord::Select(EventAnalogOutputStatusVariation var) +{ + this->selected = true; + value.analogOutputStatus.selectedVariation = var; +} + +void SOERecord::Select(EventSecurityStatVariation var) +{ + this->selected = true; + value.securityStat.selectedVariation = var; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.binary; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.doubleBinary; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.counter; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.frozenCounter; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.analog; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.binaryOutputStatus; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.analogOutputStatus; +} + +template <> +const ValueAndVariation& SOERecord::GetValue() +{ + return value.securityStat; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.h new file mode 100644 index 0000000..036ead8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SOERecord.h @@ -0,0 +1,130 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SOERECORD_H +#define OPENDNP3_SOERECORD_H + +#include "opendnp3/app/EventType.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" +#include "opendnp3/app/SecurityStat.h" + +#include + + +namespace opendnp3 +{ + +template +struct ValueAndVariation +{ + typename Spec::value_t value; + typename Spec::event_variation_t defaultVariation; + typename Spec::event_variation_t selectedVariation; + + void SelectDefaultVariation() + { + selectedVariation = defaultVariation; + } +}; + +template +struct EventInstance +{ + ValueType value; + uint16_t index; +}; + +union EventValue +{ + ValueAndVariation binary; + ValueAndVariation doubleBinary; + ValueAndVariation binaryOutputStatus; + ValueAndVariation counter; + ValueAndVariation frozenCounter; + ValueAndVariation analog; + ValueAndVariation analogOutputStatus; + ValueAndVariation securityStat; +}; + +class SOERecord +{ +public: + + SOERecord(); + + SOERecord(const Binary& meas, uint16_t index, EventClass clazz, EventBinaryVariation var); + SOERecord(const DoubleBitBinary& meas, uint16_t index, EventClass clazz, EventDoubleBinaryVariation var); + SOERecord(const BinaryOutputStatus& meas, uint16_t index, EventClass clazz, EventBinaryOutputStatusVariation var); + SOERecord(const Counter& meas, uint16_t index, EventClass clazz, EventCounterVariation var); + SOERecord(const FrozenCounter& meas, uint16_t index, EventClass clazz, EventFrozenCounterVariation var); + SOERecord(const Analog& meas, uint16_t index, EventClass clazz, EventAnalogVariation var); + SOERecord(const AnalogOutputStatus& meas, uint16_t index, EventClass clazz, EventAnalogOutputStatusVariation var); + SOERecord(const SecurityStat& meas, uint16_t index, EventClass clazz, EventSecurityStatVariation var); + + template + EventInstance ReadEvent() + { + return EventInstance + { + typename Spec::meas_t(GetValue().value, flags, time), index + }; + } + + template + const ValueAndVariation& GetValue(); + + void SelectDefault(); + + void Select(EventBinaryVariation var); + void Select(EventDoubleBinaryVariation var); + void Select(EventBinaryOutputStatusVariation var); + void Select(EventCounterVariation var); + void Select(EventFrozenCounterVariation var); + void Select(EventAnalogVariation var); + void Select(EventAnalogOutputStatusVariation var); + void Select(EventSecurityStatVariation var); + + EventType type; + EventClass clazz; + bool selected; + bool written; + void Reset(); + + DNPTime GetTime() const + { + return time; + } + +private: + + SOERecord(EventType type, EventClass clazz, uint16_t index, DNPTime time, uint8_t flags); + + + // the actual value; + EventValue value; + uint16_t index; + DNPTime time; + uint8_t flags; + +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.cpp new file mode 100644 index 0000000..f3f0bb1 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.cpp @@ -0,0 +1,99 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "SelectedRanges.h" + +#include "opendnp3/app/MeasurementTypeSpecs.h" +#include "opendnp3/app/SecurityStat.h" + +namespace opendnp3 +{ + +bool SelectedRanges::HasAnySelection() const +{ + return + binaries.IsValid() || + doubleBinaries.IsValid() || + analogs.IsValid() || + counters.IsValid() || + frozenCounters.IsValid() || + binaryOutputStatii.IsValid() || + analogOutputStatii.IsValid() || + timeAndIntervals.IsValid() || + securityStats.IsValid(); +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return binaries; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return doubleBinaries; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return analogs; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return counters; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return frozenCounters; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return binaryOutputStatii; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return analogOutputStatii; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return timeAndIntervals; +} + +template <> +Range& SelectedRanges::GetRangeRef() +{ + return securityStats; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.h new file mode 100644 index 0000000..0257969 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SelectedRanges.h @@ -0,0 +1,85 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_SELECTEDRANGES_H +#define OPENDNP3_SELECTEDRANGES_H + +#include + +#include "opendnp3/app/Range.h" + +namespace opendnp3 +{ + +/** +* Selected ranges for each static datatype +*/ +class SelectedRanges : private openpal::Uncopyable +{ + +public: + + template + Range Get() + { + return GetRangeRef(); + } + + template + void Set(const Range& range) + { + GetRangeRef() = range; + } + + template + void Merge(const Range& range) + { + auto& ref = GetRangeRef(); + ref = ref.Union(range); + } + + template + void Clear() + { + Set(Range::Invalid()); + } + + bool HasAnySelection() const; + +private: + + // specializations in cpp file + template + Range& GetRangeRef(); + + Range binaries; + Range doubleBinaries; + Range analogs; + Range counters; + Range frozenCounters; + Range binaryOutputStatii; + Range analogOutputStatii; + Range timeAndIntervals; + Range securityStats; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SimpleCommandHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SimpleCommandHandler.cpp new file mode 100644 index 0000000..c370427 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/SimpleCommandHandler.cpp @@ -0,0 +1,108 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "opendnp3/outstation/SimpleCommandHandler.h" + +namespace opendnp3 +{ + +SimpleCommandHandler::SimpleCommandHandler(CommandStatus status_) : status(status_), numOperate(0), numSelect(0), numStart(0), numEnd(0) +{ + +} + +CommandStatus SimpleCommandHandler::Select(const ControlRelayOutputBlock& command, uint16_t index) +{ + this->DoSelect(command, index); + ++numSelect; + return status; +} +CommandStatus SimpleCommandHandler::Operate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) +{ + this->DoOperate(command, index, opType); + ++numOperate; + return status; +} + +CommandStatus SimpleCommandHandler::Select(const AnalogOutputInt16& command, uint16_t index) +{ + this->DoSelect(command, index); + ++numSelect; + return status; +} +CommandStatus SimpleCommandHandler::Operate(const AnalogOutputInt16& command, uint16_t index, OperateType opType) +{ + this->DoOperate(command, index, opType); + ++numOperate; + return status; +} + +CommandStatus SimpleCommandHandler::Select(const AnalogOutputInt32& command, uint16_t index) +{ + this->DoSelect(command, index); + ++numSelect; + return status; +} +CommandStatus SimpleCommandHandler::Operate(const AnalogOutputInt32& command, uint16_t index, OperateType opType) +{ + this->DoOperate(command, index, opType); + ++numOperate; + return status; +} + +CommandStatus SimpleCommandHandler::Select(const AnalogOutputFloat32& command, uint16_t index) +{ + this->DoSelect(command, index); + ++numSelect; + return status; +} +CommandStatus SimpleCommandHandler::Operate(const AnalogOutputFloat32& command, uint16_t index, OperateType opType) +{ + this->DoOperate(command, index, opType); + ++numOperate; + return status; +} + +CommandStatus SimpleCommandHandler::Select(const AnalogOutputDouble64& command, uint16_t index) +{ + this->DoSelect(command, index); + ++numSelect; + return status; +} +CommandStatus SimpleCommandHandler::Operate(const AnalogOutputDouble64& command, uint16_t index, OperateType opType) +{ + this->DoOperate(command, index, opType); + ++numOperate; + return status; +} + +void SimpleCommandHandler::Start() +{ + ++numStart; +} + +void SimpleCommandHandler::End() +{ + ++numEnd; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.cpp new file mode 100644 index 0000000..4fcb6fc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.cpp @@ -0,0 +1,110 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "StaticBuffers.h" + +namespace opendnp3 +{ + +StaticBuffers::StaticBuffers(const DatabaseSizes& dbSizes) : + binaries(dbSizes.numBinary), + doubleBinaries(dbSizes.numDoubleBinary), + analogs(dbSizes.numAnalog), + counters(dbSizes.numCounter), + frozenCounters(dbSizes.numFrozenCounter), + binaryOutputStatii(dbSizes.numBinaryOutputStatus), + analogOutputStatii(dbSizes.numAnalogOutputStatus), + timeAndIntervals(dbSizes.numTimeAndInterval) +{ + this->SetDefaultIndices(); + this->SetDefaultIndices(); + this->SetDefaultIndices(); + this->SetDefaultIndices(); + this->SetDefaultIndices(); + this->SetDefaultIndices(); + this->SetDefaultIndices(); + this->SetDefaultIndices(); +} + +DatabaseConfigView StaticBuffers::GetView() const +{ + return DatabaseConfigView( + binaries.ToView(), + doubleBinaries.ToView(), + analogs.ToView(), + counters.ToView(), + frozenCounters.ToView(), + binaryOutputStatii.ToView(), + analogOutputStatii.ToView(), + timeAndIntervals.ToView() + ); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return binaries.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return doubleBinaries.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return counters.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return frozenCounters.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return analogs.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return binaryOutputStatii.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return analogOutputStatii.ToView(); +} + +template <> +openpal::ArrayView, uint16_t> StaticBuffers::GetArrayView() +{ + return timeAndIntervals.ToView(); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.h new file mode 100644 index 0000000..c14c82d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticBuffers.h @@ -0,0 +1,76 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_STATICBUFFERS_H +#define OPENDNP3_STATICBUFFERS_H + +#include "opendnp3/outstation/DatabaseConfigView.h" + +#include "opendnp3/outstation/Cell.h" +#include "opendnp3/outstation/DatabaseSizes.h" + +#include +#include + + +namespace opendnp3 +{ + +/** +* The static database provides storage for current values and all of the associated metadata +*/ +class StaticBuffers : private openpal::Uncopyable +{ + +public: + + explicit StaticBuffers(const DatabaseSizes& dbSizes); + + DatabaseConfigView GetView() const; + + // specializations in cpp file + template + openpal::ArrayView, uint16_t> GetArrayView(); + +private: + + template + void SetDefaultIndices() + { + auto view = GetArrayView(); + for (uint16_t i = 0; i < view.Size(); ++i) + { + view[i].config.vIndex = i; + } + } + + openpal::Array, uint16_t> binaries; + openpal::Array, uint16_t> doubleBinaries; + openpal::Array, uint16_t> analogs; + openpal::Array, uint16_t> counters; + openpal::Array, uint16_t> frozenCounters; + openpal::Array, uint16_t> binaryOutputStatii; + openpal::Array, uint16_t> analogOutputStatii; + openpal::Array, uint16_t> timeAndIntervals; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.cpp new file mode 100644 index 0000000..2d7b361 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.cpp @@ -0,0 +1,133 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "StaticLoadFunctions.h" + +#include "opendnp3/objects/Group1.h" +#include "opendnp3/objects/Group3.h" +#include "opendnp3/objects/Group10.h" +#include "opendnp3/objects/Group20.h" +#include "opendnp3/objects/Group21.h" +#include "opendnp3/objects/Group30.h" +#include "opendnp3/objects/Group40.h" +#include "opendnp3/objects/Group50.h" +#include "opendnp3/objects/Group121.h" + +using namespace openpal; + +namespace opendnp3 +{ + + +StaticWriter::Function GetStaticWriter(StaticBinaryVariation variation) +{ + switch (variation) + { + case(StaticBinaryVariation::Group1Var1) : + return &WriteSingleBitfield; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticDoubleBinaryVariation variation) +{ + switch (variation) + { + case(StaticDoubleBinaryVariation::Group3Var2) : + return &WriteWithSerializer; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticAnalogVariation variation) +{ + switch (variation) + { + case(StaticAnalogVariation::Group30Var1): return &WriteWithSerializer; + case(StaticAnalogVariation::Group30Var2): return &WriteWithSerializer; + case(StaticAnalogVariation::Group30Var3): return &WriteWithSerializer; + case(StaticAnalogVariation::Group30Var4): return &WriteWithSerializer; + case(StaticAnalogVariation::Group30Var5): return &WriteWithSerializer; + case(StaticAnalogVariation::Group30Var6): return &WriteWithSerializer; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticCounterVariation variation) +{ + switch (variation) + { + case(StaticCounterVariation::Group20Var1): return &WriteWithSerializer; + case(StaticCounterVariation::Group20Var2): return &WriteWithSerializer; + case(StaticCounterVariation::Group20Var5): return &WriteWithSerializer; + case(StaticCounterVariation::Group20Var6): return &WriteWithSerializer; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticFrozenCounterVariation variation) +{ + switch (variation) + { + case(StaticFrozenCounterVariation::Group21Var1): return &WriteWithSerializer; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticBinaryOutputStatusVariation variation) +{ + switch (variation) + { + case(StaticBinaryOutputStatusVariation::Group10Var2): return &WriteWithSerializer; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticAnalogOutputStatusVariation variation) +{ + switch (variation) + { + case(StaticAnalogOutputStatusVariation::Group40Var1): return &WriteWithSerializer; + case(StaticAnalogOutputStatusVariation::Group40Var2): return &WriteWithSerializer; + case(StaticAnalogOutputStatusVariation::Group40Var3): return &WriteWithSerializer; + case(StaticAnalogOutputStatusVariation::Group40Var4): return &WriteWithSerializer; + default: + return &WriteWithSerializer; + } +} + +StaticWriter::Function GetStaticWriter(StaticTimeAndIntervalVariation variation) +{ + return &WriteWithSerializer; +} + +StaticWriter::Function GetStaticWriter(StaticSecurityStatVariation variation) +{ + return &WriteWithSerializer < SecurityStatSpec, Group121Var1 > ; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.h new file mode 100644 index 0000000..db5addb --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/StaticLoadFunctions.h @@ -0,0 +1,170 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_STATICLOADFUNCTIONS_H +#define OPENDNP3_STATICLOADFUNCTIONS_H + +#include "opendnp3/app/Range.h" +#include "opendnp3/app/HeaderWriter.h" +#include "opendnp3/app/MeasurementTypeSpecs.h" +#include "opendnp3/app/SecurityStat.h" +#include "opendnp3/outstation/Cell.h" + +#include "opendnp3/gen/StaticBinaryVariation.h" +#include "opendnp3/gen/StaticDoubleBinaryVariation.h" +#include "opendnp3/gen/StaticCounterVariation.h" +#include "opendnp3/gen/StaticFrozenCounterVariation.h" +#include "opendnp3/gen/StaticAnalogVariation.h" +#include "opendnp3/gen/StaticAnalogOutputStatusVariation.h" +#include "opendnp3/gen/StaticBinaryOutputStatusVariation.h" + +#include + +namespace opendnp3 +{ + +template +struct StaticWriter +{ + typedef bool (*Function)(openpal::ArrayView, uint16_t>& view, HeaderWriter& writer, Range& range); +}; + +StaticWriter::Function GetStaticWriter(StaticBinaryVariation variation); + +StaticWriter::Function GetStaticWriter(StaticDoubleBinaryVariation variation); + +StaticWriter::Function GetStaticWriter(StaticCounterVariation variation); + +StaticWriter::Function GetStaticWriter(StaticFrozenCounterVariation variation); + +StaticWriter::Function GetStaticWriter(StaticAnalogVariation variation); + +StaticWriter::Function GetStaticWriter(StaticAnalogOutputStatusVariation variation); + +StaticWriter::Function GetStaticWriter(StaticBinaryOutputStatusVariation variation); + +StaticWriter::Function GetStaticWriter(StaticTimeAndIntervalVariation variation); + +StaticWriter::Function GetStaticWriter(StaticSecurityStatVariation variation); + +template +bool LoadWithRangeIterator(openpal::ArrayView, uint16_t>& view, RangeWriteIterator& iterator, Range& range) +{ + const Cell& start = view[range.start]; + uint16_t nextIndex = start.config.vIndex; + + while ( + range.IsValid() && + view[range.start].selection.selected && + (view[range.start].selection.variation == start.selection.variation) && + (view[range.start].config.vIndex == nextIndex) + ) + { + if (iterator.Write(view[range.start].selection.value)) + { + // deselect the value and advance the range + view[range.start].selection.selected = false; + range.Advance(); + ++nextIndex; + } + else + { + return false; + } + } + + return true; +} + +template +bool LoadWithBitfieldIterator(openpal::ArrayView, uint16_t>& view, BitfieldRangeWriteIterator& iterator, Range& range) +{ + const Cell& start = view[range.start]; + + uint16_t nextIndex = start.config.vIndex; + + while ( + range.IsValid() && + view[range.start].selection.selected && + (view[range.start].selection.variation == start.selection.variation) && + (view[range.start].config.vIndex == nextIndex) + ) + { + if (iterator.Write(view[range.start].selection.value.value)) + { + // deselect the value and advance the range + view[range.start].selection.selected = false; + range.Advance(); + ++nextIndex; + } + else + { + return false; + } + } + + return true; +} + +template +bool WriteSingleBitfield(openpal::ArrayView, uint16_t>& view, HeaderWriter& writer, Range& range) +{ + auto start = view[range.start].config.vIndex; + auto stop = view[range.stop].config.vIndex; + auto mapped = Range::From(start, stop); + + if (mapped.IsOneByte()) + { + auto iter = writer.IterateOverSingleBitfield(GV::ID(), QualifierCode::UINT8_START_STOP, static_cast(mapped.start)); + return LoadWithBitfieldIterator(view, iter, range); + } + else + { + auto iter = writer.IterateOverSingleBitfield(GV::ID(), QualifierCode::UINT16_START_STOP, mapped.start); + return LoadWithBitfieldIterator(view, iter, range); + } +} + + +template +bool WriteWithSerializer(openpal::ArrayView, uint16_t>& view, HeaderWriter& writer, Range& range) +{ + auto start = view[range.start].config.vIndex; + auto stop = view[range.stop].config.vIndex; + auto mapped = Range::From(start, stop); + + if (mapped.IsOneByte()) + { + auto iter = writer.IterateOverRange(QualifierCode::UINT8_START_STOP, Serializer::Inst(), static_cast(mapped.start)); + return LoadWithRangeIterator(view, iter, range); + } + else + { + auto iter = writer.IterateOverRange(QualifierCode::UINT16_START_STOP, Serializer::Inst(), mapped.start); + return LoadWithRangeIterator(view, iter, range); + } +} + + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.cpp new file mode 100644 index 0000000..c6e875f --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.cpp @@ -0,0 +1,106 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "WriteHandler.h" + +#include "openpal/logging/LogMacros.h" + +using namespace openpal; + +namespace opendnp3 +{ + +WriteHandler::WriteHandler(IOutstationApplication& application, IINField* pWriteIIN_) : + pApplication(&application), + pWriteIIN(pWriteIIN_), + wroteTime(false), + wroteIIN(false) +{} + +IINField WriteHandler::ProcessHeader(const RangeHeader& header, const ICollection>& values) +{ + Indexed pair; + + if (!values.ReadOnlyValue(pair)) + { + return IINBit::PARAM_ERROR; + } + + if (wroteIIN) + { + return IINBit::PARAM_ERROR; + } + + if (pair.index != static_cast(IINBit::DEVICE_RESTART)) + { + return IINBit::PARAM_ERROR; + } + + if (pair.value.value) + { + return IINBit::PARAM_ERROR; + } + + wroteIIN = true; + pWriteIIN->ClearBit(IINBit::DEVICE_RESTART); + return IINField(); +} + +IINField WriteHandler::ProcessHeader(const CountHeader& header, const ICollection& values) +{ + if (wroteTime) + { + return IINBit::PARAM_ERROR; + } + else + { + Group50Var1 value; + if (values.ReadOnlyValue(value)) + { + if (pApplication->SupportsWriteAbsoluteTime()) + { + wroteTime = true; + return pApplication->WriteAbsoluteTime(UTCTimestamp(value.time)) ? IINField::Empty() : IINBit::PARAM_ERROR; + } + else + { + return IINBit::FUNC_NOT_SUPPORTED; + } + } + else + { + return IINBit::PARAM_ERROR; + } + } +} + +IINField WriteHandler::ProcessHeader(const PrefixHeader& header, const ICollection>& values) +{ + if (!pApplication->SupportsWriteTimeAndInterval()) + { + return IINBit::FUNC_NOT_SUPPORTED; + } + + return pApplication->WriteTimeAndInterval(values) ? IINField::Empty() : IINBit::PARAM_ERROR; +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.h b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.h new file mode 100644 index 0000000..9b84b3d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/outstation/WriteHandler.h @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_WRITEHANDLER_H +#define OPENDNP3_WRITEHANDLER_H + +#include "opendnp3/app/parsing/IAPDUHandler.h" +#include "opendnp3/app/IINField.h" + +#include "opendnp3/outstation/IOutstationApplication.h" + +#include + +namespace opendnp3 +{ + +class WriteHandler : public IAPDUHandler +{ +public: + + WriteHandler(IOutstationApplication& application, IINField* pWriteIIN_); + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final + { + return true; + } + +private: + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final; + + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& times) override final; + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final; + + IOutstationApplication* pApplication; + IINField* pWriteIIN; + + bool wroteTime; + bool wroteIIN; +}; + +} + + + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportConstants.h b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportConstants.h new file mode 100644 index 0000000..0315873 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportConstants.h @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TRANSPORTCONSTANTS_H +#define OPENDNP3_TRANSPORTCONSTANTS_H + +#include + +namespace opendnp3 +{ + +/// Transport header bitmasks +enum TransportHeader +{ + TL_HDR_FIN = 0x80, + TL_HDR_FIR = 0x40, + TL_HDR_SEQ = 0x3F +}; + +/// Maximum TPDU length +const uint8_t MAX_TPDU_LENGTH = 250; +/// Maximum TPDU payload size +const uint8_t MAX_TPDU_PAYLOAD = 249; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.cpp new file mode 100644 index 0000000..70b5fcc --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.cpp @@ -0,0 +1,187 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "TransportLayer.h" + +#include + +#include "TransportConstants.h" + +#include "opendnp3/LogLevels.h" + +#include + +using namespace std; +using namespace openpal; + +namespace opendnp3 +{ + + +TransportLayer::TransportLayer(const openpal::Logger& logger, uint32_t maxRxFragSize) : + logger(logger), + receiver(logger, maxRxFragSize), + transmitter(logger) +{ + +} + +/////////////////////////////////////// +// Actions +/////////////////////////////////////// + +bool TransportLayer::BeginTransmit(const RSlice& apdu) +{ + if (!isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer offline"); + return false; + } + + if (apdu.IsEmpty()) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "APDU cannot be empty"); + return false; + } + + if (isSending) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Invalid BeginTransmit call, already transmitting"); + return false; + } + + if (!lower) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Can't send without an attached link layer"); + return false; + } + + isSending = true; + transmitter.Configure(apdu); + lower->Send(transmitter); + + return true; +} + +/////////////////////////////////////// +// IUpperLayer +/////////////////////////////////////// + +bool TransportLayer::OnReceive(const RSlice& tpdu) +{ + if (isOnline) + { + auto apdu = receiver.ProcessReceive(tpdu); + if (apdu.IsNotEmpty() && upper) + { + upper->OnReceive(apdu); + } + return true; + } + else + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer offline"); + return false; + } +} + +bool TransportLayer::OnSendResult(bool isSuccess) +{ + if (!isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer offline"); + return false; + } + + if (!isSending) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Invalid send callback"); + return false; + } + + isSending = false; + + if (upper) + { + upper->OnSendResult(isSuccess); + } + + return true; +} + +void TransportLayer::SetAppLayer(IUpperLayer& upperLayer) +{ + assert(!upper); + upper = &upperLayer; +} + +void TransportLayer::SetLinkLayer(ILinkLayer& linkLayer) +{ + assert(!lower); + lower = &linkLayer; +} + +StackStatistics::Transport TransportLayer::GetStatistics() const +{ + return StackStatistics::Transport(this->receiver.Statistics(), this->transmitter.Statistics()); +} + +bool TransportLayer::OnLowerLayerUp() +{ + if (isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer already online"); + return false; + } + + isOnline = true; + if (upper) + { + upper->OnLowerLayerUp(); + } + return true; +} + +bool TransportLayer::OnLowerLayerDown() +{ + if (!isOnline) + { + SIMPLE_LOG_BLOCK(logger, flags::ERR, "Layer already offline"); + return false; + } + + isOnline = false; + isSending = false; + receiver.Reset(); + + if (upper) + { + upper->OnLowerLayerDown(); + } + + return true; +} + +/////////////////////////////////////// +// Helpers +/////////////////////////////////////// + +} //end namespace + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.h b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.h new file mode 100644 index 0000000..63b4a32 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportLayer.h @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TRANSPORTLAYER_H +#define OPENDNP3_TRANSPORTLAYER_H + +#include "TransportRx.h" +#include "TransportTx.h" + +#include +#include + +#include "opendnp3/LayerInterfaces.h" +#include "opendnp3/StackStatistics.h" +#include "opendnp3/link/ILinkLayer.h" + +namespace opendnp3 +{ + +/** + Implements the DNP3 transport layer +*/ +class TransportLayer : public IUpperLayer, public ILowerLayer +{ + +public: + + TransportLayer(const openpal::Logger& logger, uint32_t maxRxFragSize); + + /// ILowerLayer + + virtual bool BeginTransmit(const openpal::RSlice&) override final; + + /// IUpperLayer + + virtual bool OnReceive(const openpal::RSlice&) override final; + virtual bool OnLowerLayerUp() override final; + virtual bool OnLowerLayerDown() override final; + virtual bool OnSendResult(bool isSuccess) override final; + + void SetAppLayer(IUpperLayer& upperLayer); + + void SetLinkLayer(ILinkLayer& linkLayer); + + StackStatistics::Transport GetStatistics() const; + +private: + + openpal::Logger logger; + + IUpperLayer* upper = nullptr; + ILinkLayer* lower = nullptr; + + // ---- state ---- + bool isOnline = false; + bool isSending = false; + + // ----- Transmitter and Receiver Classes ------ + TransportRx receiver; + TransportTx transmitter; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.cpp new file mode 100644 index 0000000..a1775ba --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.cpp @@ -0,0 +1,146 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "TransportRx.h" +#include "TransportConstants.h" +#include "opendnp3/LogLevels.h" + +#include +#include + +#include + +using namespace std; +using namespace openpal; + +namespace opendnp3 +{ + +TransportRx::TransportRx(const Logger& logger, uint32_t maxRxFragSize) : + logger(logger), + rxBuffer(maxRxFragSize), + numBytesRead(0) +{ + +} + +void TransportRx::Reset() +{ + sequence.Reset(); + this->ClearRxBuffer(); +} + +void TransportRx::ClearRxBuffer() +{ + numBytesRead = 0; +} + +openpal::WSlice TransportRx::GetAvailable() +{ + return rxBuffer.GetWSlice().Skip(numBytesRead); +} + +RSlice TransportRx::ProcessReceive(const RSlice& input) +{ + ++statistics.numTransportRx; + + if (input.IsEmpty()) + { + FORMAT_LOG_BLOCK(logger, flags::WARN, "Received tpdu with no header"); + ++statistics.numTransportErrorRx; + return RSlice::Empty(); + } + + const uint8_t HDR = input[0]; + const bool FIR = (HDR & TL_HDR_FIR) != 0; + const bool FIN = (HDR & TL_HDR_FIN) != 0; + const int SEQ = HDR & TL_HDR_SEQ; + + auto payload = input.Skip(1); + + FORMAT_LOG_BLOCK(logger, flags::TRANSPORT_RX, "FIR: %d FIN: %d SEQ: %u LEN: %u", FIR, FIN, SEQ, payload.Size()); + + if (!this->ValidateHeader(FIR, SEQ)) + { + ++statistics.numTransportErrorRx; + return RSlice::Empty(); + } + + auto available = this->GetAvailable(); + + if (payload.Size() > available.Size()) + { + ++statistics.numTransportBufferOverflow; + SIMPLE_LOG_BLOCK(logger, flags::WARN, "Exceeded the buffer size before a complete fragment was read"); + this->ClearRxBuffer(); + return RSlice::Empty(); + } + + payload.CopyTo(available); + + this->numBytesRead += payload.Size(); + this->sequence.Increment(); + + if(FIN) + { + RSlice ret = rxBuffer.ToRSlice().Take(numBytesRead); + this->ClearRxBuffer(); + return ret; + } + else + { + return RSlice::Empty(); + } +} + +bool TransportRx::ValidateHeader(bool fir, uint8_t sequence_) +{ + if(fir) + { + sequence = sequence_; //always accept the sequence on FIR + if (numBytesRead > 0) + { + ++statistics.numTransportDiscard; + // drop existing received bytes from segment + SIMPLE_LOG_BLOCK(logger, flags::WARN, "FIR received mid-fragment, discarding previous bytes"); + numBytesRead = 0; + } + return true; + } + + if(numBytesRead == 0) //non-first packet with 0 prior bytes + { + ++statistics.numTransportIgnore; + SIMPLE_LOG_BLOCK(logger, flags::WARN, "non-FIR packet with 0 prior bytes"); + return false; + } + + if(sequence_ != sequence) + { + ++statistics.numTransportIgnore; + FORMAT_LOG_BLOCK(logger, flags::WARN, "Ignoring bad sequence, got %u, expected %u", sequence_, sequence.Get()); + return false; + } + + return true; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.h b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.h new file mode 100644 index 0000000..3b5f777 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportRx.h @@ -0,0 +1,73 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TRANSPORTRX_H +#define OPENDNP3_TRANSPORTRX_H + +#include "opendnp3/StackStatistics.h" +#include "opendnp3/transport/TransportConstants.h" +#include "opendnp3/transport/TransportSeqNum.h" + +#include +#include +#include + +namespace opendnp3 +{ + +/** +State/validation for the DNP3 transport layer's receive channel. +*/ +class TransportRx +{ + +public: + TransportRx(const openpal::Logger&, uint32_t maxRxFragSize); + + openpal::RSlice ProcessReceive(const openpal::RSlice& input); + + void Reset(); + + const StackStatistics::Transport::Rx& Statistics() const + { + return statistics; + } + +private: + + openpal::WSlice GetAvailable(); + + void ClearRxBuffer(); + + bool ValidateHeader(bool fir, uint8_t sequence); + + openpal::Logger logger; + StackStatistics::Transport::Rx statistics; + + openpal::Buffer rxBuffer; + uint32_t numBytesRead; + + TransportSeqNum sequence; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportSeqNum.h b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportSeqNum.h new file mode 100644 index 0000000..5abe33c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportSeqNum.h @@ -0,0 +1,34 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TRANSPORTSEQNUM_H +#define OPENDNP3_TRANSPORTSEQNUM_H + +#include +#include + +namespace opendnp3 +{ + +typedef openpal::SequenceNum TransportSeqNum; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.cpp new file mode 100644 index 0000000..b4175a7 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.cpp @@ -0,0 +1,35 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "TransportStack.h" + +using namespace openpal; + +namespace opendnp3 +{ + +TransportStack::TransportStack(const openpal::Logger& logger, const std::shared_ptr& executor, const std::shared_ptr& listener, uint32_t maxRxFragSize, const LinkConfig& config) : + transport(std::make_shared(logger, maxRxFragSize)), + link(std::make_shared(logger, executor, transport, listener, config)) +{ + transport->SetLinkLayer(*link); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.h b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.h new file mode 100644 index 0000000..1577de8 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportStack.h @@ -0,0 +1,44 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TRANSPORTSTACK_H +#define OPENDNP3_TRANSPORTSTACK_H + +#include "opendnp3/link/LinkLayer.h" +#include "opendnp3/link/ILinkListener.h" +#include "opendnp3/transport/TransportLayer.h" + +namespace opendnp3 +{ + +class TransportStack +{ + +public: + + TransportStack(const openpal::Logger& logger, const std::shared_ptr& executor, const std::shared_ptr& listener, uint32_t maxRxFragSize, const LinkConfig& config); + + std::shared_ptr transport; + std::shared_ptr link; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.cpp b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.cpp new file mode 100644 index 0000000..4d6234e --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.cpp @@ -0,0 +1,111 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "TransportTx.h" + +#include "opendnp3/transport/TransportLayer.h" +#include "opendnp3/LogLevels.h" + +#include + +#include + +using namespace std; +using namespace openpal; + +namespace opendnp3 +{ + +TransportTx::TransportTx(const openpal::Logger& logger) : logger(logger) +{} + +void TransportTx::Configure(const openpal::RSlice& output) +{ + assert(output.IsNotEmpty()); + txSegment.Clear(); + this->apdu = output; + this->tpduCount = 0; +} + +bool TransportTx::HasValue() const +{ + return apdu.Size() > 0; +} + +openpal::RSlice TransportTx::GetSegment() +{ + if (txSegment.IsSet()) + { + return txSegment.Get(); + } + else + { + uint32_t numToSend = (apdu.Size() < MAX_TPDU_PAYLOAD) ? apdu.Size() : MAX_TPDU_PAYLOAD; + + auto dest = tpduBuffer.GetWSlice().Skip(1); + apdu.Take(numToSend).CopyTo(dest); + + bool fir = (tpduCount == 0); + bool fin = (numToSend == apdu.Size()); + tpduBuffer()[0] = GetHeader(fir, fin, sequence); + + FORMAT_LOG_BLOCK(logger, flags::TRANSPORT_TX, "FIR: %d FIN: %d SEQ: %u LEN: %u", fir, fin, sequence.Get(), numToSend); + + ++statistics.numTransportTx; + + auto segment = tpduBuffer.ToRSlice(numToSend + 1); + txSegment.Set(segment); + return segment; + } + +} + +bool TransportTx::Advance() +{ + txSegment.Clear(); + uint32_t numToSend = apdu.Size() < MAX_TPDU_PAYLOAD ? apdu.Size() : MAX_TPDU_PAYLOAD; + apdu.Advance(numToSend); + ++tpduCount; + sequence.Increment(); + return apdu.IsNotEmpty(); +} + +uint8_t TransportTx::GetHeader(bool fir, bool fin, uint8_t sequence) +{ + uint8_t hdr = 0; + + if (fir) + { + hdr |= TL_HDR_FIR; + } + + if (fin) + { + hdr |= TL_HDR_FIN; + } + + // Only the lower 6 bits of the sequence number + hdr |= TL_HDR_SEQ & sequence; + + return hdr; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.h b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.h new file mode 100644 index 0000000..8ec321a --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/opendnp3/transport/TransportTx.h @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_TRANSPORTTX_H +#define OPENDNP3_TRANSPORTTX_H + +#include +#include +#include + +#include "opendnp3/StackStatistics.h" +#include "opendnp3/link/ITransportSegment.h" +#include "opendnp3/transport/TransportConstants.h" +#include "opendnp3/transport/TransportSeqNum.h" + +namespace opendnp3 +{ + +/** +State/validation for the DNP3 transport layer's send channel. +*/ +class TransportTx : public ITransportSegment +{ + +public: + + TransportTx(const openpal::Logger& logger); + + void Configure(const openpal::RSlice& output); + + static uint8_t GetHeader(bool fir, bool fin, uint8_t sequence); + + /// ------- IBufferSegment ------------ + + virtual bool HasValue() const override final; + + virtual openpal::RSlice GetSegment() override final; + + virtual bool Advance() override final; + + const StackStatistics::Transport::Tx& Statistics() const + { + return statistics; + } + +private: + + // A wrapper to the APDU buffer that we're segmenting + openpal::RSlice apdu; + + openpal::Settable txSegment; + + // Static buffer where we store tpdus that are being transmitted + openpal::StaticBuffer tpduBuffer; + + openpal::Logger logger; + StackStatistics::Transport::Tx statistics; + TransportSeqNum sequence; + uint32_t tpduCount = 0; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/container/Buffer.cpp b/utils/dnp3_src/cpp/libs/src/openpal/container/Buffer.cpp new file mode 100644 index 0000000..63d60c4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/container/Buffer.cpp @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/container/Buffer.h" + +namespace openpal +{ +Buffer::Buffer() : Array(0) +{} + +Buffer::Buffer(uint32_t size) : Array(size) +{} + +Buffer::Buffer(const RSlice& input) : Array(input.Size()) +{ + auto dest = this->GetWSlice(); + input.CopyTo(dest); +} + +RSlice Buffer::ToRSlice() const +{ + return RSlice(this->buffer, this->size); +} + +WSlice Buffer::GetWSlice() +{ + return WSlice(this->buffer, this->Size()); +} + +WSlice Buffer::GetWSlice(uint32_t maxSize) +{ + if (maxSize <= this->Size()) + { + return WSlice(this->buffer, maxSize); + } + else + { + return GetWSlice(); + } +} +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/container/RSlice.cpp b/utils/dnp3_src/cpp/libs/src/openpal/container/RSlice.cpp new file mode 100644 index 0000000..2c45e1b --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/container/RSlice.cpp @@ -0,0 +1,96 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/container/RSlice.h" + +#include "openpal/util/Comparisons.h" + +#include "openpal/container/WSlice.h" + +#include + +namespace openpal +{ + +RSlice RSlice::Empty() +{ + return RSlice(); +} + +RSlice::RSlice(): HasSize(0), pBuffer(nullptr) +{} + +RSlice::RSlice(uint8_t const* pBuffer, uint32_t size) : + HasSize(size), + pBuffer(pBuffer) +{} + +RSlice RSlice::CopyTo(WSlice& dest) const +{ + if (dest.Size() < size) + { + return RSlice::Empty(); + } + else + { + WSlice copy(dest); + memcpy(dest, pBuffer, size); + dest.Advance(size); + return copy.ToRSlice().Take(size); + } +} + +RSlice RSlice::Take(uint32_t count) const +{ + return RSlice(pBuffer, openpal::Min(size, count)); +} + +RSlice RSlice::Skip(uint32_t count) const +{ + auto num = openpal::Min(size, count); + return RSlice(pBuffer + num, size - num); +} + +void RSlice::Clear() +{ + pBuffer = nullptr; + size = 0; +} + +bool RSlice::Equals(const RSlice& rhs) const +{ + if (this->Size() == rhs.Size()) + { + return memcmp(pBuffer, rhs.pBuffer, Size()) == 0; + } + else + { + return false; + } +} + +void RSlice::Advance(uint32_t count) +{ + auto num = openpal::Min(size, count); + pBuffer += num; + size -= num; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/openpal/container/WSlice.cpp b/utils/dnp3_src/cpp/libs/src/openpal/container/WSlice.cpp new file mode 100644 index 0000000..63958fe --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/container/WSlice.cpp @@ -0,0 +1,78 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/container/WSlice.h" + +#include "openpal/util/Comparisons.h" +#include "openpal/container/RSlice.h" + +#include + +namespace openpal +{ + +WSlice WSlice::Empty() +{ + return WSlice(); +} + +WSlice::WSlice(): + HasSize(0), + pBuffer(nullptr) +{} + +void WSlice::SetAllTo(uint8_t value) +{ + memset(pBuffer, value, size); +} + +WSlice::WSlice(uint8_t* pBuffer_, uint32_t size) : + HasSize(size), + pBuffer(pBuffer_) +{} + +void WSlice::Clear() +{ + pBuffer = nullptr; + size = 0; +} + +uint32_t WSlice::Advance(uint32_t count) +{ + auto num = openpal::Min(count, size); + pBuffer += num; + size -= num; + return num; +} + +WSlice WSlice::Skip(uint32_t count) const +{ + auto num = openpal::Min(count, size); + return WSlice(pBuffer + num, size - num); +} + +RSlice WSlice::ToRSlice() const +{ + return RSlice(pBuffer, size); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/executor/MonotonicTimestamp.cpp b/utils/dnp3_src/cpp/libs/src/openpal/executor/MonotonicTimestamp.cpp new file mode 100644 index 0000000..340a02c --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/executor/MonotonicTimestamp.cpp @@ -0,0 +1,78 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/executor/MonotonicTimestamp.h" + +#include + +namespace openpal +{ + +MonotonicTimestamp MonotonicTimestamp::Max() +{ + return MonotonicTimestamp(INT64_MAX); +} + +MonotonicTimestamp MonotonicTimestamp::Min() +{ + return MonotonicTimestamp(INT64_MIN); +} + +bool MonotonicTimestamp::IsMax() const +{ + return milliseconds == INT64_MAX; +} + +bool MonotonicTimestamp::IsMin() const +{ + return milliseconds == INT64_MIN; +} + +MonotonicTimestamp::MonotonicTimestamp() : milliseconds(0) +{} + +MonotonicTimestamp::MonotonicTimestamp(int64_t aMilliseconds) : milliseconds(aMilliseconds) +{} + + +MonotonicTimestamp MonotonicTimestamp::Add(const TimeDuration& duration) const +{ + const auto maximum = INT64_MAX - this->milliseconds; + + return duration.GetMilliseconds() >= maximum ? MonotonicTimestamp::Max() : MonotonicTimestamp(milliseconds + duration.GetMilliseconds()); +} + +bool operator==(const MonotonicTimestamp& first, const MonotonicTimestamp& second) +{ + return first.milliseconds == second.milliseconds; +} + +bool operator<(const MonotonicTimestamp& first, const MonotonicTimestamp& second) +{ + return first.milliseconds < second.milliseconds; +} + +bool operator>(const MonotonicTimestamp& first, const MonotonicTimestamp& second) +{ + return first.milliseconds > second.milliseconds; +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/executor/TimeDuration.cpp b/utils/dnp3_src/cpp/libs/src/openpal/executor/TimeDuration.cpp new file mode 100644 index 0000000..1998931 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/executor/TimeDuration.cpp @@ -0,0 +1,78 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/executor/TimeDuration.h" + +#include "openpal/util/Limits.h" + +namespace openpal +{ + +TimeDuration TimeDuration::Min() +{ + return TimeDuration(openpal::MinValue()); +} + +TimeDuration TimeDuration::Max() +{ + return TimeDuration(openpal::MaxValue()); +} + +TimeDuration TimeDuration::Zero() +{ + return TimeDuration(0); +} + +TimeDuration TimeDuration::Milliseconds(int64_t milliseconds) +{ + return TimeDuration(milliseconds); +} + +TimeDuration TimeDuration::Seconds(int64_t seconds) +{ + return TimeDuration(1000 * seconds); +} + +TimeDuration TimeDuration::Minutes(int64_t minutes) +{ + return TimeDuration(static_cast(1000 * 60) * minutes); +} + +TimeDuration TimeDuration::Hours(int64_t hours) +{ + return TimeDuration(static_cast(1000 * 60 * 60) * hours); +} + +TimeDuration TimeDuration::Days(int64_t days) +{ + return TimeDuration(static_cast(1000 * 60 * 60 * 24) * days); +} + +TimeDuration::TimeDuration() : TimeDurationBase(0) {} + +TimeDuration::TimeDuration(int64_t aMilliseconds) : TimeDurationBase(aMilliseconds) +{} + +bool operator==(const TimeDuration& lhs, const TimeDuration& rhs) +{ + return lhs.GetMilliseconds() == rhs.GetMilliseconds(); +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/openpal/executor/TimerRef.cpp b/utils/dnp3_src/cpp/libs/src/openpal/executor/TimerRef.cpp new file mode 100644 index 0000000..9730c4d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/executor/TimerRef.cpp @@ -0,0 +1,107 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/executor/TimerRef.h" + +namespace openpal +{ + +TimerRef::TimerRef(openpal::IExecutor& executor) : pExecutor(&executor), pTimer(nullptr) +{} + +TimerRef::~TimerRef() +{ + this->Cancel(); +} + + +bool TimerRef::IsActive() const +{ + return (pTimer != nullptr); +} + +MonotonicTimestamp TimerRef::ExpiresAt() const +{ + return pTimer ? pTimer->ExpiresAt() : MonotonicTimestamp::Max(); +} + +bool TimerRef::Cancel() +{ + if (pTimer) + { + pTimer->Cancel(); + pTimer = nullptr; + return true; + } + else + { + return false; + } +} + +bool TimerRef::StartAction(const TimeDuration& timeout, const action_t& action) +{ + if (pTimer) + { + return false; + } + else + { + pTimer = pExecutor->Start(timeout, action); + return true; + } +} + +bool TimerRef::StartAction(const MonotonicTimestamp& expiration, const action_t& action) +{ + if (pTimer) + { + return false; + } + else + { + pTimer = pExecutor->Start(expiration, action); + return true; + } +} + +void TimerRef::RestartAction(const TimeDuration& timeout, const action_t& action) +{ + if (pTimer) + { + pTimer->Cancel(); + } + + pTimer = pExecutor->Start(timeout, action); +} + +void TimerRef::RestartAction(const MonotonicTimestamp& expiration, const action_t& action) +{ + if (pTimer) + { + pTimer->Cancel(); + } + + pTimer = pExecutor->Start(expiration, action); +} + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/logging/Logger.cpp b/utils/dnp3_src/cpp/libs/src/openpal/logging/Logger.cpp new file mode 100644 index 0000000..694e102 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/logging/Logger.cpp @@ -0,0 +1,53 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "openpal/logging/Logger.h" + +namespace openpal +{ + +Logger::Logger(const std::shared_ptr& backend, const std::string& id, openpal::LogFilters levels) : + backend(backend), + settings(std::make_shared(id, levels)) +{} + +bool Logger::IsEnabled(const LogFilters& filters) const +{ + return backend && (settings->levels & filters); +} + +void Logger::Log(const LogFilters& filters, const char* location, const char* message) +{ + if (backend) + { + backend->Log( + LogEntry( + this->settings->id.c_str(), + filters, + location, + message + ) + ); + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/logging/StringFormatting.cpp b/utils/dnp3_src/cpp/libs/src/openpal/logging/StringFormatting.cpp new file mode 100644 index 0000000..2a4f4a0 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/logging/StringFormatting.cpp @@ -0,0 +1,87 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/logging/StringFormatting.h" + +#include "openpal/logging/LogMacros.h" +#include "openpal/util/ToHex.h" +#include "openpal/container/RSlice.h" +#include "openpal/Configure.h" + +#include +#include +#include + +namespace openpal +{ +char* AllocateCopy(char const* src) +{ + auto size = strlen(src) + 1; + char* tmp = new char[size]; +#ifdef WIN32 + strcpy_s(tmp, size, src); +#else + strcpy(tmp, src); +#endif + return tmp; +} + +void LogHex(Logger& logger, const openpal::LogFilters& filters, const openpal::RSlice& source, uint32_t firstRowSize, uint32_t otherRowSize) +{ + char buffer[MAX_LOG_ENTRY_SIZE]; + RSlice copy(source); + uint32_t rowCount = 0; + while (copy.IsNotEmpty()) + { + uint32_t rowSize = (copy.Size() < MAX_HEX_PER_LINE) ? copy.Size() : MAX_HEX_PER_LINE; + if (rowCount == 0) + { + if (firstRowSize < rowSize) + { + rowSize = firstRowSize; + } + } + else + { + if (otherRowSize < rowSize) + { + rowSize = otherRowSize; + } + } + auto region = copy.Take(rowSize); + auto pLocation = buffer; + for (uint32_t pos = 0; pos < rowSize; ++pos) + { + pLocation[0] = ToHexChar((region[pos] & 0xf0) >> 4); + pLocation[1] = ToHexChar(region[pos] & 0xf); + pLocation[2] = ' '; + pLocation += 3; + } + buffer[3 * rowSize] = '\0'; + copy.Advance(rowSize); + + logger.Log(filters, "", buffer); + + ++rowCount; + } +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/ByteSerialization.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/ByteSerialization.cpp new file mode 100644 index 0000000..4d18852 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/ByteSerialization.cpp @@ -0,0 +1,33 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/ByteSerialization.h" + +#include + +#include "openpal/util/Limits.h" + +namespace openpal +{ + +const uint8_t UInt8Simple::Max = openpal::MaxValue(); +const uint8_t UInt8Simple::Min = openpal::MinValue(); + +} diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/DoubleFloat.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/DoubleFloat.cpp new file mode 100644 index 0000000..fd272e4 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/DoubleFloat.cpp @@ -0,0 +1,80 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/DoubleFloat.h" + +#include "openpal/util/Limits.h" +#include "openpal/serialization/FloatByteOrder.h" + +#include + +namespace openpal +{ +const double DoubleFloat::Max(openpal::MaxValue()); +const double DoubleFloat::Min(openpal::MinValue()); + +union DoubleFloatUnion +{ + uint8_t bytes[8]; + double value; +}; + +double DoubleFloat::ReadBuffer(RSlice& buffer) +{ + auto ret = Read(buffer); + buffer.Advance(SIZE); + return ret; +} + +void DoubleFloat::WriteBuffer(WSlice& buffer, double value) +{ + Write(buffer, value); + buffer.Advance(SIZE); +} + +double DoubleFloat::Read(const uint8_t* data) +{ + if (FloatByteOrder::ORDER == FloatByteOrder::Value::NORMAL) + { + DoubleFloatUnion x = {{ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7] }}; + return x.value; + } + else + { + DoubleFloatUnion x = {{ data[7], data[6], data[5], data[4], data[3], data[2], data[1], data[0] }}; + return x.value; + } +} + +void DoubleFloat::Write(uint8_t* dest, double value) +{ + if (FloatByteOrder::ORDER == FloatByteOrder::Value::NORMAL) + { + memcpy(dest, &value, SIZE); + } + else + { + auto data = reinterpret_cast(&value); + uint8_t bytes[8] = { data[7], data[6], data[5], data[4], data[3], data[2], data[1], data[0] }; + memcpy(dest, bytes, SIZE); + } +} +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/FloatByteOrder.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/FloatByteOrder.cpp new file mode 100644 index 0000000..fec3d6d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/FloatByteOrder.cpp @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/FloatByteOrder.h" + + +namespace openpal +{ + +const FloatByteOrder::Value FloatByteOrder::ORDER(GetByteOrder()); + +union FloatUnion +{ + uint8_t bytes[4]; + float f; +}; + +static_assert(sizeof(FloatUnion) == 4, "Bad float union size"); + +bool FloatByteOrder::IsNormalByteOrder() +{ + FloatUnion value = {{ 0x00, 0x00, 0xA0, 0xC1 }}; + return (value.f == -20.0f); +} + +bool FloatByteOrder::IsReverseByteOrder() +{ + FloatUnion value = {{ 0xC1, 0xA0, 0x00, 0x00 }}; + return (value.f == -20.0f); +} + +FloatByteOrder::Value FloatByteOrder::GetByteOrder() +{ + if (IsNormalByteOrder()) + { + return FloatByteOrder::Value::NORMAL; + } + else if (IsReverseByteOrder()) + { + return FloatByteOrder::Value::REVERSE; + } + else + { + return FloatByteOrder::Value::UNSUPPORTED; + } +} + + +} + + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/Format.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/Format.cpp new file mode 100644 index 0000000..6274751 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/Format.cpp @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/Format.h" + +#include "openpal/serialization/Serialization.h" + +namespace openpal +{ +template +bool WriteType(WSlice& dest, const typename Serializer::Type& value) +{ + if (dest.Size() < Serializer::SIZE) + { + return false; + } + else + { + Serializer::WriteBuffer(dest, value); + return true; + } +} + +bool Format::Write(WSlice& dest, const uint8_t& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const uint16_t& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const uint32_t& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const UInt48Type& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const int16_t& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const int32_t& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const double& value) +{ + return WriteType(dest, value); +} + +bool Format::Write(WSlice& dest, const float& value) +{ + return WriteType(dest, value); +} +} + + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/Parse.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/Parse.cpp new file mode 100644 index 0000000..bf7b135 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/Parse.cpp @@ -0,0 +1,82 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/Parse.h" + +#include "openpal/serialization/Serialization.h" + +namespace openpal +{ +template +bool ParseType(RSlice& input, typename Serializer::Type& output) +{ + if (input.Size() < Serializer::SIZE) + { + return false; + } + else + { + output = Serializer::ReadBuffer(input); + return true; + } +} + +bool Parse::Read(RSlice& input, uint8_t& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, uint16_t& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, uint32_t& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, UInt48Type& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, int16_t& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, int32_t& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, double& output) +{ + return ParseType(input, output); +} + +bool Parse::Read(RSlice& input, float& output) +{ + return ParseType(input, output); +} +} + + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/SingleFloat.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/SingleFloat.cpp new file mode 100644 index 0000000..9cca9ba --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/SingleFloat.cpp @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/SingleFloat.h" + +#include "openpal/util/Limits.h" +#include "openpal/serialization/FloatByteOrder.h" + +#include + +namespace openpal +{ +const float SingleFloat::Max(openpal::MaxValue()); +const float SingleFloat::Min(openpal::MinValue()); + +union SingleFloatUnion +{ + uint8_t bytes[4]; + float value; +}; + + +float SingleFloat::ReadBuffer(RSlice& buffer) +{ + auto ret = Read(buffer); + buffer.Advance(SIZE); + return ret; +} + +void SingleFloat::WriteBuffer(WSlice& buffer, float value) +{ + Write(buffer, value); + buffer.Advance(SIZE); +} + +float SingleFloat::Read(const uint8_t* data) +{ + if (FloatByteOrder::ORDER == FloatByteOrder::Value::NORMAL) + { + SingleFloatUnion x = {{ data[0], data[1], data[2], data[3] }}; + return x.value; + } + else + { + SingleFloatUnion x = {{ data[3], data[2], data[1], data[0] }}; + return x.value; + } +} + +void SingleFloat::Write(uint8_t* dest, float value) +{ + if (FloatByteOrder::ORDER == FloatByteOrder::Value::NORMAL) + { + memcpy(dest, &value, SIZE); + } + else + { + auto data = reinterpret_cast(&value); + uint8_t bytes[4] = { data[3], data[2], data[1], data[0] }; + memcpy(dest, bytes, SIZE); + } +} +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/serialization/UInt48LE.cpp b/utils/dnp3_src/cpp/libs/src/openpal/serialization/UInt48LE.cpp new file mode 100644 index 0000000..0320202 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/serialization/UInt48LE.cpp @@ -0,0 +1,53 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/serialization/UInt48LE.h" + +namespace openpal +{ + +UInt48Type UInt48LE::Read(const uint8_t* data) +{ + return UInt48Type( + (static_cast(data[0]) << 0) | + (static_cast(data[1]) << 8) | + (static_cast(data[2]) << 16) | + (static_cast(data[3]) << 24) | + (static_cast(data[4]) << 32) | + (static_cast(data[5]) << 40)); +} + +void UInt48LE::Write(uint8_t* data, UInt48Type value) +{ + if (value > MAX) + { + value = UInt48Type(MAX); + } + + data[0] = static_cast(value & 0xFF); + data[1] = static_cast((value >> 8) & 0xFF); + data[2] = static_cast((value >> 16) & 0xFF); + data[3] = static_cast((value >> 24) & 0xFF); + data[4] = static_cast((value >> 32) & 0xFF); + data[5] = static_cast((value >> 40) & 0xFF); +} + +} + diff --git a/utils/dnp3_src/cpp/libs/src/openpal/util/Limits.cpp b/utils/dnp3_src/cpp/libs/src/openpal/util/Limits.cpp new file mode 100644 index 0000000..6d58f8d --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/util/Limits.cpp @@ -0,0 +1,127 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/util/Limits.h" + +#include +#include + +/// these are implemented in terms of cstdint +/// since AVR doesn't have std::limits +namespace openpal +{ + +template <> +uint8_t MinValue() +{ + return 0; +} + +template <> +uint8_t MaxValue() +{ + return UINT8_MAX; +} + +template <> +uint16_t MinValue() +{ + return 0; +} + +template <> +uint16_t MaxValue() +{ + return UINT16_MAX; +} + +template <> +float MinValue() +{ + return -FLT_MAX; +} + +template <> +float MaxValue() +{ + return FLT_MAX ; +} + +template <> +double MinValue() +{ + return -DBL_MAX; +} + +template <> +double MaxValue() +{ + return DBL_MAX; +} + +template <> +int16_t MinValue() +{ + return INT16_MIN; +} + +template <> +int16_t MaxValue() +{ + return INT16_MAX; +} + +template <> +int32_t MinValue() +{ + return INT32_MIN; +} + +template <> +int32_t MaxValue() +{ + return INT32_MAX; +} + +template <> +uint32_t MinValue() +{ + return 0; +} + +template <> +uint32_t MaxValue() +{ + return UINT32_MAX; +} + +template <> +int64_t MinValue() +{ + return INT64_MIN; +} + +template <> +int64_t MaxValue() +{ + return INT64_MAX; +} + +} diff --git a/utils/dnp3_src/cpp/libs/src/openpal/util/ToHex.cpp b/utils/dnp3_src/cpp/libs/src/openpal/util/ToHex.cpp new file mode 100644 index 0000000..7afda29 --- /dev/null +++ b/utils/dnp3_src/cpp/libs/src/openpal/util/ToHex.cpp @@ -0,0 +1,32 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "openpal/util/ToHex.h" + +namespace openpal +{ + +char ToHexChar(char c) +{ + return (c > 9) ? ('A' + (c - 10)) : ('0' + c); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/afl-fuzzer/main.cpp b/utils/dnp3_src/cpp/tests/afl-fuzzer/main.cpp new file mode 100644 index 0000000..d621f24 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/afl-fuzzer/main.cpp @@ -0,0 +1,129 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +using namespace openpal; +using namespace opendnp3; + +class ConsoleLogger : public openpal::ILogHandler +{ + +public: + virtual void Log(const openpal::LogEntry& entry) override final + { + //std::cout << entry.GetMessage() << std::endl; + } +}; + +class Timer : public openpal::ITimer +{ + virtual void Cancel() override {} + virtual MonotonicTimestamp ExpiresAt() override + { + return MonotonicTimestamp(0); + } +}; + +class Executor : public openpal::IExecutor +{ +public: + + Timer m_timer; + + Executor() : m_timer() {} + virtual MonotonicTimestamp GetTime() override + { + return MonotonicTimestamp(0); + } + virtual ITimer* Start(const TimeDuration& duration, const Action0& action) override + { + return &m_timer; + } + virtual ITimer* Start(const MonotonicTimestamp& expiration, const Action0& action) override + { + return &m_timer; + } + virtual void Post(const Action0& action) override {} +}; + +class LowerLayer : public ILowerLayer +{ +public: + + virtual void BeginTransmit(const openpal::ReadBufferView& buffer) override + { + fwrite(buffer, 1, buffer.Size(), stdout); + fflush(stdout); + } + +}; + +int main(int argc, char* argv[]) +{ + uint8_t buffer[4096]; + + //try to read from stdin + size_t num = fread(buffer, 1, 4096, stdin); + + ReadBufferView input(buffer, num); + + ConsoleLogger handler; + LogRoot root(&handler, "log", ~0); + auto logger = root.GetLogger(); + + OutstationConfig config; + config.params.allowUnsolicited = false; + DatabaseTemplate db = DatabaseTemplate::AllTypes(10); + + Executor exe; + LowerLayer lower; + + OContext context(config, db, logger, exe, lower, SuccessCommandHandler::Instance(), DefaultOutstationApplication::Instance()); + + Outstation outstation(context); + + outstation.OnLowerLayerUp(); + + outstation.OnReceive(ReadBufferView(buffer, num)); + /* + + std::cout << "read: " << num << std::endl; + + ReadBufferView view(buffer, static_cast(num)); + + + APDUParser::ParseAndLogAll(view, &logger); + */ +} + + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/CatchTestStart.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/CatchTestStart.cpp new file mode 100644 index 0000000..3da2194 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/CatchTestStart.cpp @@ -0,0 +1,22 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#define CATCH_CONFIG_MAIN +#include diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/TestDNP3Manager.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestDNP3Manager.cpp new file mode 100644 index 0000000..e7cc2f5 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestDNP3Manager.cpp @@ -0,0 +1,138 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +using namespace opendnp3; +using namespace asiodnp3; +using namespace asiopal; +using namespace openpal; + +#define SUITE(name) "DNP3ManagerTestSuite - " name + +const int ITERATIONS = 100; + +struct Channels +{ + Channels(DNP3Manager& manager) : + client(manager.AddTCPClient("client", levels::ALL, ChannelRetry::Default(), "127.0.0.1", "", 20000, nullptr)), + server(manager.AddTCPServer("server", levels::ALL, ChannelRetry::Default(), "0.0.0.0", 20000, nullptr)) + { + + } + + std::shared_ptr client; + std::shared_ptr server; +}; + +struct Components : Channels +{ + Components(DNP3Manager& manager) : + Channels(manager), + outstation(server->AddOutstation("outstation", SuccessCommandHandler::Create(), DefaultOutstationApplication::Create(), OutstationStackConfig(DatabaseSizes::Empty()))), + master(client->AddMaster("master", NullSOEHandler::Create(), asiodnp3::DefaultMasterApplication::Create(), MasterStackConfig())) + { + + } + + void Enable() + { + outstation->Enable(); + master->Enable(); + } + + + std::shared_ptr outstation; + std::shared_ptr master; +}; + + + +TEST_CASE(SUITE("ConstructionDestruction")) +{ + for(int i = 0; i < ITERATIONS; ++i) + { + DNP3Manager manager(std::thread::hardware_concurrency()); + Components components(manager); + components.Enable(); + } +} + +TEST_CASE(SUITE("ManualStackShutdown")) +{ + for(int i = 0; i < ITERATIONS; ++i) + { + DNP3Manager manager(std::thread::hardware_concurrency()); + Components components(manager); + components.Enable(); + + // manually shutdown the stacks prior automatic cleanup + components.outstation->Shutdown(); + components.master->Shutdown(); + } + +} + +TEST_CASE(SUITE("ManualChannelShutdownWithStacks")) +{ + for(int i = 0; i < ITERATIONS; ++i) + { + DNP3Manager manager(std::thread::hardware_concurrency()); + Components components(manager); + components.Enable(); + + // manually shutdown the channels prior automatic cleanup + components.client->Shutdown(); + components.server->Shutdown(); + } +} + +TEST_CASE(SUITE("ManualChannelShutdown")) +{ + for(int i = 0; i < ITERATIONS; ++i) + { + DNP3Manager manager(std::thread::hardware_concurrency()); + Channels channels(manager); + + channels.client->Shutdown(); + channels.server->Shutdown(); + } +} + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/TestEventIntegration.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestEventIntegration.cpp new file mode 100644 index 0000000..b97f0c2 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestEventIntegration.cpp @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include + +#include +#include + +#include +#include +#include + +#include "mocks/StackPair.h" + +using namespace opendnp3; +using namespace asiodnp3; + +#define SUITE(name) "EventIntegrationTestSuite - " name + +TEST_CASE(SUITE("TestEventIntegration")) +{ + const uint16_t START_PORT = 20000; + const uint16_t NUM_STACK_PAIRS = 10; + + const uint16_t NUM_POINTS_PER_TYPE = 50; + const uint16_t EVENTS_PER_ITERATION = 50; + const int NUM_ITERATIONS = 10; + + const uint32_t LEVELS = flags::ERR | flags::WARN; + + const auto TEST_TIMEOUT = std::chrono::seconds(5); + const auto STACK_TIMEOUT = openpal::TimeDuration::Seconds(1); + + // run with at least a concurrency of 2, but more if there are more cores + const auto concurreny = std::max(std::thread::hardware_concurrency(), 2); + + DNP3Manager manager(concurreny); + + std::vector> pairs; + + for (uint16_t i = 0; i < NUM_STACK_PAIRS; ++i) + { + auto pair = std::make_unique(LEVELS, STACK_TIMEOUT, manager, START_PORT + i, NUM_POINTS_PER_TYPE, EVENTS_PER_ITERATION); + pairs.push_back(std::move(pair)); + } + + for (auto& pair : pairs) + { + pair->WaitForChannelsOnline(TEST_TIMEOUT); + } + + const auto start = std::chrono::steady_clock::now(); + + for (int i = 0; i < NUM_ITERATIONS; ++i) + { + + for (auto& pair : pairs) + { + pair->SendRandomValues(); + } + + for (auto& pair : pairs) + { + pair->WaitToRxValues(TEST_TIMEOUT); + } + } + + const auto milliseconds = std::chrono::duration_cast(std::chrono::steady_clock::now() - start); + + const auto total_events_transferred = static_cast(NUM_STACK_PAIRS) * static_cast(EVENTS_PER_ITERATION) * static_cast(NUM_ITERATIONS); + + const auto rate = (total_events_transferred * 1000) / milliseconds.count(); + + //std::cout << total_events_transferred << " in " << milliseconds.count() << " ms == " << rate << " events per/sec" << std::endl; +} + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/TestMasterServerSmoke.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestMasterServerSmoke.cpp new file mode 100644 index 0000000..550b37e --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestMasterServerSmoke.cpp @@ -0,0 +1,98 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "catch.hpp" + +#include "asiodnp3/DNP3Manager.h" +#include "asiodnp3/DefaultMasterApplication.h" +#include "asiodnp3/DefaultListenCallbacks.h" + +#include "opendnp3/LogLevels.h" +#include "opendnp3/outstation/SimpleCommandHandler.h" +#include "opendnp3/outstation/IOutstationApplication.h" +#include "opendnp3/master/ISOEHandler.h" + +#include "asiopal/UTCTimeSource.h" +#include "asiodnp3/ConsoleLogger.h" +#include "dnp3mocks/NullSOEHandler.h" + +#include + +using namespace opendnp3; +using namespace asiodnp3; +using namespace asiopal; +using namespace openpal; + +#define SUITE(name) "MasterServerSmokeTestSuite - " name + +struct TestComponents +{ + TestComponents(DNP3Manager& manager, int numOutstations, std::error_code& ec) : + listener(manager.CreateListener("listener", levels::ALL, IPEndpoint::Localhost(20000), std::make_shared(), ec)) + { + for(int i = 0; i < numOutstations; ++i) + { + auto channel = manager.AddTCPClient("client", levels::ALL, ChannelRetry::Default(), "127.0.0.1", "", 20000, nullptr); + auto outstation = channel->AddOutstation("outstation", SuccessCommandHandler::Create(), DefaultOutstationApplication::Create(), GetConfig()); + + this->channels.push_back(channel); + this->outstations.push_back(outstation); + } + } + + void Enable() + { + for(auto& outstation : outstations) + { + outstation->Enable(); + } + } + + static OutstationStackConfig GetConfig() + { + OutstationStackConfig config(DatabaseSizes::Empty()); + config.outstation.params.allowUnsolicited = true; + return config; + } + + std::shared_ptr listener; + std::vector> channels; + std::vector> outstations; +}; + +const int ITERATIONS = 5; +const int NUM_OUTSTATIONS = 5; + +TEST_CASE(SUITE("ConstructionDestruction")) +{ + for(int i = 0; i < ITERATIONS; ++i) + { + DNP3Manager manager(std::thread::hardware_concurrency()); + std::error_code ec; + TestComponents components(manager, NUM_OUTSTATIONS, ec); + if (ec) throw std::logic_error(ec.message()); + components.Enable(); + } +} + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/TestPerfomance.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestPerfomance.cpp new file mode 100644 index 0000000..096606f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/TestPerfomance.cpp @@ -0,0 +1,98 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include + +#include +#include + +#include +#include +#include + +#include "mocks/PerformanceStackPair.h" + +using namespace opendnp3; +using namespace asiodnp3; + +#define SUITE(name) "PerformanceTestSuite - " name + +TEST_CASE(SUITE("PointsPerSecond")) +{ + const uint16_t START_PORT = 20000; + const uint16_t NUM_STACK_PAIRS = 10; + + const uint16_t NUM_POINTS_PER_TYPE = 50; + const uint16_t EVENTS_PER_ITERATION = 50; + const int NUM_ITERATIONS = 100; + + const uint32_t LEVELS = flags::ERR | flags::WARN; + + const auto TEST_TIMEOUT = std::chrono::seconds(5); + const auto STACK_TIMEOUT = openpal::TimeDuration::Seconds(1); + + // run with at least a concurrency of 2, but more if there are more cores + const auto concurrency = std::max(std::thread::hardware_concurrency(), 2); + + std::cout << "Concurrency: " << concurrency << std::endl; + + DNP3Manager manager(concurrency); + + std::vector> pairs; + + for (uint16_t i = 0; i < NUM_STACK_PAIRS; ++i) + { + auto pair = std::make_unique(LEVELS, STACK_TIMEOUT, manager, START_PORT + i, NUM_POINTS_PER_TYPE, EVENTS_PER_ITERATION); + pairs.push_back(std::move(pair)); + } + + for (auto& pair : pairs) + { + pair->WaitForChannelsOnline(TEST_TIMEOUT); + } + + const auto start = std::chrono::steady_clock::now(); + + for (int i = 0; i < NUM_ITERATIONS; ++i) + { + + for (auto& pair : pairs) + { + pair->SendValues(); + } + + for (auto& pair : pairs) + { + pair->WaitForValues(TEST_TIMEOUT); + } + + //std::cout << "iteration: " << i << std::endl; + } + + const auto milliseconds = std::chrono::duration_cast(std::chrono::steady_clock::now() - start); + + const auto total_events_transferred = static_cast(NUM_STACK_PAIRS) * static_cast(EVENTS_PER_ITERATION) * static_cast(NUM_ITERATIONS); + + const auto rate = (total_events_transferred * 1000) / milliseconds.count(); + + std::cout << total_events_transferred << " in " << milliseconds.count() << " ms == " << rate << " events per/sec" << std::endl; +} + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/CountingSOEHandler.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/CountingSOEHandler.h new file mode 100644 index 0000000..44d9389 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/CountingSOEHandler.h @@ -0,0 +1,127 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_COUNTINGSOEHANDLER_H +#define OPENDNP3_COUNTINGSOEHANDLER_H + +#include "opendnp3/master/ISOEHandler.h" + +#include +#include + +namespace opendnp3 +{ + +class CountingSOEHandler final : public opendnp3::ISOEHandler +{ + std::mutex mutex; + std::condition_variable cv; + size_t count = 0; + +public: + + void WaitForCount(size_t num, std::chrono::steady_clock::duration timeout) + { + std::unique_lock lock(mutex); + auto equals_num = [this, num]() -> bool { return this->count == num; }; + + if (!cv.wait_for(lock, timeout, equals_num)) + { + throw std::logic_error("timeout waiting for count"); + } + count -= num; + } + + virtual void Start() override + { + mutex.lock(); + } + + virtual void End() override + { + mutex.unlock(); + cv.notify_all(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + count += values.Count(); + } + + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection& values) override + { + count += values.Count(); + } +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/ExpectedValue.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/ExpectedValue.h new file mode 100644 index 0000000..0e3f968 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/ExpectedValue.h @@ -0,0 +1,101 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_EXPECTEDVALUE_H +#define OPENDNP3_EXPECTEDVALUE_H + +#include + +#include "opendnp3/app/MeasurementTypes.h" +#include "opendnp3/gen/StaticTypeBitmask.h" + +#include + +namespace opendnp3 +{ + +enum class ValueType +{ + Binary, + DoubleBitBinary, + Analog, + Counter, + FrozenCounter, + AnalogOutputStatus, + BinaryOutputStatus +}; + +class ExpectedValue final +{ + ExpectedValue(int64_t value, uint16_t index, ValueType type) : + value(value), index(index), type(type) + {} + +public: + + static const char* ToString(ValueType vt) + { + switch (vt) + { + case(ValueType::Binary): + return "Binary"; + case(ValueType::DoubleBitBinary): + return "DoubleBitBinary"; + case(ValueType::Analog): + return "Analog"; + case(ValueType::Counter): + return "Counter"; + case(ValueType::FrozenCounter): + return "FrozenCounter"; + case(ValueType::AnalogOutputStatus): + default: + return "BinaryOutputStatus"; + } + } + + bool Equals(const ExpectedValue& other) const + { + return (type == other.type) && (index == other.index) && (value == other.value); + } + + int64_t value; + uint16_t index; + ValueType type; + + ExpectedValue(const Binary& value, uint16_t index) : ExpectedValue(value.value, index, ValueType::Binary) {} + ExpectedValue(const DoubleBitBinary& value, uint16_t index) : ExpectedValue(static_cast(value.value), index, ValueType::DoubleBitBinary) {} + ExpectedValue(const Analog& value, uint16_t index) : ExpectedValue(static_cast(value.value), index, ValueType::Analog) {} + ExpectedValue(const Counter& value, uint16_t index) : ExpectedValue(value.value, index, ValueType::Counter) {} + ExpectedValue(const FrozenCounter& value, uint16_t index) : ExpectedValue(value.value, index, ValueType::FrozenCounter) {} + ExpectedValue(const AnalogOutputStatus& value, uint16_t index) : ExpectedValue(static_cast(value.value), index, ValueType::AnalogOutputStatus) {} + ExpectedValue(const BinaryOutputStatus& value, uint16_t index) : ExpectedValue(value.value, index, ValueType::BinaryOutputStatus) {} +}; + +inline std::ostream& operator<<(std::ostream& os, const ExpectedValue& v) +{ + os << v.index << " - " << ExpectedValue::ToString(v.type) << "(" << v.value << ")"; + return os; +} + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.cpp new file mode 100644 index 0000000..7f0d3b6 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.cpp @@ -0,0 +1,180 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "PerformanceStackPair.h" + +#include "asiodnp3/DefaultMasterApplication.h" +#include "opendnp3/outstation/SimpleCommandHandler.h" + +#include +#include +#include + +using namespace opendnp3; + +namespace asiodnp3 +{ + +PerformanceStackPair::PerformanceStackPair(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager& manager, uint16_t port, uint16_t numPointsPerType, uint32_t eventsPerIteration) : + PORT(port), + NUM_POINTS_PER_TYPE(numPointsPerType), + EVENTS_PER_ITERATION(eventsPerIteration), + soeHandler(std::make_shared()), + clientListener(std::make_shared()), + serverListener(std::make_shared()), + master(CreateMaster(levels, timeout, manager, port, this->soeHandler, this->clientListener)), + outstation(CreateOutstation(levels, timeout, manager, port, numPointsPerType, 3 * eventsPerIteration, this->serverListener)) +{ + this->outstation->Enable(); + this->master->Enable(); +} + +void PerformanceStackPair::WaitForChannelsOnline(std::chrono::steady_clock::duration timeout) +{ + if (!this->clientListener->WaitForState(ChannelState::OPEN, timeout)) + { + throw std::runtime_error("client timed out before opening"); + } + + if (!this->serverListener->WaitForState(ChannelState::OPEN, timeout)) + { + throw std::runtime_error("server timed out before opening"); + } +} + +void PerformanceStackPair::SendValues() +{ + UpdateBuilder builder; + for (uint32_t i = 0; i < EVENTS_PER_ITERATION; ++i) + { + AddValue(i, builder); + } + this->outstation->Apply(builder.Build()); +} + +void PerformanceStackPair::AddValue(uint32_t i, UpdateBuilder& builder) +{ + const uint16_t index = i % NUM_POINTS_PER_TYPE; + + switch (i % 7) + { + case(0): + builder.Update(Binary(i % 2 == 0), index, EventMode::Force); + break; + case(1): + builder.Update(DoubleBitBinary(i % 2 == 0 ? DoubleBit::DETERMINED_ON : DoubleBit::DETERMINED_OFF), index, EventMode::Force); + break; + case(2): + builder.Update(Analog(i), index, EventMode::Force); + break; + case(3): + builder.Update(Counter(i), index, EventMode::Force); + break; + case(4): + builder.Update(FrozenCounter(i), index, EventMode::Force); + break; + case(5): + builder.Update(BinaryOutputStatus(i % 2 == 0), index, EventMode::Force); + break; + default: + builder.Update(AnalogOutputStatus(i), index, EventMode::Force); + break; + } +} + +void PerformanceStackPair::WaitForValues(std::chrono::steady_clock::duration timeout) +{ + this->soeHandler->WaitForCount(this->EVENTS_PER_ITERATION, timeout); +} + +OutstationStackConfig PerformanceStackPair::GetOutstationStackConfig(uint16_t numPointsPerType, uint16_t eventBufferSize, openpal::TimeDuration timeout) +{ + OutstationStackConfig config(DatabaseSizes::AllTypes(numPointsPerType)); + + config.outstation.params.unsolConfirmTimeout = timeout; + config.outstation.eventBufferConfig = EventBufferConfig::AllTypes(eventBufferSize); + config.outstation.params.allowUnsolicited = true; + + return config; +} + +MasterStackConfig PerformanceStackPair::GetMasterStackConfig(openpal::TimeDuration timeout) +{ + MasterStackConfig config; + + config.master.responseTimeout = timeout; + config.master.taskRetryPeriod = timeout; + config.master.disableUnsolOnStartup = false; + config.master.startupIntegrityClassMask = ClassField::None(); + config.master.unsolClassMask = ClassField::AllEventClasses(); + + return config; +} + +std::shared_ptr PerformanceStackPair::CreateMaster(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager& manager, uint16_t port, std::shared_ptr soehandler, std::shared_ptr listener) +{ + auto channel = manager.AddTCPClient( + GetId("client", port).c_str(), + levels, + asiopal::ChannelRetry::Default(), + "127.0.0.1", + "127.0.0.1", + port, + listener + ); + + return channel->AddMaster( + GetId("master", port).c_str(), + soehandler, + DefaultMasterApplication::Create(), + GetMasterStackConfig(timeout) + ); +} + +std::shared_ptr PerformanceStackPair::CreateOutstation(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager& manager, uint16_t port, uint16_t numPointsPerType, uint16_t eventBufferSize, std::shared_ptr listener) +{ + auto channel = manager.AddTCPServer( + GetId("server", port).c_str(), + levels, + asiopal::ChannelRetry::Default(), + "127.0.0.1", + port, + listener + ); + + return channel->AddOutstation( + GetId("outstation", port).c_str(), + SuccessCommandHandler::Create(), + DefaultOutstationApplication::Create(), + GetOutstationStackConfig(numPointsPerType, eventBufferSize, timeout) + ); +} + +std::string PerformanceStackPair::GetId(const char* name, uint16_t port) +{ + std::ostringstream oss; + oss << name << ":" << port; + return oss.str(); +} +} + + + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.h new file mode 100644 index 0000000..1b11788 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/PerformanceStackPair.h @@ -0,0 +1,80 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_PERFORMANCESTACKPAIR_H +#define OPENDNP3_PERFORMANCESTACKPAIR_H + +#include "asiodnp3/DNP3Manager.h" +#include "opendnp3/LogLevels.h" + +#include "CountingSOEHandler.h" +#include "QueuedChannelListener.h" + +#include "asiodnp3/UpdateBuilder.h" + +#include +#include +#include + +namespace asiodnp3 +{ + +class PerformanceStackPair final : openpal::Uncopyable +{ + const uint16_t PORT; + const uint16_t NUM_POINTS_PER_TYPE; + const uint32_t EVENTS_PER_ITERATION; + + const std::shared_ptr soeHandler; + + std::shared_ptr clientListener; + std::shared_ptr serverListener; + + const std::shared_ptr master; + const std::shared_ptr outstation; + + static OutstationStackConfig GetOutstationStackConfig(uint16_t numPointsPerType, uint16_t eventBufferSize, openpal::TimeDuration timeout); + static MasterStackConfig GetMasterStackConfig(openpal::TimeDuration timeout); + + static std::shared_ptr CreateMaster(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager&, uint16_t port, std::shared_ptr, std::shared_ptr listener); + static std::shared_ptr CreateOutstation(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager&, uint16_t port, uint16_t numPointsPerType, uint16_t eventBufferSize, std::shared_ptr listener); + + static std::string GetId(const char* name, uint16_t port); + void AddValue(uint32_t i, UpdateBuilder& builder); + +public: + + PerformanceStackPair(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager&, uint16_t port, uint16_t numPointsPerType, uint32_t eventsPerIteration); + + void WaitForChannelsOnline(std::chrono::steady_clock::duration timeout); + + void SendValues(); + + void WaitForValues(std::chrono::steady_clock::duration timeout); + + + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuedChannelListener.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuedChannelListener.h new file mode 100644 index 0000000..6ed55f6 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuedChannelListener.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_QUEUEDCHANNELISTENER_H +#define OPENDNP3_QUEUEDCHANNELISTENER_H + +#include "SynchronizedQueue.h" + +#include "asiodnp3/IChannelListener.h" + +namespace asiodnp3 +{ +class QueuedChannelListener : public IChannelListener +{ + SynchronizedQueue states; + +public: + + virtual void OnStateChange(opendnp3::ChannelState state) override + { + states.Add(state); + } + + bool WaitForState(opendnp3::ChannelState state, std::chrono::steady_clock::duration timeout) + { + std::vector output; + while (states.DrainTo(output, timeout) > 0) + { + for (auto& s : output) + { + if (s == state) return true; + } + output.clear(); + } + + return false; + } + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuingSOEHandler.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuingSOEHandler.h new file mode 100644 index 0000000..d5e9fea --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/QueuingSOEHandler.h @@ -0,0 +1,116 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_QUEUINGSOEHANDLER_H +#define OPENDNP3_QUEUINGSOEHANDLER_H + +#include "opendnp3/master/ISOEHandler.h" + +#include "ExpectedValue.h" + +#include "SynchronizedQueue.h" + +#include +#include + +namespace opendnp3 +{ + +class QueuingSOEHandler final : public opendnp3::ISOEHandler +{ + std::mutex mutex; + std::vector temp; + + template + void ProcessAny(const ICollection>& values) + { + auto add = [this](const Indexed& item) + { + temp.push_back(ExpectedValue(item.value, item.index)); + }; + + values.ForeachItem(add); + } + +public: + + asiodnp3::SynchronizedQueue values; + + virtual void Start() override + { + mutex.lock(); + } + + virtual void End() override + { + values.AddMany(temp); + temp.clear(); + mutex.unlock(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override + { + this->ProcessAny(values); + } + + virtual void Process(const opendnp3::HeaderInfo& info, const opendnp3::ICollection& values) override {} + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override {} +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.cpp b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.cpp new file mode 100644 index 0000000..fac907f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.cpp @@ -0,0 +1,241 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "StackPair.h" + +#include "asiodnp3/DefaultMasterApplication.h" +#include "opendnp3/outstation/SimpleCommandHandler.h" + +#include +#include +#include + +using namespace opendnp3; + +namespace asiodnp3 +{ + +StackPair::StackPair(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager& manager, uint16_t port, uint16_t numPointsPerType, uint32_t eventsPerIteration) : + PORT(port), + NUM_POINTS_PER_TYPE(numPointsPerType), + EVENTS_PER_ITERATION(eventsPerIteration), + soeHandler(std::make_shared()), + clientListener(std::make_shared()), + serverListener(std::make_shared()), + master(CreateMaster(levels, timeout, manager, port, this->soeHandler, this->clientListener)), + outstation(CreateOutstation(levels, timeout, manager, port, numPointsPerType, 3 * eventsPerIteration, this->serverListener)), + index_distribution(0, numPointsPerType - 1), + type_distribution(0, 6), + bool_distribution(0, 1), + int_distribution(0, 32767) +{ + this->outstation->Enable(); + this->master->Enable(); +} + +void StackPair::WaitForChannelsOnline(std::chrono::steady_clock::duration timeout) +{ + if (!this->clientListener->WaitForState(opendnp3::ChannelState::OPEN, timeout)) + { + throw std::runtime_error("client timed out before opening"); + } + + if (!this->serverListener->WaitForState(opendnp3::ChannelState::OPEN, timeout)) + { + throw std::runtime_error("server timed out before opening"); + } +} + +void StackPair::SendRandomValues() +{ + UpdateBuilder builder; + for (uint32_t i = 0; i < EVENTS_PER_ITERATION; ++i) + { + this->tx_values.push_back(this->AddRandomValue(builder)); + } + this->outstation->Apply(builder.Build()); +} + +void StackPair::WaitToRxValues(std::chrono::steady_clock::duration timeout) +{ + while (!this->tx_values.empty()) + { + std::deque rx_values; + this->soeHandler->values.DrainTo(rx_values, timeout); + + if (rx_values.empty()) + { + std::ostringstream oss; + oss << "No values received within timeout: " << PORT; + throw std::runtime_error(oss.str()); + } + + // compare values + + while (!rx_values.empty()) + { + if (tx_values.empty()) + { + std::ostringstream oss; + oss << "more values received than transmited: " << PORT; + throw std::runtime_error(oss.str()); + } + + const auto& rx = rx_values.front(); + const auto& tx = tx_values.front(); + + if (!rx.Equals(tx)) + { + std::ostringstream oss; + oss << rx << " != " << tx; + throw std::runtime_error(oss.str()); + } + + rx_values.pop_front(); + tx_values.pop_front(); + } + } +} + +ExpectedValue StackPair::AddRandomValue(UpdateBuilder& builder) +{ + const auto index = index_distribution(generator); + + switch (type_distribution(generator)) + { + case(0): + { + opendnp3::Binary value(bool_distribution(generator) == 0); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + case(1): + { + opendnp3::DoubleBitBinary value(static_cast(bool_distribution(generator))); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + case(2): + { + opendnp3::Analog value(static_cast(int_distribution(generator))); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + case(3): + { + opendnp3::Counter value(int_distribution(generator)); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + case(4): + { + opendnp3::FrozenCounter value(int_distribution(generator)); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + case(5): + { + opendnp3::BinaryOutputStatus value(bool_distribution(generator) == 0); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + default: + { + opendnp3::AnalogOutputStatus value(static_cast(int_distribution(generator))); + builder.Update(value, index, EventMode::Force); + return ExpectedValue(value, index); + } + } +} + +OutstationStackConfig StackPair::GetOutstationStackConfig(uint16_t numPointsPerType, uint16_t eventBufferSize, openpal::TimeDuration timeout) +{ + OutstationStackConfig config(opendnp3::DatabaseSizes::AllTypes(numPointsPerType)); + + config.outstation.params.unsolConfirmTimeout = timeout; + config.outstation.eventBufferConfig = opendnp3::EventBufferConfig::AllTypes(eventBufferSize); + config.outstation.params.allowUnsolicited = true; + + return config; +} + +MasterStackConfig StackPair::GetMasterStackConfig(openpal::TimeDuration timeout) +{ + MasterStackConfig config; + + config.master.responseTimeout = timeout; + config.master.taskRetryPeriod = timeout; + config.master.disableUnsolOnStartup = false; + config.master.startupIntegrityClassMask = opendnp3::ClassField::None(); + config.master.unsolClassMask = opendnp3::ClassField::AllEventClasses(); + + return config; +} + +std::shared_ptr StackPair::CreateMaster(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager& manager, uint16_t port, std::shared_ptr soehandler, std::shared_ptr listener) +{ + auto channel = manager.AddTCPClient( + GetId("client", port).c_str(), + levels, + asiopal::ChannelRetry::Default(), + "127.0.0.1", + "127.0.0.1", + port, + listener + ); + + return channel->AddMaster( + GetId("master", port).c_str(), + soehandler, + DefaultMasterApplication::Create(), + GetMasterStackConfig(timeout) + ); +} + +std::shared_ptr StackPair::CreateOutstation(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager& manager, uint16_t port, uint16_t numPointsPerType, uint16_t eventBufferSize, std::shared_ptr listener) +{ + auto channel = manager.AddTCPServer( + GetId("server", port).c_str(), + levels, + asiopal::ChannelRetry::Default(), + "127.0.0.1", + port, + listener + ); + + return channel->AddOutstation( + GetId("outstation", port).c_str(), + opendnp3::SuccessCommandHandler::Create(), + opendnp3::DefaultOutstationApplication::Create(), + GetOutstationStackConfig(numPointsPerType, eventBufferSize, timeout) + ); +} + +std::string StackPair::GetId(const char* name, uint16_t port) +{ + std::ostringstream oss; + oss << name << ":" << port; + return oss.str(); +} +} + + + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.h new file mode 100644 index 0000000..4f8d21f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/StackPair.h @@ -0,0 +1,87 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_STACKPAIR_H +#define OPENDNP3_STACKPAIR_H + +#include "asiodnp3/DNP3Manager.h" +#include "asiodnp3/UpdateBuilder.h" +#include "opendnp3/LogLevels.h" + +#include "QueuingSOEHandler.h" +#include "QueuedChannelListener.h" + + +#include +#include +#include + +namespace asiodnp3 +{ + +class StackPair final : openpal::Uncopyable +{ + const uint16_t PORT; + const uint16_t NUM_POINTS_PER_TYPE; + const uint32_t EVENTS_PER_ITERATION; + const std::shared_ptr soeHandler; + + std::shared_ptr clientListener; + std::shared_ptr serverListener; + + const std::shared_ptr master; + const std::shared_ptr outstation; + + std::default_random_engine generator; + + std::uniform_int_distribution index_distribution; + std::uniform_int_distribution type_distribution; + std::uniform_int_distribution bool_distribution; + std::uniform_int_distribution int_distribution; + + std::deque tx_values; + + static OutstationStackConfig GetOutstationStackConfig(uint16_t numPointsPerType, uint16_t eventBufferSize, openpal::TimeDuration timeout); + static MasterStackConfig GetMasterStackConfig(openpal::TimeDuration timeout); + + static std::shared_ptr CreateMaster(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager&, uint16_t port, std::shared_ptr, std::shared_ptr listener); + static std::shared_ptr CreateOutstation(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager&, uint16_t port, uint16_t numPointsPerType, uint16_t eventBufferSize, std::shared_ptr listener); + + static std::string GetId(const char* name, uint16_t port); + + opendnp3::ExpectedValue AddRandomValue(asiodnp3::UpdateBuilder& builder); + + +public: + + StackPair(uint32_t levels, openpal::TimeDuration timeout, DNP3Manager&, uint16_t port, uint16_t numPointsPerType, uint32_t eventsPerIteration); + + void WaitForChannelsOnline(std::chrono::steady_clock::duration timeout); + + void SendRandomValues(); + + void WaitToRxValues(std::chrono::steady_clock::duration timeout); +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/SynchronizedQueue.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/SynchronizedQueue.h new file mode 100644 index 0000000..18a0779 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/SynchronizedQueue.h @@ -0,0 +1,89 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENDNP3_SYNCHRONIZEDQUEUE_H +#define OPENDNP3_SYNCHRONIZEDQUEUE_H + +#include +#include +#include +#include + +namespace asiodnp3 +{ +template +class SynchronizedQueue +{ + std::deque queue; + std::mutex mutex; + std::condition_variable cv; + +public: + + template + void AddMany(const U& collection) + { + { + std::unique_lock lock(mutex); + for (auto& item : collection) + { + queue.push_back(item); + } + } + cv.notify_one(); + } + + void Add(const T& item) + { + { + std::unique_lock lock(mutex); + queue.push_back(item); + } + cv.notify_one(); + } + + template + size_t DrainTo(U& collection, const std::chrono::steady_clock::duration& duration) + { + const auto timeout = std::chrono::steady_clock::now() + duration; + + std::unique_lock lock(mutex); + + cv.wait_until(lock, timeout, [this]() -> bool { return !this->queue.empty(); }); + + for (auto& item : queue) + { + collection.push_back(item); + } + + const auto ret = queue.size(); + + queue.clear(); + + return ret; + } + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/TestTypedefs.h b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/TestTypedefs.h new file mode 100644 index 0000000..f8f7951 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiodnp3/src/mocks/TestTypedefs.h @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __TEST_TYPEDEFS_H_ +#define __TEST_TYPEDEFS_H_ + +#include +#include + +namespace opendnp3 +{ + +class FlexibleDataObserver; +const auto G_TEST_TIMEOUT = openpal::TimeDuration::Seconds(60); + +typedef std::function EvalFunc; +typedef std::function OutputEvalFunc; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/CatchTestStart.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/CatchTestStart.cpp new file mode 100644 index 0000000..3da2194 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/CatchTestStart.cpp @@ -0,0 +1,22 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#define CATCH_CONFIG_MAIN +#include diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/TestASIO.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/TestASIO.cpp new file mode 100644 index 0000000..cc385af --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/TestASIO.cpp @@ -0,0 +1,65 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include +#include +#include + +using namespace std; +using namespace asio; + +namespace asio +{ +typedef asio::basic_waitable_timer steady_timer; +} + +void AssertCanceled(bool* apFlag, const std::error_code& ec) +{ + if(ec) *apFlag = true; +} + +void Cancel(asio::basic_waitable_timer* aptimer) +{ + aptimer->cancel(); +} + +#define SUITE(name) "TestBoostASIO - " name + +TEST_CASE(SUITE("TimerCancel")) +{ + bool flag = false; + + io_service io; + steady_timer t1(io, std::chrono::seconds(0)); + steady_timer t2(io, std::chrono::seconds(1)); + + t1.async_wait(std::bind(Cancel, &t2)); + t2.async_wait(std::bind(AssertCanceled, &flag, std::placeholders::_1)); + + io.run(); + + REQUIRE(flag); +} + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/TestStrandExecutor.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/TestStrandExecutor.cpp new file mode 100644 index 0000000..fd68241 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/TestStrandExecutor.cpp @@ -0,0 +1,165 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include + +using namespace std; +using namespace std::chrono; +using namespace openpal; +using namespace opendnp3; +using namespace asiopal; + +#define SUITE(name) "ExecutorTestSuite - " name + +TEST_CASE(SUITE("Test automatic resource reclaimation")) +{ + const int NUM_THREAD = 10; + const int NUM_STRAND = 100; + const int NUM_OPS = 1000; + + uint32_t counter[NUM_STRAND] = { 0 }; + + auto io = std::make_shared(); + + ThreadPool pool(Logger::Empty(), io, NUM_THREAD); + + auto setup = [&](uint32_t& counter) + { + auto exe = pool.CreateExecutor(); + auto increment = [&]() + { + ++counter; + }; + for (int i = 0; i < NUM_OPS; ++i) + { + exe->Post(increment); + exe->Start(TimeDuration::Milliseconds(0), increment); + } + }; + + for (int i = 0; i < NUM_STRAND; ++i) + { + setup(counter[i]); + } + + pool.Shutdown(); + + for (int i = 0; i < NUM_STRAND; ++i) + { + REQUIRE(counter[i] == 2 * NUM_OPS); + } +} + +TEST_CASE(SUITE("Executor dispatch is from only one thread at a time")) +{ + const int NUM_THREAD = 10; + const int NUM_OPS = 1000; + + auto io = std::make_shared(); + + int sum = 0; + + { + ThreadPool pool(Logger::Empty(), io, NUM_THREAD); + auto exe = pool.CreateExecutor(); + + for (int i = 0; i < NUM_OPS; ++i) + { + auto increment = [&sum]() + { + ++sum; + }; + exe->Post(increment); + } + } + + REQUIRE(sum == NUM_OPS); +} + +TEST_CASE(SUITE("Executor dispatch is in same order as post order")) +{ + const int NUM_THREAD = 10; + const int NUM_OPS = 1000; + + auto io = std::make_shared(); + + int order = 0; + bool is_ordered = true; + + { + ThreadPool pool(Logger::Empty(), io, NUM_THREAD); + auto exe = pool.CreateExecutor(); + + for (int i = 0; i < NUM_OPS; ++i) + { + auto test_order = [i, &order, &is_ordered]() + { + if (is_ordered) + { + if (i == order) + { + ++order; + } + else + { + is_ordered = false; + } + } + }; + exe->Post(test_order); + } + } + + REQUIRE(is_ordered); +} + +TEST_CASE(SUITE("Test ReturnFrom()")) +{ + const int NUM_THREAD = 10; + const int NUM_ACTIONS = 100; + int counter = 0; + + auto io = std::make_shared(); + + { + ThreadPool pool(Logger::Empty(), io, NUM_THREAD); + auto exe = pool.CreateExecutor(); + + + for (int i = 0; i < NUM_ACTIONS; ++i) + { + auto getvalue = []() -> int { return 1; }; + counter += exe->ReturnFrom(getvalue); + } + } + + + REQUIRE(counter == NUM_ACTIONS); + +} + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/TestTCPClientServer.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/TestTCPClientServer.cpp new file mode 100644 index 0000000..3558b52 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/TestTCPClientServer.cpp @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MockTCPPair.h" + +#include + +using namespace asiopal; + +#define SUITE(name) "TCPClientServerSuite - " name + +template +void WithIO(const F& fun) +{ + auto io = std::make_shared(); + fun(io); + io->RunUntilOutOfWork(); +} + +TEST_CASE(SUITE("Client and server can connect")) +{ + auto iteration = []() + { + auto test = [](const std::shared_ptr& io) + { + MockTCPPair pair(io, 20000); + pair.Connect(1); + }; + + WithIO(test); + }; + + // run multiple times to ensure the test is cleaning up after itself in terms of system resources + for (int i = 0; i < 5; ++i) + { + iteration(); + //std::cout << "iteration: " << i << " complete" << std::endl; + } +} + + + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.cpp new file mode 100644 index 0000000..bfc3814 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.cpp @@ -0,0 +1,142 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "MockIO.h" + +#include + +namespace asiopal +{ + +MockIO::Timeout::Timeout(asio::io_service& service, std::chrono::steady_clock::duration timeout) : + timer(std::make_shared>(service, timeout)) +{ + auto callback = [t = timer](const std::error_code & ec) + { + if (!ec) + { + throw std::logic_error("timeout before completion"); + } + }; + + this->timer->async_wait(callback); +} + +MockIO::Timeout::~Timeout() +{ + this->timer->cancel(); +} + +size_t MockIO::RunUntilTimeout(const std::function& condition, std::chrono::steady_clock::duration timeout) +{ + size_t iterations = 0; + Timeout to(this->service, timeout); + + while (!condition()) + { + std::error_code ec; + const auto num = this->service.run_one(ec); + if (ec) throw std::logic_error(ec.message()); + if (num == 0) + { + std::ostringstream oss; + oss << "Ran out of work after " << iterations << " iterations"; + throw std::logic_error(oss.str()); + } + + ++iterations; + + this->service.reset(); + } + + return iterations; +} + +void MockIO::CompleteInXIterations(size_t expectedIterations, const std::function& condition, std::chrono::steady_clock::duration timeout) +{ + size_t iterations = 0; + + Timeout to(this->service, timeout); + + while (!condition()) + { + if (iterations == expectedIterations) + { + std::ostringstream oss; + oss << "not complete after " << iterations << " iterations"; + throw std::logic_error(oss.str()); + } + + std::error_code ec; + const auto num = this->service.run_one(ec); + if (ec) throw std::logic_error(ec.message()); + if (num == 0) + { + std::ostringstream oss; + oss << "Ran out of work after " << iterations << " iterations"; + throw std::logic_error(oss.str()); + } + + ++iterations; + this->service.reset(); + } + + if (iterations != expectedIterations) + { + std::ostringstream oss; + oss << "completed after " << iterations << " iterations, (expected " << expectedIterations << ")"; + throw std::logic_error(oss.str()); + } + +} + +size_t MockIO::RunUntilOutOfWork() +{ + size_t iterations = 0; + + while (true) + { + std::error_code ec; + const auto num = this->service.poll_one(ec); + if (ec) throw std::logic_error(ec.message()); + + if (num == 0) + { + return iterations; + } + + ++iterations; + + this->service.reset(); + } +} + + +} + + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.h b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.h new file mode 100644 index 0000000..9cc5c00 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockIO.h @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKIO_H +#define ASIOPAL_MOCKIO_H + +#include "asiopal/Executor.h" + +#include + +namespace asiopal +{ + +class MockIO final : public IO, public std::enable_shared_from_this +{ + class Timeout + { + + public: + + Timeout(asio::io_service& service, std::chrono::steady_clock::duration timeout); + + ~Timeout(); + + private: + + std::shared_ptr> timer; + }; + +public: + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + std::shared_ptr GetExecutor() + { + return Executor::Create(this->shared_from_this()); + } + + size_t RunUntilTimeout(const std::function& condition, std::chrono::steady_clock::duration timeout = std::chrono::seconds(1)); + + void CompleteInXIterations(size_t iterations, const std::function& condition, std::chrono::steady_clock::duration timeout = std::chrono::seconds(1)); + + size_t RunUntilOutOfWork(); + +}; + +} + +#endif + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.cpp new file mode 100644 index 0000000..b8213a3 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.cpp @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "MockTCPClientHandler.h" + +#include "asiopal/SocketChannel.h" + +namespace asiopal +{ + +void MockTCPClientHandler::OnConnect(const std::shared_ptr& executor, asio::ip::tcp::socket socket, const std::error_code& ec) +{ + if (ec) + { + ++this->num_error; + throw std::logic_error(ec.message()); + } + else + { + this->channels.push_back(SocketChannel::Create(executor, std::move(socket))); + } +} + +MockTCPClientHandler::~MockTCPClientHandler() +{ + for (auto& channel : channels) + { + channel->Shutdown(); + } +} + +} + + + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.h b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.h new file mode 100644 index 0000000..c179ead --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPClientHandler.h @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKTCPCLIENTHANDLER_H +#define ASIOPAL_MOCKTCPCLIENTHANDLER_H + +#include "asiopal/IAsyncChannel.h" + +#include + +namespace asiopal +{ + +class MockTCPClientHandler final +{ + +public: + + void OnConnect(const std::shared_ptr& executor, asio::ip::tcp::socket socket, const std::error_code& ec); + + ~MockTCPClientHandler(); + + size_t num_error = 0; + + std::deque> channels; + +}; + +} + +#endif + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.cpp new file mode 100644 index 0000000..f5976fd --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.cpp @@ -0,0 +1,80 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "MockTCPPair.h" + +namespace asiopal +{ + +MockTCPPair::MockTCPPair(std::shared_ptr io, uint16_t port, std::error_code ec) : + log(), + io(io), + chandler(std::make_shared()), + client(TCPClient::Create(log.logger, io->GetExecutor(), IPEndpoint::Localhost(port), "127.0.0.1")), + server(MockTCPServer::Create(log.logger, io->GetExecutor(), IPEndpoint::Localhost(20000), ec)) +{ + if (ec) + { + throw std::logic_error(ec.message()); + } +} + +MockTCPPair::~MockTCPPair() +{ + this->server->Shutdown(); + this->client->Cancel(); +} + +void MockTCPPair::Connect(size_t num) +{ + auto callback = [handler = this->chandler](const std::shared_ptr& executor, asio::ip::tcp::socket socket, const std::error_code & ec) + { + handler->OnConnect(executor, std::move(socket), ec); + }; + + if (!this->client->BeginConnect(callback)) + { + throw std::logic_error("BeginConnect returned false"); + } + + auto connected = [this, num]() -> bool + { + return this->NumConnectionsEqual(num); + }; + + io->CompleteInXIterations(2, connected); +} + +bool MockTCPPair::NumConnectionsEqual(size_t num) const +{ + return (this->server->channels.size() == num) && (this->chandler->channels.size() == num); +} + +} + + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.h b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.h new file mode 100644 index 0000000..3c09b2c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPPair.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKTCPPAIR_H +#define ASIOPAL_MOCKTCPPAIR_H + +#include "MockIO.h" +#include "MockTCPClientHandler.h" +#include "MockTCPServer.h" + +#include "asiopal/TCPClient.h" + +#include "testlib/MockLogHandler.h" + +namespace asiopal +{ + +class MockTCPPair +{ + +public: + + MockTCPPair(std::shared_ptr io, uint16_t port, std::error_code ec = std::error_code()); + + ~MockTCPPair(); + + void Connect(size_t num = 1); + + bool NumConnectionsEqual(size_t num) const; + +private: + + testlib::MockLogHandler log; + std::shared_ptr io; + std::shared_ptr chandler; + std::shared_ptr client; + std::shared_ptr server; +}; + +} + +#endif + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPServer.h b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPServer.h new file mode 100644 index 0000000..780fb7f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/mocks/MockTCPServer.h @@ -0,0 +1,94 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKTCPSERVER_H +#define ASIOPAL_MOCKTCPSERVER_H + +#include "asiopal/TCPServer.h" +#include "asiopal/IAsyncChannel.h" +#include "asiopal/SocketChannel.h" + +#include + +namespace asiopal +{ + +class MockTCPServer final : public TCPServer +{ + +public: + + MockTCPServer( + const openpal::Logger& logger, + std::shared_ptr executor, + IPEndpoint endpoint, + std::error_code& ec + ) : TCPServer(logger, executor, endpoint, ec) + { + + } + + static std::shared_ptr Create( + const openpal::Logger& logger, + std::shared_ptr executor, + IPEndpoint endpoint, + std::error_code& ec) + { + auto server = std::make_shared(logger, executor, endpoint, ec); + + if (!ec) + { + server->StartAccept(); + } + + return server; + } + + + virtual void AcceptConnection(uint64_t sessionid, const std::shared_ptr& executor, asio::ip::tcp::socket socket) override + { + this->channels.push_back(SocketChannel::Create(executor, std::move(socket))); + } + + virtual void OnShutdown() override {} + + ~MockTCPServer() + { + for (auto& channel : channels) + { + channel->Shutdown(); + } + } + + std::deque> channels; +}; + +} + +#endif + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/tls/TestTLSClientServer.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/tls/TestTLSClientServer.cpp new file mode 100644 index 0000000..59011a4 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/tls/TestTLSClientServer.cpp @@ -0,0 +1,99 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MockTLSPair.h" + +#include +#include + +using namespace asiopal; + +#define SUITE(name) "TLS client/server suite - " name + +template +void WithIO(const F& fun) +{ + auto io = std::make_shared(); + fun(io); + io->RunUntilOutOfWork(); +} + +std::string get_path(const std::string& file) +{ + std::ostringstream oss; + oss << "../cpp/tests/asiopal/tls-certs/" << file; + return oss.str(); +} + +bool exists(const std::string& file) +{ + std::ifstream infile(file); + return infile.good(); +} + +TEST_CASE(SUITE("client and server can connect")) +{ + const auto key1 = get_path("entity1_key.pem"); + const auto key2 = get_path("entity2_key.pem"); + const auto cert1 = get_path("entity1_cert.pem"); + const auto cert2 = get_path("entity2_cert.pem"); + + if (!(exists(key1) && exists(key2) && exists(cert1) && exists(cert2))) + { + std::cout << "Could not locate one or more of the test TLS certificates. Expected to be run from the project root directory." << std::endl; + std::cout << "This test will be skipped." << std::endl; + return; + } + + auto iteration = [ = ]() + { + auto test = [ = ](const std::shared_ptr& io) + { + + + TLSConfig cfg1(cert2, cert1, key1); + TLSConfig cfg2(cert1, cert2, key2); + + MockTLSPair pair(io, 20001, cfg1, cfg2); + + pair.Connect(1); + }; + + WithIO(test); + }; + + // run multiple times to ensure the test is cleaning up after itself in terms of system resources + for (int i = 0; i < 5; ++i) + { + iteration(); + } +} + + + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSClientHandler.h b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSClientHandler.h new file mode 100644 index 0000000..142f842 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSClientHandler.h @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKTLSCLIENTHANDLER_H +#define ASIOPAL_MOCKTLSCLIENTHANDLER_H + +#include "asiopal/IAsyncChannel.h" + +#include "asiopal/tls/TLSStreamChannel.h" + +#include +#include + +namespace asiopal +{ + +class MockTLSClientHandler final +{ + +public: + + void OnConnect(const std::shared_ptr& executor, const std::shared_ptr>& stream, const std::error_code& ec) + { + if (ec) + { + ++num_error; + throw std::logic_error(ec.message()); + } + else + { + channels.push_back(TLSStreamChannel::Create(executor, stream)); + } + } + + ~MockTLSClientHandler() + { + for (auto& channel : channels) + { + channel->Shutdown(); + } + } + + size_t num_error = 0; + + std::deque> channels; + +}; + +} + +#endif + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.cpp b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.cpp new file mode 100644 index 0000000..f3a13f1 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.cpp @@ -0,0 +1,84 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "MockTLSPair.h" + +namespace asiopal +{ + + +MockTLSPair::MockTLSPair(std::shared_ptr io, uint16_t port, const TLSConfig& client, const TLSConfig& server, std::error_code ec) : + log(), + io(io), + chandler(std::make_shared()), + client(TLSClient::Create(log.logger, io->GetExecutor(), IPEndpoint::Localhost(port), "127.0.0.1", client, ec)), + server(ec ? nullptr : MockTLSServer::Create(log.logger, io->GetExecutor(), IPEndpoint::Localhost(port), server, ec)) +{ + if (ec) + { + throw std::logic_error(ec.message()); + } +} + +MockTLSPair::~MockTLSPair() +{ + this->server->Shutdown(); + this->client->Cancel(); +} + +void MockTLSPair::Connect(size_t num) +{ + auto callback = [handler = this->chandler]( + const std::shared_ptr& executor, + const std::shared_ptr>& stream, + const std::error_code & ec) + { + handler->OnConnect(executor, stream, ec); + }; + + if (!this->client->BeginConnect(callback)) + { + throw std::logic_error("BeginConnect returned false"); + } + + auto connected = [this, num]() -> bool + { + return this->NumConnectionsEqual(num); + }; + + io->CompleteInXIterations(10, connected); +} + +bool MockTLSPair::NumConnectionsEqual(size_t num) const +{ + return (this->server->channels.size() == num) && (this->chandler->channels.size() == num); +} + +} + + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.h b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.h new file mode 100644 index 0000000..4b30614 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSPair.h @@ -0,0 +1,68 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKTLSPAIR_H +#define ASIOPAL_MOCKTLSPAIR_H + +#include "../../mocks/MockIO.h" +#include "MockTLSClientHandler.h" +#include "MockTLSServer.h" + +#include "asiopal/tls/TLSClient.h" + +#include "testlib/MockLogHandler.h" + +namespace asiopal +{ + +class MockTLSPair +{ + +public: + + MockTLSPair(std::shared_ptr io, uint16_t port, const TLSConfig& client, const TLSConfig& server, std::error_code ec = std::error_code()); + + ~MockTLSPair(); + + void Connect(size_t num = 1); + + bool NumConnectionsEqual(size_t num) const; + + testlib::MockLogHandler log; + +private: + + std::shared_ptr io; + std::shared_ptr chandler; + std::shared_ptr client; + std::shared_ptr server; +}; + +} + +#endif + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSServer.h b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSServer.h new file mode 100644 index 0000000..b583beb --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/src/tls/mocks/MockTLSServer.h @@ -0,0 +1,107 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef ASIOPAL_MOCKTLSSERVER_H +#define ASIOPAL_MOCKTLSSERVER_H + +#include "asiopal/tls/TLSServer.h" +#include "asiopal/IAsyncChannel.h" +#include "asiopal/tls/TLSStreamChannel.h" + +#include + +namespace asiopal +{ + +class MockTLSServer final : public TLSServer +{ + +public: + + MockTLSServer( + const openpal::Logger& logger, + std::shared_ptr executor, + IPEndpoint endpoint, + const TLSConfig& config, + std::error_code& ec + ) : TLSServer(logger, executor, endpoint, config, ec) + { + + } + + static std::shared_ptr Create( + const openpal::Logger& logger, + std::shared_ptr executor, + IPEndpoint endpoint, + const TLSConfig& config, + std::error_code& ec) + { + auto server = std::make_shared(logger, executor, endpoint, config, ec); + + if (ec) return nullptr; + + server->StartAccept(ec); + + if (ec) return nullptr; + + return server; + } + + virtual bool AcceptConnection(uint64_t sessionid, const asio::ip::tcp::endpoint& remote) override + { + return true; + } + + virtual bool VerifyCallback(uint64_t sessionid, bool preverified, asio::ssl::verify_context& ctx) + { + return preverified; + } + + virtual void AcceptStream(uint64_t sessionid, const std::shared_ptr& executor, std::shared_ptr> stream) + { + channels.push_back(TLSStreamChannel::Create(executor, stream)); + } + + virtual void OnShutdown() {} + + + ~MockTLSServer() + { + for (auto& channel : channels) + { + channel->Shutdown(); + } + } + + std::deque> channels; +}; + +} + +#endif + + + + + + + + diff --git a/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_cert.pem b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_cert.pem new file mode 100644 index 0000000..a6e2014 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTTCCAjWgAwIBAgIJALunynUE8K2oMA0GCSqGSIb3DQEBCwUAMD0xCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJOQzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTE3MDcwNjE5MjQxOFoXDTI3MDcwNDE5MjQxOFowPTELMAkGA1UE +BhMCVVMxCzAJBgNVBAgMAk5DMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKO/V9/YnVyNrp +X6g6divKZe4uQMDu/HCr3icj/wvIGbYnXsL2q/RcRZ3AblRZaE1VCz2Zdpas19ib +BnX3e7s7z/5/ZylabSNzZNUz8LNpvybDEVHaHbv3w2GWBuZyJPU8BThfWvai9Oa9 +SJTXa7SbR1ieeCGSi+GbXm94oQ8QvasOkPiBVFnIqc66wYjalIi20U4+dm2Cu5Mj +nbKLrQ2rO9HtUJ6D9cixCtUsvAJX7nbK1hmMe7YjmU7HmznuAsk7Xbg11ngK3NJW +4X5MWrLuNV/aPh3jb10SMg0aNA5d6fT3PbgSyS6ePS5IDVU2kxfNI3czy7oc98IZ +QkR01RiLAgMBAAGjUDBOMB0GA1UdDgQWBBS0bRL03x9ZT7ALfxjcsU5O1lANaTAf +BgNVHSMEGDAWgBS0bRL03x9ZT7ALfxjcsU5O1lANaTAMBgNVHRMEBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4IBAQBCsf0atdmaTaR4LqKjPPjn9G4AIrV/yGdROR18QNut +zIyy/eDt+ahkwtj9Kg51k6V1FuM3LV8xd88PS4jyXC0Q8foF5y6qprdEN0rlfsR6 +DRxx3uF8cHIV6oM6RRmprP2mp4TaIWbD5aUGkZWxTYFn9fLM3CwsH1q6OS66K3m0 ++decNPfrV1NfD6+HcjCtGcNsL8GA/NCZCO2qUzRe9BkX8jFm6Opw7dCqmmU89+X3 +mIQX5SSFsmJieEDbknbMb0YFwuqrSbgqW9i8kKnrFcjy7oJyp6V7qEMFtsFg7S4F +jTyLtpYPlY4/tB4g6VlUDIvXFQW/RHXSAMHCUofFO/j6 +-----END CERTIFICATE----- diff --git a/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_key.pem b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_key.pem new file mode 100644 index 0000000..8112f22 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity1_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKO/V9/YnVyNrp +X6g6divKZe4uQMDu/HCr3icj/wvIGbYnXsL2q/RcRZ3AblRZaE1VCz2Zdpas19ib +BnX3e7s7z/5/ZylabSNzZNUz8LNpvybDEVHaHbv3w2GWBuZyJPU8BThfWvai9Oa9 +SJTXa7SbR1ieeCGSi+GbXm94oQ8QvasOkPiBVFnIqc66wYjalIi20U4+dm2Cu5Mj +nbKLrQ2rO9HtUJ6D9cixCtUsvAJX7nbK1hmMe7YjmU7HmznuAsk7Xbg11ngK3NJW +4X5MWrLuNV/aPh3jb10SMg0aNA5d6fT3PbgSyS6ePS5IDVU2kxfNI3czy7oc98IZ +QkR01RiLAgMBAAECggEBAJIUK2i9ehG1iwMl+JN6BnmllR1N4s7+A7jxuB4VPYJl +qCDaH0Qkw1bfZmq4hy8p2ypB+1XdxkrFgw2/5fhFJOK4hCGs9778tK3GuQZSqJYK +4EnpOdGuxrbaJ6RCCbWLoqSfNLAUObFN61nwkqrkfsnnCEk3hzCe3/Dljul4lTRG +MqT/5gfeuFz6wWHtevG431yjtxb9RgyeseWMnpnzJLIJGleY4bs/WTHvRcUD7aKc +cAXxTAUL8pNanpYaovsAARJSAHyId1aY6Y9hkyyJbXpainCP6i2WVRr3m5MzozuM +JUv518Pxver7Gt1f7E7OTy1gokCnvB0QqRM1clAsBnECgYEA+btvg3pF/DSb+dfM +f9tW1M3+0XHnRqAn1WmRRKXotZohZS0hRXEGTHQ/81dHr20IZHuTMZ1MgaEJWmG3 +yb/ServEcLzCKwlfkPtZ0JHfwbSbTIYI20fU/71DDKNeGJCLksJBKW5yYKLoxadS +lAQtEIZrInXhXGKmkcjTxhBw7WkCgYEAz09XoH8qLpjStMQS7h/jkKc5oyynZRYQ +8fhgSCim7W9NhskXJA4fQscs+HKbVnIp6LMt+l4eyJ4HCk0U5cOmT1cdk6T2wNXQ +g1Nj+SqsNREsSvVdNCDgI0F487KJam/NAwuSpZJ60kLFp4M5xl5CBfrl9AhVFF3b +EhteD96Zs9MCgYEAnkN/90W9Jok8tAhjzD939uMZcyiJVkPXGrONYYD3SmeEdHc2 +V6i6QieGA7QzdORXZj6+WLoEKz6gC8xTyiKrxCZM5tlpABcvnlT8ZWac9Eh+BvAG +mtkaDnymClNaJZ0tJvO+kgAxsjZr6B8TAUToPknBiZRFHuRSBZ/NPf9bYckCgYA9 +/X65am0lo+MV1K/IbtawcaDFj1u62X9Vq6y2xxkrVKX9EPKPgH2OjVqALF0Q23B2 +ueWcwTo5SS/Xv7bpAbkgbm9Ur/ZtMUJ5kp0Ja940vB7fh0FIjjAXusM9M/ztS+Mk +7vf59LQvXXIXJiFHlPXvLdhHQZqXTX1ti6tz2V9iqwKBgGwYtpYi6s+ke5X6GHtW +9oBzVp23LD8JxvjWiU/e6hxNbmuGvq00OR5L/9afSz9w7EnrItOI9UwiBJNb8+gI +sQ+LFrpjfPpvMjZ9wyuUQcl2P7PhRZSeWKvjeLkgFf7UKiUlLq8NYbcqHAZuRfET +q/4BlhHhmeVBmZuY8ijcXGwZ +-----END PRIVATE KEY----- diff --git a/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_cert.pem b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_cert.pem new file mode 100644 index 0000000..f4edc8d --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDTTCCAjWgAwIBAgIJALztSg/IjyZkMA0GCSqGSIb3DQEBCwUAMD0xCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJOQzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTE3MDcwNjE5MjQ0MVoXDTI3MDcwNDE5MjQ0MVowPTELMAkGA1UE +BhMCVVMxCzAJBgNVBAgMAk5DMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtbAuN/MjpHJh8 +/H0eXdHfgqUY+gIpHfXHyTyqixfdIFwBEoutmV7unaEzJT2vmPNA9IFVpGSW0yFb +Wgr4tGB6mBCjJsHEELJCdZl1JVz/lg7vPpDY8BzCCtAP+K0IefkNNLycY0VQiGj2 +v7+lTgI/hgJNh8l4bYH0WmRRs//qsqH/wnSNCyCpRC4IexvEdMrcLZ0wBi7LRhrl +D3kjZDPQ61V4/iDgWo8ygMIff8G11ka/CoJMNVsDgo+TW63r03PjmGm8QVJuM79f +vIiv8zDjy1eKW+oT+ixuGtBCX2/xkZVUqYcu6rx/vMBBwJNk7mTEy8hHxgo5FHkp +/MewWyRpAgMBAAGjUDBOMB0GA1UdDgQWBBSN/PdCO0kFRq5h8GAWfa9NgzdwnzAf +BgNVHSMEGDAWgBSN/PdCO0kFRq5h8GAWfa9NgzdwnzAMBgNVHRMEBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4IBAQBwEKbVvXvr6ChFQwMM4if1Mp8+SxzolW8xtSaeCaRM +4LL7P2LJdMxDhC/bjCgeeTN+SfrjM3QiiyVxk2ZrcRJbwKnkqE1R6OWUXHvbicvE +IMBQp+5JHhYp+TJRwdgL/jmc7eruUD1O8lRtBX8AEdRZFyoG06JthzQvyObuxTi1 +50OQ4iR9qrIXsLALFJbftDYgAT2nFX2iM8Cpq/jyQ7YcIKR8iCCaGBbHurFEFA/O +xdBrLFyAH2BcVVpYrwOf/DhOczwcrRtYW8oKMRjwXYDZG3+tsyTADRicjdmUsl13 +tqGLqqK+CHC2t0xtasE/0kAiHxFugA2pFCbgRub2iun1 +-----END CERTIFICATE----- diff --git a/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_key.pem b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_key.pem new file mode 100644 index 0000000..e5823f1 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/asiopal/tls-certs/entity2_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtbAuN/MjpHJh8 +/H0eXdHfgqUY+gIpHfXHyTyqixfdIFwBEoutmV7unaEzJT2vmPNA9IFVpGSW0yFb +Wgr4tGB6mBCjJsHEELJCdZl1JVz/lg7vPpDY8BzCCtAP+K0IefkNNLycY0VQiGj2 +v7+lTgI/hgJNh8l4bYH0WmRRs//qsqH/wnSNCyCpRC4IexvEdMrcLZ0wBi7LRhrl +D3kjZDPQ61V4/iDgWo8ygMIff8G11ka/CoJMNVsDgo+TW63r03PjmGm8QVJuM79f +vIiv8zDjy1eKW+oT+ixuGtBCX2/xkZVUqYcu6rx/vMBBwJNk7mTEy8hHxgo5FHkp +/MewWyRpAgMBAAECggEBAKq7yXBjY0UlEvdR+LhRs5Kx42qAkGn8hgHIHALm53qb +JhkkMgGaEj0nURGyY1WiZjIXxdEUBLf8akWuk0ihBK8NUKvfNzqZGXaWopsTSsiR +6mgdl6sMUbOzw31F3MyQkOIwflQU46PSeEwdIUdUUqBJhbDgszftz9hKuaM6bASZ +c0uWxiOVyNVayJ7/pSFb720R2cvVn/pIwZHnuPzFmXL19YGIZmWJzq0ABgBZik1P +4VS7dkJ7vCAM2Cpihp9Kxc1q2rdRuigmcPxjGkKIyjdu9fya/qMdxmgoGRP+7rD1 +F+xQVuVH7lGVGH2PcUW14Kzy+8LJf8t05QNvFqiOqgECgYEA4aHigQ588LMMFXgv +yzjxQ1ceUzMbT7Rv4AB2nwyaOTPa4KLcWhwN0B/9h0fwwh8klbyqt74ASJg7FQ8C +k6FAvbM/gwpuC+fN3eWad3lKVo8OVjzi5xaMouRBAUxmfyo6NYpLd6K8SYRBiPgV +kYfk3gQLh5zBVfhjAQTCc4KWEkECgYEAxMND4Pa5uCQCBjO1+EmVDjkh+TPukvUT +pIfFhU0f0sB1YYUNZw7kSbJULUhs9Pe7P0C8QCaB7IQ3YXnVumeUUnrTitBb5Le6 +4FXG1NSdENio4BIl0OOtBblLaSQuIwGYj1ySeilEcZZwLncH7nX0rLFZh63Lc6yx +/b6ZUbVUOCkCgYEAz1EIpt5iDGPnkX6KI6dhfyd4FKhbyuOW+/JRDBjvR+oOjeL2 +ptEqG/aY5AlE/YjR+8eL8SJiblF50AKnsnAy5Vri24vky4mlDeMfB/HpTRlK6hAt +yHlepXknBYNmlid9rp4wc2+So9YixTB12O9NanW7BlMRDeYZSeFOrgXp0EECgYBk +5VQ7WYkmeaBoGcAoD2NVpcpcBVtDFFT8O3r3vfKhmXsXhKi4vhQmDkHH7qmgfCAS +cVmW86gP5kSXwWftbAvMt5seRXW5tNUpEBMjM9tOtiryq5ukn/srQjb/NURLQxg9 ++1RJPDwSmvfve64fg3Dx1Qd54Y7AREAJQ+FO2tLS8QKBgC8MsKsfxLeB00acYJb+ +rYoTaeTvccdpppk10qQN/VSqFRgGKfk1Ew7038YhRH/KiBM7QGb8tCapZEXO0ljh +Po6xcZDrsle47/SYVRIjeDeHbwESl08shJhg4EyjqTUWgMnPWHkrv1chKFs+D7Nc +eZPoP5I4JMPWberDjsNevfSp +-----END PRIVATE KEY----- diff --git a/utils/dnp3_src/cpp/tests/libs/src/catch.hpp b/utils/dnp3_src/cpp/tests/libs/src/catch.hpp new file mode 100644 index 0000000..de61226 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/catch.hpp @@ -0,0 +1,9416 @@ +/* + * Catch v1.2.1 + * Generated: 2015-06-30 18:23:27.961086 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// #included from: internal/catch_suppress_warnings.h + +#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif + +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include +#include +#include + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +#endif + +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +#endif + +#endif // _MSC_VER + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// catch all support for C++11 +#if (__cplusplus >= 201103L) + +# define CATCH_CPP11_OR_GREATER + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +#define CATCH_CONFIG_VARIADIC_MACROS +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +namespace Catch { + + class NonCopyable { +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template + class Ptr { + public: + Ptr() : m_p( NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() { return m_p; } + const T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; + + }; +} + +namespace Catch { + +template +class MethodTestCase : public SharedImpl { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +struct AutoReg { + + AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template + AutoReg( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + registerTestCase( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } + + void registerTestCase( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template + class Evaluator{}; + + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return opCast( lhs ) == opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) != opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) < opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) > opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) >= opCast( rhs ); + } + }; + template + struct Evaluator { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) <= opCast( rhs ); + } + }; + + template + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator::evaluate( lhs, rhs ); + } + + // unsigned X to int + template bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // unsigned X to long + template bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + template bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator( lhs, static_cast( rhs ) ); + } + + // int to unsigned X + template bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // long to unsigned X + template bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template bool compare( long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template bool compare( int lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, int rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template bool compare( std::nullptr_t, T* rhs ) { + return Evaluator::evaluate( NULL, rhs ); + } + template bool compare( T* lhs, std::nullptr_t ) { + return Evaluator::evaluate( lhs, NULL ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CONFIG_CPP11_TUPLE +#include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM +#include +#endif + +namespace Catch { + +// Why we're here. +template +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern std::string unprintableString; + + struct BorgType { + template BorgType( T const& ); + }; + + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template + struct EnumStringMaker + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast::type>(v) + ); + } + }; +#endif + template + struct StringMakerBase { +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) + template + static std::string convert( T const& v ) + { + return EnumStringMaker::convert( v ); + } +#else + template + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template +struct StringMaker : + Detail::StringMakerBase::value> {}; + +template +struct StringMaker { + template + static std::string convert( U* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +template +struct StringMaker { + static std::string convert( R C::* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template +//struct StringMaker > { +// static std::string convert( std::vector const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template +std::string toString( std::vector const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CONFIG_CPP11_TUPLE + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get(tuple)); + ElementPrinter::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template +struct StringMaker> { + + static std::string convert( const std::tuple& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif // CATCH_CONFIG_CPP11_TUPLE + +namespace Detail { + template + std::string makeString( T const& value ) { + return StringMaker::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template +std::string toString( T const& value ) { + return StringMaker::convert( value ); +} + + namespace Detail { + template + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + template + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { + return ExpressionLhs( *this, operand ); + } + + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { + return ExpressionLhs( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + ( __catchResult <= expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include +#include +#include +#include + +namespace Catch { + +template +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template +class BetweenGenerator : public IGenerator { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast( index ); + } + + virtual std::size_t size() const { + return static_cast( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template +class ValuesGenerator : public IGenerator { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector m_values; +}; + +template +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector*>::const_iterator it = m_composed.begin(); + typename std::vector*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template + CompositeGenerator between( T from, T to ) { + CompositeGenerator generators; + generators.add( new BetweenGenerator( from, to ) ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3 ){ + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template + CompositeGenerator values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator generators; + ValuesGenerator* valuesGen = new ValuesGenerator(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate() const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate() const { + try { + throw; + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector > > m_matchers; + }; + + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct Equals : MatcherImpl { + Equals( std::string const& str ) : m_str( str ){} + Equals( Equals const& other ) : m_str( other.m_str ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_str == expr; + } + virtual std::string toString() const { + return "equals: \"" + m_str + "\""; + } + + std::string m_str; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr ) : m_substr( substr ){} + Contains( Contains const& other ) : m_substr( other.m_substr ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr ) : m_substr( substr ){} + StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr ) : m_substr( substr ){} + EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == expr.size() - m_substr.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str ) { + return Impl::StdString::Equals( str ); + } + inline Impl::StdString::Equals Equals( const char* str ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); + } + inline Impl::StdString::Contains Contains( std::string const& substr ) { + return Impl::StdString::Contains( substr ); + } + inline Impl::StdString::Contains Contains( const char* substr ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != NULL; } + bool none() const { return nullableValue == NULL; } + + bool operator !() const { return nullableValue == NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set tags; + std::set lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template + struct StringHolder : MatcherImpl{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_runner.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { + if( startsWith( m_name, "*" ) ) { + m_name = m_name.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_name, "*" ) ) { + m_name = m_name.substr( 0, m_name.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_name == toLower( testCase.name ); + case WildcardAtStart: + return endsWith( toLower( testCase.name ), m_name ); + case WildcardAtEnd: + return startsWith( toLower( testCase.name ), m_name ); + case WildcardAtBothEnds: + return contains( toLower( testCase.name ), m_name ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string m_name; + WildcardPosition m_wildcard; + }; + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr m_underlyingPattern; + }; + + struct Filter { + std::vector > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual bool forceColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +#include + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + class Stream { + public: + Stream(); + Stream( std::streambuf* _streamBuf, bool _isOwned ); + void release(); + + std::streambuf* streamBuf; + + private: + bool isOwned; + }; + + std::ostream& cout(); + std::ostream& cerr(); +} + +#include +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + forceColour( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool forceColour; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + + std::string reporterName; + std::string outputFilename; + std::string name; + std::string processName; + + std::vector testsOrTags; + }; + + class Config : public SharedImpl { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + : m_os( Catch::cout().rdbuf() ) + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_os( Catch::cout().rdbuf() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + m_os.rdbuf( Catch::cout().rdbuf() ); + m_stream.release(); + } + + void setFilename( std::string const& filename ) { + m_data.outputFilename = filename; + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + void setStreamBuf( std::streambuf* buf ) { + m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); + } + + void useStream( std::string const& streamName ) { + Stream stream = createStream( streamName ); + setStreamBuf( stream.streamBuf ); + m_stream.release(); + m_stream = stream; + } + + std::string getReporterName() const { return m_data.reporterName; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_os; } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual bool forceColour() const { return m_data.forceColour; } + + private: + ConfigData m_data; + + Stream m_stream; + mutable std::ostream m_os; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +# endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != NULL; + } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template + class CommandLine { + + struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} + + using CommonArgProperties::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + // NOTE: std::auto_ptr is deprecated in c++11/c++0x +#if defined(__cplusplus) && __cplusplus > 199711L + typedef std::unique_ptr ArgAutoPtr; +#else + typedef std::auto_ptr ArgAutoPtr; +#endif + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember( field ); + } + template + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const * const * argv ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + validate(); + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine makeCommandLineParser() { + + using namespace Clara; + CommandLine cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &ConfigData::reporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes/no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output" ) + .bind( &ConfigData::forceColour ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = LightGrey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Yellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include +#include +#include +#include + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template + struct LazyStat : Option { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map FactoryMap; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + }; + +} + +#include +#include + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map tagCounts; + + std::vector matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_runner_impl.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { +namespace SectionTracking { + + class TrackedSection { + + typedef std::map TrackedSections; + + public: + enum RunState { + NotStarted, + Executing, + ExecutingChildren, + Completed + }; + + TrackedSection( std::string const& name, TrackedSection* parent ) + : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + {} + + RunState runState() const { return m_runState; } + + TrackedSection* findChild( std::string const& childName ); + TrackedSection* acquireChild( std::string const& childName ); + + void enter() { + if( m_runState == NotStarted ) + m_runState = Executing; + } + void leave(); + + TrackedSection* getParent() { + return m_parent; + } + bool hasChildren() const { + return !m_children.empty(); + } + + private: + std::string m_name; + RunState m_runState; + TrackedSections m_children; + TrackedSection* m_parent; + }; + + inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { + TrackedSections::iterator it = m_children.find( childName ); + return it != m_children.end() + ? &it->second + : NULL; + } + inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { + if( TrackedSection* child = findChild( childName ) ) + return child; + m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); + return findChild( childName ); + } + inline void TrackedSection::leave() { + for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); + it != itEnd; + ++it ) + if( it->second.runState() != Completed ) { + m_runState = ExecutingChildren; + return; + } + m_runState = Completed; + } + + class TestCaseTracker { + public: + TestCaseTracker( std::string const& testCaseName ) + : m_testCase( testCaseName, NULL ), + m_currentSection( &m_testCase ), + m_completedASectionThisRun( false ) + {} + + bool enterSection( std::string const& name ) { + TrackedSection* child = m_currentSection->acquireChild( name ); + if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) + return false; + + m_currentSection = child; + m_currentSection->enter(); + return true; + } + void leaveSection() { + m_currentSection->leave(); + m_currentSection = m_currentSection->getParent(); + assert( m_currentSection != NULL ); + m_completedASectionThisRun = true; + } + + bool currentSectionHasChildren() const { + return m_currentSection->hasChildren(); + } + bool isCompleted() const { + return m_testCase.runState() == TrackedSection::Completed; + } + + class Guard { + public: + Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { + m_tracker.enterTestCase(); + } + ~Guard() { + m_tracker.leaveTestCase(); + } + private: + Guard( Guard const& ); + void operator = ( Guard const& ); + TestCaseTracker& m_tracker; + }; + + private: + void enterTestCase() { + m_currentSection = &m_testCase; + m_completedASectionThisRun = false; + m_testCase.enter(); + } + void leaveTestCase() { + m_testCase.leave(); + } + + TrackedSection m_testCase; + TrackedSection* m_currentSection; + bool m_completedASectionThisRun; + }; + +} // namespace SectionTracking + +using SectionTracking::TestCaseTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include +#include + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr const& config, Ptr const& reporter ) + : m_runInfo( config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( NULL ), + m_config( config ), + m_reporter( reporter ), + m_prevRunner( m_context.getRunner() ), + m_prevResultCapture( m_context.getResultCapture() ), + m_prevConfig( m_context.getConfig() ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + m_context.setRunner( m_prevRunner ); + m_context.setConfig( NULL ); + m_context.setResultCapture( m_prevResultCapture ); + m_context.setConfig( m_prevConfig ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + m_testCaseTracker = TestCaseTracker( testInfo.name ); + + do { + do { + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isCompleted() && !aborting() ); + } + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = NULL; + m_testCaseTracker.reset(); + + return deltaTotals; + } + + Ptr config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + if( !m_testCaseTracker->enterSection( oss.str() ) ) + return false; + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 || + !m_config->warnAboutMissingAssertions() || + m_testCaseTracker->currentSectionHasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { + if( std::uncaught_exception() ) { + m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); + return; + } + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + m_testCaseTracker->leaveSection(); + + m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + TestCaseTracker::Guard guard( *m_testCaseTracker ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + m_unfinishedSections.clear(); + } + + struct UnfinishedSections { + UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) + : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo info; + Counts prevAssertions; + double durationInSeconds; + }; + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + Option m_testCaseTracker; + AssertionResult m_lastResult; + + Ptr m_config; + Totals m_totals; + Ptr m_reporter; + std::vector m_messages; + IRunner* m_prevRunner; + IResultCapture* m_prevResultCapture; + Ptr m_prevConfig; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include +#include +#include + +namespace Catch { + + class Runner { + + public: + Runner( Ptr const& config ) + : m_config( config ) + { + openStream(); + makeReporter(); + } + + Totals runTests() { + + RunContext context( m_config.get(), m_reporter ); + + Totals totals; + + context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + + TestSpec testSpec = m_config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); + + int testsRunForGroup = 0; + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + + if( context.aborting() ) + break; + + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); + } + } + std::vector skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + + context.testGroupEnded( "all tests", totals, 1, 1 ); + return totals; + } + + private: + void openStream() { + // Open output file, if specified + if( !m_config->getFilename().empty() ) { + m_ofs.open( m_config->getFilename().c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << m_config->getFilename() << "'"; + throw std::domain_error( oss.str() ); + } + m_config->setStreamBuf( m_ofs.rdbuf() ); + } + } + void makeReporter() { + std::string reporterName = m_config->getReporterName().empty() + ? "console" + : m_config->getReporterName(); + + m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); + if( !m_reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + } + + private: + Ptr m_config; + std::ofstream m_ofs; + Ptr m_reporter; + std::set m_testsAlreadyRun; + }; + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char* const argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + std::srand( m_configData.rngSeed ); + + Runner runner( m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return static_cast( runner.runTests().assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits::max)(); + } + } + + Clara::CommandLine const& cli() const { + return m_cli; + } + std::vector const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + + private: + Clara::CommandLine m_cli; + std::vector m_unusedTokens; + ConfigData m_configData; + Ptr m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace Catch { + + class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i const& getAllTests() const { + return m_functionsInOrder; + } + + virtual std::vector const& getAllNonHiddenTests() const { + return m_nonHiddenFunctions; + } + + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { + + for( std::vector::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); + if( includeTest != negated ) + matchingTestCases.push_back( *it ); + } + sortTests( config, matchingTestCases ); + } + + private: + + static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } + std::set m_functions; + std::vector m_functionsInOrder; + std::vector m_nonHiddenFunctions; + size_t m_unnamedCount; + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + AutoReg::~AutoReg() {} + + void AutoReg::registerTestCase( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() { + deleteAllValues( m_factories ); + } + + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + + FactoryMap const& getFactories() const { + return m_factories; + } + + private: + FactoryMap m_factories; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + throw; + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + throw; +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return tryTranslators( m_translators.begin() ); + } + } + + std::string tryTranslators( std::vector::const_iterator it ) const { + if( it == m_translators.end() ) + return "Unknown exception"; + + try { + return (*it)->translate(); + } + catch(...) { + return tryTranslators( it+1 ); + } + } + + private: + std::vector m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerTest( TestCase const& testInfo ) { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include + +namespace Catch { + + template + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + Stream::Stream() + : streamBuf( NULL ), isOwned( false ) + {} + + Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) + : streamBuf( _streamBuf ), isOwned( _isOwned ) + {} + + void Stream::release() { + if( isOwned ) { + delete streamBuf; + streamBuf = NULL; + isOwned = false; + } + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map m_generatorsByTestName; + }; + + namespace { + Context* currentContext = NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + Stream createStream( std::string const& streamName ) { + if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); + if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); + if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); + + throw std::domain_error( "Unknown stream: " + streamName ); + } + + void cleanUpContext() { + delete currentContext; + currentContext = NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalAttributes = csbiInfo.wAttributes; + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + } + HANDLE stdoutHandle; + WORD originalAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0:34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr config = getCurrentContext().getConfig(); + return (config && config->forceColour()) || isatty(STDOUT_FILENO) + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = isDebuggerActive() + ? NoColourImpl::instance() + : platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector::const_iterator it = m_generatorsInOrder.begin(); + std::vector::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map m_generatorsByName; + std::vector m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + tags( _tags ), + lineInfo( _lineInfo ), + properties( None ) + { + std::ostringstream oss; + for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); + lcaseTags.insert( lcaseTag ); + } + tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 2, 1, "", 0 ); + +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl + { + public: + LegacyReporterAdapter( Ptr const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include +#else +#include +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency( reinterpret_cast( &hz ) ); + QueryPerformanceCounter( reinterpret_cast( &hzo ) ); + } + uint64_t t; + QueryPerformanceCounter( reinterpret_cast( &t ) ); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,NULL); + return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) + getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include + +#ifdef CATCH_PLATFORM_MAC + + #include + #include + #include + #include + #include + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + std::string unprintableString = "{?}"; + + namespace { + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + oss << value; + if( value >= 255 ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + oss << value; + if( value >= 255 ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast( value ) ); +} + +template +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +#include +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option TagAliasRegistry::find( std::string const& alias ) const { + std::map::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include + +namespace Catch { + + struct StreamingReporterBase : SharedImpl { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + + virtual ~StreamingReporterBase(); + + virtual void noMatchingTestCases( std::string const& ) {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + }; + + struct CumulativeReporterBase : SharedImpl { + template + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector > ChildSections; + typedef std::vector Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node TestCaseNode; + typedef Node TestGroupNode; + typedef Node TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + ~CumulativeReporterBase(); + + virtual void testRunStarting( TestRunInfo const& ) {} + virtual void testGroupStarting( GroupInfo const& ) {} + + virtual void testCaseStarting( TestCaseInfo const& ) {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + Ptr node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + Ptr node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) { + Ptr node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) {} + + Ptr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector > > m_sections; + std::vector > m_testCases; + std::vector > m_testGroups; + + std::vector > m_testRuns; + + Ptr m_rootSection; + Ptr m_deepestSection; + std::vector > m_sectionStack; + + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include +#include +#include + +namespace Catch { + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) { + stream() << " " << name << "=\""; + writeEncodedText( attribute ); + stream() << "\""; + } + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + if( !name.empty() ) + stream() << " " << name << "=\"" << attribute << "\""; + return *this; + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + writeEncodedText( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << ""; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + void writeEncodedText( std::string const& text ) { + static const char* charsToEncode = "<&\""; + std::string mtext = text; + std::string::size_type pos = mtext.find_first_of( charsToEncode ); + while( pos != std::string::npos ) { + stream() << mtext.substr( 0, pos ); + + switch( mtext[pos] ) { + case '<': + stream() << "<"; + break; + case '&': + stream() << "&"; + break; + case '\"': + stream() << """; + break; + } + mtext = mtext.substr( pos+1 ); + pos = mtext.find_first_of( charsToEncode ); + } + stream() << mtext; + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + {} + + virtual ~XmlReporter(); + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + {} + + ~JunitReporter(); + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter(); + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { + for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * const argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( " Given: " desc, "" ) +#define WHEN( desc ) SECTION( " When: " desc, "" ) +#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) +#define THEN( desc ) SECTION( " Then: " desc, "" ) +#define AND_THEN( desc ) SECTION( " And: " desc, "" ) + +using Catch::Detail::Approx; + +// #included from: internal/catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.cpp b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.cpp new file mode 100644 index 0000000..dafc761 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.cpp @@ -0,0 +1,452 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUHexBuilders.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +namespace hex +{ +std::string repeat(uint8_t value, uint16_t count) +{ + Buffer buffer(count); + buffer.GetWSlice().SetAllTo(value); + return ToHex(buffer.ToRSlice()); +} + +std::string ClassTask(FunctionCode fc, uint8_t seq, const ClassField& field) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest request(buffer.GetWSlice()); + opendnp3::build::ClassRequest(request, fc, field, seq); + return ToHex(request.ToRSlice()); +} + +std::string IntegrityPoll(uint8_t seq, const ClassField& field) +{ + return ClassTask(FunctionCode::READ, seq, field); +} + +std::string ClassPoll(uint8_t seq, PointClass pc) +{ + return ClassTask(FunctionCode::READ, seq, ClassField(pc)); +} + +std::string EventPoll(uint8_t seq, const ClassField& field) +{ + return ClassTask(FunctionCode::READ, seq, field); +} + +std::string ClearRestartIIN(uint8_t seq) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest request(buffer.GetWSlice()); + build::ClearRestartIIN(request, seq); + return ToHex(request.ToRSlice()); +} + +std::string MeasureDelay(uint8_t seq) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest request(buffer.GetWSlice()); + build::MeasureDelay(request, seq); + return ToHex(request.ToRSlice()); +} + +std::string Control(opendnp3::FunctionCode code, uint8_t seq, const opendnp3::ControlRelayOutputBlock& crob, uint16_t index) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest request(buffer.GetWSlice()); + + request.SetControl(AppControlField::Request(seq)); + request.SetFunction(code); + + auto writer = request.GetWriter(); + writer.WriteSingleIndexedValue(QualifierCode::UINT16_CNT_UINT16_INDEX, Group12Var1::Inst(), crob, index); + + + return ToHex(request.ToRSlice()); +} + +std::string EmptyResponse(uint8_t seq, const opendnp3::IINField& iin) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse response(buffer.GetWSlice()); + response.SetFunction(FunctionCode::RESPONSE); + response.SetControl(AppControlField(true, true, false, false, seq)); + response.SetIIN(iin); + return ToHex(response.ToRSlice()); +} + +std::string EmptyAuthResponse(uint8_t seq, const opendnp3::IINField& iin) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse response(buffer.GetWSlice()); + response.SetFunction(FunctionCode::AUTH_RESPONSE); + response.SetControl(AppControlField(true, true, false, false, seq)); + response.SetIIN(iin); + return ToHex(response.ToRSlice()); +} + +std::string NullUnsolicited(uint8_t seq, const IINField& iin) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse response(buffer.GetWSlice()); + build::NullUnsolicited(response, seq, iin); + return ToHex(response.ToRSlice()); +} + +std::string SolicitedConfirm(uint8_t seq) +{ + return Confirm(seq, false); +} + +std::string UnsolConfirm(uint8_t seq) +{ + return Confirm(seq, true); +} + +std::string Confirm(uint8_t seq, bool unsol) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, unsol, seq)); + apdu.SetFunction(FunctionCode::CONFIRM); + return ToHex(apdu.ToRSlice()); +} + +// ----------- sec auth ------------- + +std::string RequestKeyStatus(uint8_t seq, uint16_t user) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_REQUEST); + Group120Var4 status; + status.userNum = user; + apdu.GetWriter().WriteSingleValue(QualifierCode::UINT8_CNT, status); + return ToHex(apdu.ToRSlice()); +} + +std::string AuthErrorResponse( + opendnp3::IINField iin, + uint8_t appSeq, + uint32_t challengeSeqNum, + uint16_t user, + uint16_t assocId, + opendnp3::AuthErrorCode code, + opendnp3::DNPTime timestamp, + std::string hexErrorText) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse apdu(buffer.GetWSlice()); + + apdu.SetControl(AppControlField(true, true, false, false, appSeq)); + apdu.SetFunction(FunctionCode::AUTH_RESPONSE); + apdu.SetIIN(iin); + + HexSequence hexErrorTextBuff(hexErrorText); + + Group120Var7 error( + challengeSeqNum, + user, + assocId, + code, + timestamp, + hexErrorTextBuff.ToRSlice() + ); + + apdu.GetWriter().WriteFreeFormat(error); + + return ToHex(apdu.ToRSlice()); +} + +std::string ChallengeResponse( + opendnp3::IINField iin, + uint8_t seq, + uint32_t csq, + uint16_t user, + HMACType hmacType, + ChallengeReason reason, + std::string challengeDataHex +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse apdu(buffer.GetWSlice()); + + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_RESPONSE); + apdu.SetIIN(iin); + + HexSequence challengeBuff(challengeDataHex); + + Group120Var1 rsp( + csq, + user, + hmacType, + reason, + challengeBuff.ToRSlice() + ); + + apdu.GetWriter().WriteFreeFormat(rsp); + + return ToHex(apdu.ToRSlice()); +} + +std::string ChallengeReply( + uint8_t appSeq, + uint32_t challengeSeqNum, + uint16_t userNum, + std::string hmacHex +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + + apdu.SetControl(AppControlField(true, true, false, false, appSeq)); + apdu.SetFunction(FunctionCode::AUTH_REQUEST); + + HexSequence hmacBuff(hmacHex); + + Group120Var2 rsp(challengeSeqNum, userNum, hmacBuff.ToRSlice()); + + apdu.GetWriter().WriteFreeFormat(rsp); + + return ToHex(apdu.ToRSlice()); +} + +std::string KeyStatusResponse( + IINField iin, + uint8_t seq, + uint32_t ksq, + uint16_t user, + KeyWrapAlgorithm keyWrap, + KeyStatus status, + HMACType hmacType, + const std::string& challenge, + const std::string& hmac +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_RESPONSE); + apdu.SetIIN(iin); + + HexSequence challengeBuff(challenge); + HexSequence hmacBuff(hmac); + + Group120Var5 rsp; + rsp.keyChangeSeqNum = ksq; + rsp.userNum = user; + rsp.keyWrapAlgo = keyWrap; + rsp.keyStatus = status; + rsp.hmacAlgo = hmacType; + rsp.challengeData = challengeBuff.ToRSlice(); + rsp.hmacValue = hmacBuff.ToRSlice(); + + apdu.GetWriter().WriteFreeFormat(rsp); + + return ToHex(apdu.ToRSlice()); +} + +std::string KeyChangeRequest( + uint8_t seq, + uint32_t ksq, + uint16_t user, + const std::string& keyWrapData +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_REQUEST); + + HexSequence keyBuffer(keyWrapData); + + Group120Var6 rsp; + rsp.keyChangeSeqNum = ksq; + rsp.userNum = user; + rsp.keyWrapData = keyBuffer.ToRSlice(); + + apdu.GetWriter().WriteFreeFormat(rsp); + + return ToHex(apdu.ToRSlice()); +} + +std::string UserStatusChangeRequest( + uint8_t seq, + opendnp3::KeyChangeMethod keyChangeMethod, + opendnp3::UserOperation userOperation, + uint32_t statusChangeSeqNum, + uint16_t userRole, + uint16_t userRoleExpDays, + const std::string& userName, + const std::string& userPublicKeyHex, + const std::string& certificationDataHex +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_REQUEST); + + RSlice name(reinterpret_cast(userName.c_str()), static_cast(userName.size())); + HexSequence userPublicKeyBuffer(userPublicKeyHex); + HexSequence certificationDataBuffer(certificationDataHex); + + Group120Var10 statusChange( + keyChangeMethod, + userOperation, + statusChangeSeqNum, + userRole, + userRoleExpDays, + name, + userPublicKeyBuffer.ToRSlice(), + certificationDataBuffer.ToRSlice() + ); + + + apdu.GetWriter().WriteFreeFormat(statusChange); + + return ToHex(apdu.ToRSlice()); +} + +std::string BeginUpdateKeyChangeRequest( + uint8_t seq, + opendnp3::KeyChangeMethod method, + const std::string& username, + const std::string& masterChallenge +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_REQUEST); + + RSlice name(reinterpret_cast(username.c_str()), static_cast(username.size())); + HexSequence challenge(masterChallenge); + + apdu.GetWriter().WriteFreeFormat(Group120Var11(method, name, challenge)); + + return ToHex(apdu.ToRSlice()); +} + +std::string BeginUpdateKeyChangeResponse( + uint8_t seq, + uint32_t ksq, + uint16_t user, + const std::string& outstationChallenge +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_RESPONSE); + apdu.SetIIN(IINBit::DEVICE_RESTART); + + HexSequence challenge(outstationChallenge); + + apdu.GetWriter().WriteFreeFormat(Group120Var12(ksq, user, challenge)); + + return ToHex(apdu.ToRSlice()); +} + +std::string FinishUpdateKeyChangeRequest( + uint8_t seq, + uint32_t ksq, + uint16_t user, + const std::string& encryptedData, + const std::string& hmac +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDURequest apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_REQUEST); + + HexSequence encryptedBuffer(encryptedData); + HexSequence hmacBuffer(hmac); + + auto writer = apdu.GetWriter(); + + writer.WriteFreeFormat(Group120Var13(ksq, user, encryptedBuffer.ToRSlice())); + writer.WriteFreeFormat(Group120Var15(hmacBuffer.ToRSlice())); + + return ToHex(apdu.ToRSlice()); +} + +std::string FinishUpdateKeyChangeResponse( + uint8_t seq, + const std::string& hmac +) +{ + Buffer buffer(DEFAULT_MAX_APDU_SIZE); + APDUResponse apdu(buffer.GetWSlice()); + apdu.SetControl(AppControlField(true, true, false, false, seq)); + apdu.SetFunction(FunctionCode::AUTH_RESPONSE); + apdu.SetIIN(IINBit::DEVICE_RESTART); + + HexSequence hmacBuffer(hmac); + + apdu.GetWriter().WriteFreeFormat(Group120Var15(hmacBuffer.ToRSlice())); + + return ToHex(apdu.ToRSlice()); +} + +std::string KeyWrapData( + uint16_t keyLengthBytes, + uint8_t keyRepeatValue, + std::string keyStatusMsg +) +{ + Buffer key(keyLengthBytes); + key.GetWSlice().SetAllTo(keyRepeatValue); + auto keyHex = ToHex(key.ToRSlice()); + HexSequence statusBuffer(keyStatusMsg); + + Buffer lengthBuff(2); + auto lenDest = lengthBuff.GetWSlice(); + UInt16::WriteBuffer(lenDest, keyLengthBytes); + auto lengthHex = ToHex(lengthBuff.ToRSlice()); + + return AppendHex({lengthHex, keyHex, keyHex, keyStatusMsg}); +} + +} + + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.h new file mode 100644 index 0000000..e3c3648 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/APDUHexBuilders.h @@ -0,0 +1,182 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __APDU_HEX_BUILDERS_H_ +#define __APDU_HEX_BUILDERS_H_ + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace hex +{ +// ----------- simple helpers -------- + +std::string repeat(uint8_t value, uint16_t count); + +// ----------- requests -------------- + +std::string IntegrityPoll(uint8_t seq, const opendnp3::ClassField& field = opendnp3::ClassField::AllClasses()); + +std::string ClassTask(opendnp3::FunctionCode fc, uint8_t seq, const opendnp3::ClassField& field = opendnp3::ClassField::AllClasses()); + +std::string ClassPoll(uint8_t seq, opendnp3::PointClass pc); + +std::string EventPoll(uint8_t seq, const opendnp3::ClassField& field = opendnp3::ClassField::AllEventClasses()); + +std::string ClearRestartIIN(uint8_t seq); + +std::string MeasureDelay(uint8_t seq); + +std::string Control(opendnp3::FunctionCode code, uint8_t seq, const opendnp3::ControlRelayOutputBlock& crob, uint16_t index); + +// ----------- responses -------------- + +std::string EmptyResponse(uint8_t seq, const opendnp3::IINField& iin = opendnp3::IINField::Empty()); + +std::string EmptyAuthResponse(uint8_t seq, const opendnp3::IINField& iin = opendnp3::IINField::Empty()); + +std::string NullUnsolicited(uint8_t seq, const opendnp3::IINField& iin = opendnp3::IINField(opendnp3::IINBit::DEVICE_RESTART)); + +// ----------- confirms -------------- + +std::string SolicitedConfirm(uint8_t seq); + +std::string UnsolConfirm(uint8_t seq); + +std::string Confirm(uint8_t seq, bool unsol); + +// ----------- sec auth ------------- + +std::string RequestKeyStatus(uint8_t seq, uint16_t user); + +std::string AuthErrorResponse( + opendnp3::IINField iin, + uint8_t appSeq, + uint32_t challengeSeqNum, + uint16_t user, + uint16_t assocId, + opendnp3::AuthErrorCode code, + opendnp3::DNPTime timestamp, + std::string hexText); + +std::string ChallengeResponse( + opendnp3::IINField iin, + uint8_t seq, + uint32_t csq, + uint16_t user, + opendnp3::HMACType hmacType, + opendnp3::ChallengeReason reason, + std::string challengeDataHex +); + +std::string ChallengeReply( + uint8_t appSeq, + uint32_t challengeSeqNum, + uint16_t userNum, + std::string hmacHex +); + +std::string KeyStatusResponse( + opendnp3::IINField iin, + uint8_t seq, + uint32_t ksq, + uint16_t user, + opendnp3::KeyWrapAlgorithm keyWrap, + opendnp3::KeyStatus status, + opendnp3::HMACType, + const std::string& challenge, + const std::string& hmac +); + +std::string KeyChangeRequest( + uint8_t seq, + uint32_t ksq, + uint16_t user, + const std::string& keyWrapData +); + +std::string UserStatusChangeRequest( + uint8_t seq, + opendnp3::KeyChangeMethod keyChangeMethod, + opendnp3::UserOperation userOperation, + uint32_t statusChangeSeqNum, + uint16_t userRole, + uint16_t userRoleExpDays, + const std::string& userName, + const std::string& userPublicKeyHex, + const std::string& certificationDataHex +); + +std::string BeginUpdateKeyChangeRequest( + uint8_t seq, + opendnp3::KeyChangeMethod keyChangeMethod, + const std::string& username, + const std::string& masterChallenge +); + +std::string BeginUpdateKeyChangeResponse( + uint8_t seq, + uint32_t ksq, + uint16_t user, + const std::string& outstationChallenge +); + +std::string FinishUpdateKeyChangeRequest( + uint8_t seq, + uint32_t ksq, + uint16_t user, + const std::string& encryptedData, + const std::string& hmac +); + +std::string FinishUpdateKeyChangeResponse( + uint8_t seq, + const std::string& hmac +); + +std::string KeyWrapData( + uint16_t keyLengthBytes, + uint8_t keyRepeatValue, + std::string keyStatusMsg +); + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CallbackQueue.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CallbackQueue.h new file mode 100644 index 0000000..b42a63f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CallbackQueue.h @@ -0,0 +1,50 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef DNP3MOCKS_CALLBACK_QUEUE_H +#define DNP3MOCKS_CALLBACK_QUEUE_H + +#include +#include + +namespace opendnp3 +{ + +template +class CallbackQueue +{ +public: + + std::function Callback() + { + return [this](const T & rsp) -> void + { + responses.push_back(rsp); + }; + } + + std::deque responses; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CommandCallbackQueue.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CommandCallbackQueue.h new file mode 100644 index 0000000..018b5fa --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/CommandCallbackQueue.h @@ -0,0 +1,111 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef DNP3MOCKS_COMMAND_CALLBACK_QUEUE_H +#define DNP3MOCKS_COMMAND_CALLBACK_QUEUE_H + +#include +#include + +#include + +namespace opendnp3 +{ + +class MockCommandResultType final : public IVisitor +{ +public: + + MockCommandResultType(TaskCompletion result_) : summary(result_) + {} + + virtual void OnValue(const CommandPointResult& value) override + { + results.push_back(value); + } + + bool Equals(TaskCompletion summary_, CommandPointResult result) const + { + return (results.size() == 1) && (summary_ == summary) && result.Equals(results.front()); + } + + TaskCompletion summary; + std::vector results; +}; + +class CommandCallbackQueue +{ +public: + + std::function Callback() + { + return [this](const ICommandTaskResult & rsp) -> void + { + MockCommandResultType result(rsp.summary); + rsp.Foreach(result); + values.push_back(result); + }; + } + + bool PopOnlyEqualValue(TaskCompletion summary, CommandPointResult item) + { + return PopOnlyEqualValue(summary, { item }); + } + + bool PopOnlyEqualValue(TaskCompletion summary, std::initializer_list list) + { + if (values.size() != 1) return false; + + auto value = values.front(); + values.pop_front(); + + if (value.summary != summary) + { + return false; + } + + if (list.size() != value.results.size()) + { + return false; + } + + uint32_t i = 0; + + for (auto& item : list) + { + if (!value.results[i].Equals(item)) + { + return false; + } + + ++i; + } + + return true; + } + + std::deque values; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockCommandHandler.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockCommandHandler.h new file mode 100644 index 0000000..d5e6663 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockCommandHandler.h @@ -0,0 +1,114 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MOCK_COMMAND_HANDLER_H +#define OPENDNP3_MOCK_COMMAND_HANDLER_H + +#include + +#include + +namespace opendnp3 +{ + +template +class Operation : public Indexed +{ +public: + + Operation(T value, uint16_t index, OperateType opType_) : + Indexed(value, index), + opType(opType_) + { + + } + + OperateType opType; +}; + + +class MockCommandHandler final : public SimpleCommandHandler +{ +public: + + MockCommandHandler(CommandStatus status = CommandStatus::SUCCESS) : SimpleCommandHandler(status) + {} + + void SetResponse(CommandStatus status_) + { + status = status_; + } + + uint32_t NumInvocations() const + { + return numSelect + numOperate; + } + + uint32_t NumSelect() const + { + return numSelect; + } + + uint32_t NumOperate() const + { + return numOperate; + } + +protected: + + virtual void DoOperate(const ControlRelayOutputBlock& command, uint16_t index, OperateType opType) override + { + this->crobOps.push_back(Operation(command, index, opType)); + } + + virtual void DoOperate(const AnalogOutputInt16& command, uint16_t index, OperateType opType) override + { + this->aoInt16Ops.push_back(Operation(command, index, opType)); + } + + virtual void DoOperate(const AnalogOutputInt32& command, uint16_t index, OperateType opType) override + { + this->aoInt32Ops.push_back(Operation(command, index, opType)); + } + + virtual void DoOperate(const AnalogOutputFloat32& command, uint16_t index, OperateType opType) override + { + this->aoFloat32Ops.push_back(Operation(command, index, opType)); + } + + virtual void DoOperate(const AnalogOutputDouble64& command, uint16_t index, OperateType opType) override + { + this->aoDouble64Ops.push_back(Operation(command, index, opType)); + } + +public: + + std::vector> crobOps; + std::vector> aoInt16Ops; + std::vector> aoInt32Ops; + std::vector> aoFloat32Ops; + std::vector> aoDouble64Ops; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.cpp b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.cpp new file mode 100644 index 0000000..f6b04d0 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.cpp @@ -0,0 +1,99 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MockFrameSink.h" + +using namespace openpal; + +namespace opendnp3 +{ + +MockFrameSink::MockFrameSink() : m_num_frames(0), mLowerOnline(false) +{} + +bool MockFrameSink::OnLowerLayerUp() +{ + mLowerOnline = true; + return true; +} + +bool MockFrameSink::OnLowerLayerDown() +{ + mLowerOnline = false; + return true; +} + +void MockFrameSink::Reset() +{ + this->ClearBuffer(); + m_num_frames = 0; +} + +bool MockFrameSink::CheckLast(LinkFunction func, bool isMaster, uint16_t dest, uint16_t src) +{ + return (m_last_header.func == func) && (isMaster == m_last_header.isFromMaster) && (m_last_header.src == src) && (m_last_header.dest == dest); +} + +bool MockFrameSink::CheckLastWithFCB(LinkFunction func, bool isMaster, bool aFcb, uint16_t dest, uint16_t src) +{ + return (m_last_header.fcb == aFcb) && CheckLast(func, isMaster, dest, src); +} + +bool MockFrameSink::CheckLastWithDFC(LinkFunction func, bool isMaster, bool aIsRcvBuffFull, uint16_t dest, uint16_t src) +{ + return (m_last_header.fcvdfc == aIsRcvBuffFull) && CheckLast(func, isMaster, dest, src); +} + +bool MockFrameSink::OnTransmitResult(bool success) +{ + return true; +} + +bool MockFrameSink::OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) +{ + ++m_num_frames; + + this->m_last_header = header; + + if (userdata.IsNotEmpty()) + { + this->WriteToBuffer(userdata); + } + + return true; +} + +void MockFrameSink::AddAction(std::function fun) +{ + m_actions.push_back(fun); +} + +void MockFrameSink::ExecuteAction() +{ + if(m_actions.size() > 0) + { + auto f = m_actions.front(); + m_actions.pop_front(); + f(); + } +} + +} + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.h new file mode 100644 index 0000000..4edc985 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockFrameSink.h @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_FRAME_SINK_H_ +#define __MOCK_FRAME_SINK_H_ + +#include +#include + +#include + +#include + +#include +#include + +namespace opendnp3 +{ + + +class MockFrameSink : public ILinkSession, public testlib::BufferTestObject +{ +public: + + MockFrameSink(); + + // ILinkSession members + bool OnLowerLayerUp() override; + bool OnLowerLayerDown() override; + bool OnTransmitResult(bool success) override; + + virtual bool OnFrame(const LinkHeaderFields& header, const openpal::RSlice& userdata) override final; + + void Reset(); + + + bool CheckLast(LinkFunction aCode, bool aIsMaster, uint16_t aDest, uint16_t aSrc); + bool CheckLastWithFCB(LinkFunction aCode, bool aIsMaster, bool aFcb, uint16_t aDest, uint16_t aSrc); + bool CheckLastWithDFC(LinkFunction aCode, bool aIsMaster, bool aIsRcvBuffFull, uint16_t aDest, uint16_t aSrc); + + // Last frame information + size_t m_num_frames; + LinkHeaderFields m_last_header; + + bool mLowerOnline; + + // Add a function to execute the next time a frame is received + // This allows us to test re-entrant behaviors + void AddAction(std::function fun); + +private: + + // Executes one action, if one is available + void ExecuteAction(); + + std::deque< std::function > m_actions; + + void Update(LinkFunction aCode, bool aIsMaster, uint16_t aSrc, uint16_t aDest); +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLinkListener.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLinkListener.h new file mode 100644 index 0000000..f08cb70 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLinkListener.h @@ -0,0 +1,70 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MOCK_LINK_LISTENER_H_ +#define OPENDNP3_MOCK_LINK_LISTENER_H_ + +#include + +#include + +namespace opendnp3 +{ + + +class MockLinkListener final : public ILinkListener +{ +public: + + MockLinkListener() : numKeepAliveTransmissions(0), numKeepAliveFailure(0), numKeepAliveReplys(0) + {} + + virtual void OnStateChange(LinkStatus value) override + { + statusValues.push_back(value); + } + + virtual void OnKeepAliveInitiated() override + { + ++numKeepAliveTransmissions; + } + + virtual void OnKeepAliveFailure() override + { + ++numKeepAliveFailure; + } + + virtual void OnKeepAliveSuccess() override + { + ++numKeepAliveReplys; + } + + uint32_t numKeepAliveTransmissions; + uint32_t numKeepAliveFailure; + uint32_t numKeepAliveReplys; + + std::vector< LinkStatus > statusValues; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.cpp b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.cpp new file mode 100644 index 0000000..0281512 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.cpp @@ -0,0 +1,116 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MockLowerLayer.h" + +#include +#include + +#include + +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ + +bool MockLowerLayer::HasNoData() const +{ + return sendQueue.empty(); +} + +size_t MockLowerLayer::NumWrites() const +{ + return sendQueue.size(); +} + +openpal::RSlice MockLowerLayer::PopWrite() +{ + auto ret = sendQueue.front(); + sendQueue.pop(); + return ret; +} + +std::string MockLowerLayer::PopWriteAsHex() +{ + if (sendQueue.empty()) + { + return ""; + } + else + { + auto ret = sendQueue.front(); + sendQueue.pop(); + return ToHex(ret); + } +} + +bool MockLowerLayer::BeginTransmit(const openpal::RSlice& output) +{ + this->sendQueue.push(output); + return true; +} + +void MockLowerLayer::SendUp(const openpal::RSlice& arBuffer) +{ + if(pUpperLayer) + { + pUpperLayer->OnReceive(arBuffer); + } +} + +void MockLowerLayer::SendUp(const std::string& arHexData) +{ + HexSequence hs(arHexData); + this->SendUp(hs.ToRSlice()); +} + +void MockLowerLayer::SendSuccess() +{ + if (pUpperLayer) + { + pUpperLayer->OnSendResult(true); + } +} + +void MockLowerLayer::SendFailure() +{ + if (pUpperLayer) + { + pUpperLayer->OnSendResult(false); + } +} + +void MockLowerLayer::ThisLayerUp() +{ + if (pUpperLayer) + { + pUpperLayer->OnLowerLayerUp(); + } +} +void MockLowerLayer::ThisLayerDown() +{ + if (pUpperLayer) + { + pUpperLayer->OnLowerLayerDown(); + } +} + +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.h new file mode 100644 index 0000000..855e899 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockLowerLayer.h @@ -0,0 +1,61 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_LOWER_LAYER_H_ +#define __MOCK_LOWER_LAYER_H_ + +#include +#include + +#include + +namespace opendnp3 +{ + +class MockLowerLayer : public ILowerLayer, public HasUpperLayer +{ +public: + + void SendUp(const openpal::RSlice& arBuffer); + void SendUp(const std::string&); + void SendSuccess(); + void SendFailure(); + void ThisLayerUp(); + void ThisLayerDown(); + + void EnableAutoSendCallback(bool aIsSuccess); + void DisableAutoSendCallback(); + + bool HasNoData() const; + + size_t NumWrites() const; + openpal::RSlice PopWrite(); + std::string PopWriteAsHex(); + + virtual bool BeginTransmit(const openpal::RSlice& arBuffer) override final; + +private: + + std::queue sendQueue; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockMasterApplication.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockMasterApplication.h new file mode 100644 index 0000000..0e1ccbc --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockMasterApplication.h @@ -0,0 +1,107 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_MASTER_APPLICATION_H_ +#define __MOCK_MASTER_APPLICATION_H_ + +#include + +#include +#include +#include + +namespace opendnp3 +{ + +class MockMasterApplication final : public IMasterApplication +{ + +public: + + enum class State + { + OPEN, + CLOSED + }; + + MockMasterApplication() : time(0) + {} + + virtual openpal::UTCTimestamp Now() override + { + return openpal::UTCTimestamp(time); + } + + virtual void OnReceiveIIN(const IINField& iin) override + { + rxIIN.push_back(iin); + } + + virtual void OnTaskStart(MasterTaskType type, TaskId id) override + { + taskStartEvents.push_back(type); + } + + virtual void OnTaskComplete(const opendnp3::TaskInfo& info) override + { + taskCompletionEvents.push_back(info); + } + + virtual void OnOpen() override + { + this->stateChanges.push_back(State::OPEN); + } + + virtual void OnClose() override + { + this->stateChanges.push_back(State::CLOSED); + } + + virtual bool AssignClassDuringStartup() override + { + return !assignClassHeaders.empty(); + } + + virtual void ConfigureAssignClassRequest(const opendnp3::WriteHeaderFunT& fun) override + { + for (auto& header : assignClassHeaders) + { + fun(header); + } + } + + std::deque stateChanges; + + + std::vector assignClassHeaders; + + std::vector rxIIN; + + std::vector taskStartEvents; + std::vector taskCompletionEvents; + + uint64_t time; +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockOutstationApplication.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockOutstationApplication.h new file mode 100644 index 0000000..ff38935 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockOutstationApplication.h @@ -0,0 +1,141 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_OUTSTATION_APPLICATION_H_ +#define __MOCK_OUTSTATION_APPLICATION_H_ + +#include + +#include + +namespace opendnp3 +{ + +class MockOutstationApplication : public IOutstationApplication +{ +public: + + MockOutstationApplication() : + supportsTimeWrite(true), + supportsAssignClass(false), + supportsWriteTimeAndInterval(false), + allowTimeWrite(true), + warmRestartSupport(RestartMode::UNSUPPORTED), + coldRestartSupport(RestartMode::UNSUPPORTED), + warmRestartTimeDelay(0), + coldRestartTimeDelay(0) + {} + + virtual void OnStateChange(LinkStatus value) override final + {} + + virtual bool SupportsWriteAbsoluteTime() override final + { + return supportsTimeWrite; + } + + virtual bool WriteAbsoluteTime(const openpal::UTCTimestamp& timestamp) override final + { + if (allowTimeWrite) + { + timestamps.push_back(timestamp); + return true; + } + else + { + return false; + } + } + + virtual bool SupportsWriteTimeAndInterval() override final + { + return supportsWriteTimeAndInterval; + } + + virtual bool WriteTimeAndInterval(const ICollection>& meas) override final + { + auto push = [this](const Indexed& value) + { + this->timeAndIntervals.push_back(value); + }; + + meas.ForeachItem(push); + return true; + } + + virtual bool SupportsAssignClass() override final + { + return supportsAssignClass; + } + + virtual void RecordClassAssignment(AssignClassType type, PointClass clazz, uint16_t start, uint16_t stop) override final + { + this->classAssignments.push_back(std::make_tuple(type, clazz, start, stop)); + } + + virtual ApplicationIIN GetApplicationIIN() const override final + { + return appIIN; + } + + virtual RestartMode ColdRestartSupport() const override final + { + return coldRestartSupport; + } + + virtual RestartMode WarmRestartSupport() const override final + { + return warmRestartSupport; + } + + virtual uint16_t ColdRestart() override final + { + return coldRestartTimeDelay; + } + + virtual uint16_t WarmRestart() override final + { + return warmRestartTimeDelay; + } + + bool supportsTimeWrite; + bool supportsAssignClass; + bool supportsWriteTimeAndInterval; + + bool allowTimeWrite; + + RestartMode warmRestartSupport; + RestartMode coldRestartSupport; + + uint16_t warmRestartTimeDelay; + uint16_t coldRestartTimeDelay; + + ApplicationIIN appIIN; + + std::deque timestamps; + std::deque> classAssignments; + std::deque> timeAndIntervals; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockSOEHandler.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockSOEHandler.h new file mode 100644 index 0000000..e22fd19 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockSOEHandler.h @@ -0,0 +1,197 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_MOCKSOEHANDLER_H_ +#define OPENDNP3_MOCKSOEHANDLER_H_ + +#include + +#include + + +namespace opendnp3 +{ + +// simple measurement handler for testing purposes +class MockSOEHandler : public ISOEHandler +{ +public: + + template + class Record + { + public: + + Record() : sequence(0) + {} + + Record(const T& meas_, const HeaderInfo& info_, uint32_t sequence_) : + meas(meas_), + info(info_), + sequence(sequence_) + {} + + + T meas; + HeaderInfo info; + uint32_t sequence; + }; + + MockSOEHandler() : soeCount(0) + {} + + uint32_t TotalReceived() const + { + return soeCount; + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->binarySOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->doubleBinarySOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->analogSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->counterSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->frozenCounterSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->binaryOutputStatusSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->analogOutputStatusSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->octetStringSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->timeAndIntervalSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->binaryCommandEventSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->analogCommandEventSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final + { + this->RecordAny(info, values, this->securityStatSOE); + } + + virtual void Process(const HeaderInfo& info, const ICollection& values) override final + { + values.ForeachItem([this](const DNPTime & value) + { + ++this->soeCount; + this->timeSOE.push_back(value); + }); + } + + void Clear() + { + soeCount = 0; + + binarySOE.clear(); + doubleBinarySOE.clear(); + analogSOE.clear(); + counterSOE.clear(); + frozenCounterSOE.clear(); + binaryOutputStatusSOE.clear(); + analogOutputStatusSOE.clear(); + octetStringSOE.clear(); + timeAndIntervalSOE.clear(); + binaryCommandEventSOE.clear(); + analogCommandEventSOE.clear(); + securityStatSOE.clear(); + timeSOE.clear(); + } + + std::map> binarySOE; + std::map> doubleBinarySOE; + std::map> analogSOE; + std::map> counterSOE; + std::map> frozenCounterSOE; + std::map> binaryOutputStatusSOE; + std::map> analogOutputStatusSOE; + std::map> octetStringSOE; + std::map> timeAndIntervalSOE; + std::map> binaryCommandEventSOE; + std::map> analogCommandEventSOE; + std::map> securityStatSOE; + std::vector timeSOE; + +protected: + + void Start() override {} + void End() override {} + +private: + + uint32_t soeCount; + + template + void RecordAny(const HeaderInfo& info, const ICollection>& values, std::map >& records) + { + auto process = [this, info, &records](const Indexed& pair) + { + Record record(pair.value, info, soeCount); + records[pair.index] = record; + ++this->soeCount; + }; + + values.ForeachItem(process); + } + + + + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockTaskCallback.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockTaskCallback.h new file mode 100644 index 0000000..db9ee0e --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockTaskCallback.h @@ -0,0 +1,60 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_COMMAND_CALLBACK_H_ +#define __MOCK_COMMAND_CALLBACK_H_ + +#include +#include + +namespace opendnp3 +{ + +class MockTaskCallback : public ITaskCallback +{ +public: + + virtual void OnStart() override final + { + ++numStart; + } + + virtual void OnComplete(TaskCompletion result) override final + { + results.push_back(result); + } + + virtual void OnDestroyed() override final + { + ++numDestroyed; + } + + uint32_t numStart = 0; + + uint32_t numDestroyed = 0; + + std::deque results; + +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.cpp b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.cpp new file mode 100644 index 0000000..082e9e6 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.cpp @@ -0,0 +1,92 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MockUpperLayer.h" + +#include + +#include +#include + +#include + +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ + +MockUpperLayer::MockUpperLayer() : isOnline(false) +{ + +} + +bool MockUpperLayer::OnReceive(const openpal::RSlice& input) +{ + this->WriteToBuffer(input); + + if (mOnReceiveHandler) + { + mOnReceiveHandler(input); + } + + return true; +} + +bool MockUpperLayer::OnSendResult(bool isSuccess) +{ + if (isSuccess) + { + ++mState.mSuccessCnt; + } + else + { + ++mState.mFailureCnt; + } + + return true; +} + +bool MockUpperLayer::OnLowerLayerUp() +{ + isOnline = true; + ++mState.mNumLayerUp; + return true; +} + +bool MockUpperLayer::OnLowerLayerDown() +{ + isOnline = false; + ++mState.mNumLayerDown; + return true; +} + +bool MockUpperLayer::SendDown(const openpal::RSlice& buffer) +{ + return this->pLowerLayer ? pLowerLayer->BeginTransmit(buffer) : false; +} + +bool MockUpperLayer::SendDown(const std::string& hex) +{ + HexSequence hs(hex); + return this->SendDown(hs.ToRSlice()); +} + +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.h new file mode 100644 index 0000000..9a8c415 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/MockUpperLayer.h @@ -0,0 +1,116 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_UPPER_LAYER_H_ +#define __MOCK_UPPER_LAYER_H_ + + +#include + +#include + +#include + +namespace opendnp3 +{ + +class MockUpperLayer : public IUpperLayer, public HasLowerLayer, public testlib::BufferTestObject +{ +public: + + typedef std::function OnReceiveHandler; + + struct State + { + + State() + { + Reset(); + } + + size_t mSuccessCnt; + size_t mFailureCnt; + size_t mNumLayerUp; + size_t mNumLayerDown; + + void Reset() + { + mSuccessCnt = mFailureCnt = mNumLayerUp = mNumLayerDown = 0; + } + }; + + MockUpperLayer(); + + bool IsOnline() const + { + return isOnline; + } + + bool SendDown(const std::string&); + bool SendDown(const openpal::RSlice& arBuffer); + + bool CountersEqual(size_t success, size_t failure) + { + return mState.mSuccessCnt == success && mState.mFailureCnt == failure; + } + + bool StateEquals(const State& s) + { + return (mState.mSuccessCnt == s.mSuccessCnt) + && (mState.mFailureCnt == s.mFailureCnt) + && (mState.mNumLayerUp == s.mNumLayerUp) + && (mState.mNumLayerDown == s.mNumLayerDown); + } + + void Reset() + { + mState.Reset(); + } + State GetState() + { + return mState; + } + + void SetReceiveHandler(const OnReceiveHandler& arHandler) + { + mOnReceiveHandler = arHandler; + } + + //these are the NVII delegates + virtual bool OnReceive(const openpal::RSlice& buffer) override final; + virtual bool OnSendResult(bool isSuccess) override final; + virtual bool OnLowerLayerUp() override final; + virtual bool OnLowerLayerDown() override final; + +private: + + bool isOnline; + + OnReceiveHandler mOnReceiveHandler; + State mState; + + +}; + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.cpp b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.cpp new file mode 100644 index 0000000..564edff --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.cpp @@ -0,0 +1,29 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "NullSOEHandler.h" + +namespace opendnp3 +{ + +NullSOEHandler NullSOEHandler::instance; + +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.h new file mode 100644 index 0000000..468b00a --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/NullSOEHandler.h @@ -0,0 +1,70 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef DNP3MOCKS_NULLSOEHANDLER_H +#define DNP3MOCKS_NULLSOEHANDLER_H + +#include + +#include + +namespace opendnp3 +{ + +class NullSOEHandler : public ISOEHandler +{ + +public: + + NullSOEHandler() = default; + + static std::shared_ptr Create() + { + return std::make_shared(); + } + + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection>& values) override final {} + virtual void Process(const HeaderInfo& info, const ICollection& values) override final {} + +protected: + + void Start() override final {} + void End() override final {} + +private: + + + static NullSOEHandler instance; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.cpp b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.cpp new file mode 100644 index 0000000..e9043f7 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.cpp @@ -0,0 +1,36 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "ProtocolUtil.h" + +// Given a buffer and max packet size, calculcate the +// maximum number of packets the buffer can hold +uint32_t CalcMaxPackets(uint32_t aBuffer, uint32_t aPayload) +{ + uint32_t remain = aBuffer % aPayload; + uint32_t num = aBuffer / aPayload; + return (remain == 0) ? num : num + 1; +} + +uint32_t CalcLastPacketSize(uint32_t aBuffer, uint32_t aPayload) +{ + uint32_t remain = aBuffer % aPayload; + return (remain == 0) ? aPayload : remain; +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.h b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.h new file mode 100644 index 0000000..4f4308c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/dnp3mocks/ProtocolUtil.h @@ -0,0 +1,36 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __PROTOCOL_UTIL_H_ +#define __PROTOCOL_UTIL_H_ + +#include + +// Given a buffer and max packet size, calculcate the +// maximum number of packets the buffer can hold +uint32_t CalcMaxPackets(uint32_t aBuffer, uint32_t aPayload); + + +// Given a buffer and max packet size, calculcate the +// size of the last packet. +uint32_t CalcLastPacketSize(uint32_t aBuffer, uint32_t aPayload); + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.cpp new file mode 100644 index 0000000..2421e43 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.cpp @@ -0,0 +1,124 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "BufferHelpers.h" + +#include + +#include "HexConversions.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace openpal; + +namespace testlib +{ + +ByteStr::ByteStr(uint32_t aLength, uint8_t aSeed) : CopyableBuffer(aLength) +{ + for(size_t i = 0; i < aLength; ++i) mpBuff[i] = static_cast((i + aSeed) % 256); +} + +ByteStr::ByteStr(const uint8_t* apData, uint32_t aLength) : CopyableBuffer(aLength) +{ + memcpy(mpBuff, apData, aLength); +} + +ByteStr::ByteStr(const std::string& aChars) : CopyableBuffer(static_cast(aChars.size())) +{ + memcpy(mpBuff, aChars.c_str(), aChars.size()); +} + +bool ByteStr::operator==(const ByteStr& arRHS) const +{ + if(Size() != arRHS.Size()) return false; + + for(size_t i = 0; i < Size(); ++i) + if(mpBuff[i] != arRHS[i]) return false; + + return true; +} + +std::string ByteStr::ToHex() const +{ + return testlib::ToHex(ToRSlice()); +} + +HexSequence::HexSequence( const std::string& aSequence) : + ByteStr(Validate(RemoveSpaces(aSequence))) +{ + std::string s = RemoveSpaces(aSequence); + + size_t size = s.size(); + for(size_t index = 0, pos = 0; pos < size; ++index, pos += 2) + { + uint32_t val; + std::stringstream ss; + ss << std::hex << s.substr(pos, 2); + if((ss >> val).fail()) + { + throw std::invalid_argument(aSequence); + } + mpBuff[index] = static_cast(val); + } +} + +std::string HexSequence::RemoveSpaces(const std::string& aSequence) +{ + std::string copy(aSequence); + RemoveSpacesInPlace(copy); + return copy; +} + +void HexSequence::RemoveSpacesInPlace(std::string& s) +{ + size_t pos = s.find_first_of(' '); + if(pos != string::npos) + { + s.replace(pos, 1, ""); + RemoveSpacesInPlace(s); + } +} + +uint32_t HexSequence::Validate(const std::string& s) +{ + //annoying when you accidentally put an 'O' instead of zero '0' + if(s.find_first_of( "oO") != string::npos) + { + throw std::invalid_argument("Sequence contains 'o' or 'O'"); + } + + if(s.size() % 2 != 0) + { + throw std::invalid_argument(s); + } + + return static_cast(s.size() / 2); +} + +} + + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.h new file mode 100644 index 0000000..8df44ae --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferHelpers.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_BUFFERHELPERS_H_ +#define TESTLIB_BUFFERHELPERS_H_ + +#include "CopyableBuffer.h" + +#include + +namespace testlib +{ + +class ByteStr : public CopyableBuffer +{ + +public: + ByteStr(uint32_t aLength, uint8_t aSeed = 0); + ByteStr(const uint8_t* apData, uint32_t aLength); + ByteStr(const std::string& aChars); + bool operator==(const ByteStr& arRHS) const; + std::string ToHex() const; +}; + +/** + * A sequence of hex values in the form "01 02 03 04" that are stored as a ByteStr. + */ +class HexSequence : public ByteStr +{ +public: + HexSequence(const std::string& aSequence); + + operator openpal::RSlice() + { + return this->ToRSlice(); + } + +private: + std::string RemoveSpaces(const std::string& aSequence); + void RemoveSpacesInPlace(std::string& aSequence); + static uint32_t Validate(const std::string& aSequence); +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.cpp new file mode 100644 index 0000000..a10940e --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.cpp @@ -0,0 +1,125 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "BufferTestObject.h" + +#include + +#include +#include + +#include + +#include + +using namespace openpal; + +namespace testlib +{ + +BufferTestObject::BufferTestObject() : + mNumWrites(0) +{ + +} + +BufferTestObject::~BufferTestObject() +{ + +} + +void BufferTestObject::ClearBuffer() +{ + mNumWrites = 0; + mBuffer.clear(); +} + +bool BufferTestObject::BufferEquals(const openpal::RSlice& arBuffer) const +{ + return BufferEquals(arBuffer, arBuffer.Size()); +} + +bool BufferTestObject::BufferEquals(const uint8_t* apData, size_t aNumBytes) const +{ + + if(aNumBytes != mBuffer.size()) return false; + for(size_t i = 0; i < aNumBytes; i++) + if(apData[i] != mBuffer[i]) + { + return false; + } + return true; +} + +bool BufferTestObject::BufferContains(const std::string& arPattern) const +{ + std::string s; + for(size_t i = 0; i < mBuffer.size(); ++i) + { + std::string c(1, static_cast(mBuffer[i])); + s.append(c); + } + return s.find(arPattern) != std::string::npos; +} + +std::string BufferTestObject::GetBufferAsHexString(bool spaced) const +{ + CopyableBuffer buffer(static_cast(mBuffer.size())); + for(size_t i = 0; i < mBuffer.size(); ++i) buffer[i] = mBuffer[i]; + return ToHex(buffer.ToRSlice(), spaced); +} + + +bool BufferTestObject::BufferEqualsHex(const std::string& arData) const +{ + HexSequence hs(arData); + return BufferEquals(hs, hs.Size()); +} + +bool BufferTestObject::BufferEqualsString(const std::string& arData) const +{ + if(arData.size() != mBuffer.size()) return false; + for(size_t i = 0; i < mBuffer.size(); i++) + if(arData[i] != mBuffer[i]) + { + return false; + } + return true; +} + +void BufferTestObject::WriteToBuffer(const RSlice& input) +{ + if((mBuffer.size() + input.Size()) > MAX_SIZE ) + { + throw std::invalid_argument("Max size exceeded"); + } + else + { + ++mNumWrites; + + for(size_t i = 0; i < input.Size(); ++i) + { + mBuffer.push_back(input[i]); + } + } +} + +} //end namespace + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.h new file mode 100644 index 0000000..09150a4 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/BufferTestObject.h @@ -0,0 +1,78 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __BUFFER_TEST_OBJECT_H_ +#define __BUFFER_TEST_OBJECT_H_ + +#include +#include +#include + +#include + +namespace testlib +{ + +class BufferTestObject +{ + static const size_t MAX_SIZE = 1024 * 1024; + +public: + BufferTestObject(); + ~BufferTestObject(); + + bool BufferEquals(const openpal::RSlice& arBuffer) const; + bool BufferEquals(const uint8_t*, size_t) const; + bool BufferEqualsHex(const std::string& arData) const; + bool BufferEqualsString(const std::string& arData) const; + bool BufferContains(const std::string& arData) const; + + std::string GetBufferAsHexString(bool spaced = true) const; + + bool IsBufferEmpty() + { + return mBuffer.size() == 0; + } + void ClearBuffer(); + size_t Size() + { + return mBuffer.size(); + } + bool SizeEquals(size_t aNum) + { + return aNum == Size(); + } + size_t NumWrites() + { + return mNumWrites; + } + +protected: + void WriteToBuffer(const openpal::RSlice& arBuffer); + +private: + size_t mNumWrites; + std::vector mBuffer; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.cpp new file mode 100644 index 0000000..e480517 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.cpp @@ -0,0 +1,118 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "CopyableBuffer.h" + +#include "HexConversions.h" + +#include + +#include +#include + +using namespace testlib; + +namespace testlib +{ + +std::ostream& operator<<(std::ostream& output, const CopyableBuffer& arBuff) +{ + output << "[" << ToHex(arBuff.ToRSlice(), true) << "]"; + return output; +} + +CopyableBuffer::CopyableBuffer() : + mpBuff(nullptr), + mSize(0) +{ + +} + +CopyableBuffer::CopyableBuffer(uint32_t aSize) : + mpBuff(new uint8_t[aSize]), + mSize(aSize) +{ + this->Zero(); +} + +CopyableBuffer::CopyableBuffer(const openpal::RSlice& buffer) : + mpBuff(new uint8_t[buffer.Size()]), + mSize(buffer.Size()) +{ + openpal::WSlice dest(mpBuff, mSize); + buffer.CopyTo(dest); +} + +CopyableBuffer::CopyableBuffer(const uint8_t* apBuff, uint32_t aSize) : + mpBuff(new uint8_t[aSize]), + mSize(aSize) +{ + memcpy(mpBuff, apBuff, aSize); +} + +CopyableBuffer::CopyableBuffer(const CopyableBuffer& arBuffer) : + mpBuff(new uint8_t[arBuffer.Size()]), + mSize(arBuffer.Size()) +{ + memcpy(mpBuff, arBuffer, mSize); +} + +void CopyableBuffer::Zero() +{ + memset(mpBuff, 0, mSize); +} + +CopyableBuffer& CopyableBuffer::operator=(const CopyableBuffer& arRHS) +{ + //check for assignment to self + if(this == &arRHS) return *this; + + if(arRHS.Size() != mSize) + { + mSize = arRHS.Size(); + delete mpBuff; + mpBuff = new uint8_t[mSize]; + } + + memcpy(mpBuff, arRHS, mSize); + + return *this; +} + +CopyableBuffer::~CopyableBuffer() +{ + delete [] mpBuff; +} + +bool CopyableBuffer::operator==( const CopyableBuffer& other) const +{ + if(other.Size() != this->Size()) return false; + else + { + for(size_t i = 0; i < this->Size(); ++i) + { + if(this->mpBuff[i] != other.mpBuff[i]) return false; + } + + return true; + } +} + +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.h new file mode 100644 index 0000000..5f7cbcb --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/CopyableBuffer.h @@ -0,0 +1,92 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_COPYABLEBUFFER_H_ +#define TESTLIB_COPYABLEBUFFER_H_ + +#include +#include +#include + +#include + +namespace testlib +{ + +/** Implements a dynamic buffer with a safe + copy constructor. This makes it easier to compose with + classes without requiring an explicit copy constructor +*/ +class CopyableBuffer +{ + friend std::ostream& operator<<(std::ostream& output, const CopyableBuffer& arBuff); + + +public: + // Construct null buffer + CopyableBuffer(); + // Construct based on starting size of buffer + CopyableBuffer(uint32_t aSize); + CopyableBuffer(const openpal::RSlice&); + CopyableBuffer(const uint8_t* apBuff, uint32_t aSize); + CopyableBuffer(const CopyableBuffer&); + CopyableBuffer& operator=(const CopyableBuffer&); + ~CopyableBuffer(); + + bool operator==( const CopyableBuffer& other) const; + bool operator!=( const CopyableBuffer& other) const + { + return ! (*this == other); + } + + openpal::RSlice ToRSlice() const + { + return openpal::RSlice(mpBuff, mSize); + } + + operator const uint8_t* () const + { + return mpBuff; + } + + operator uint8_t* () + { + return mpBuff; + } + + uint32_t Size() const + { + return mSize; + } + + void Zero(); + +protected: + uint8_t* mpBuff; + +private: + uint32_t mSize; +}; + +} + +#endif + + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.cpp new file mode 100644 index 0000000..3b598bd --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.cpp @@ -0,0 +1,99 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "HexConversions.h" + +#include "BufferHelpers.h" + +#include +#include + +#include + +using namespace std; +using namespace openpal; + +namespace testlib +{ + +std::string ToHex(const uint8_t* apBuff, size_t aLength, bool spaced) +{ + std::ostringstream oss; + size_t last = aLength - 1; + for (size_t i = 0; i < aLength; i++) + { + char c = apBuff[i]; + oss << openpal::ToHexChar((c & 0xf0) >> 4) << openpal::ToHexChar(c & 0xf); + if (spaced && i != last)oss << " "; + } + return oss.str(); +} + +std::string ToHex(const RSlice& buffer, bool spaced) +{ + return ToHex(buffer, buffer.Size(), spaced); +} + +std::string ByteToHex(uint8_t b) +{ + std::ostringstream oss; + oss << openpal::ToHexChar((b & 0xf0) >> 4) << openpal::ToHexChar(b & 0xf); + return oss.str(); +} + +std::string AppendHex(std::initializer_list segments) +{ + ostringstream oss; + for (auto& str : segments) + { + oss << str; + } + HexSequence output(oss.str()); + return ToHex(output.ToRSlice()); +} + +std::string SkipBytesHex(const std::string& input, uint32_t bytes) +{ + HexSequence buffer(input); + return ToHex(buffer.ToRSlice().Skip(bytes)); +} + +std::string RepeatHex(uint8_t byte, uint16_t count, bool spaced) +{ + Buffer buffer(count); + buffer.GetWSlice().SetAllTo(byte); + return ToHex(buffer.ToRSlice(), spaced); +} + +std::string IncrementHex(uint8_t start, uint16_t count, bool spaced) +{ + Buffer buffer(count); + + for (uint16_t i = 0; i < count; ++i) + { + buffer[i] = start; + ++start; + } + + return ToHex(buffer.ToRSlice(), spaced); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.h new file mode 100644 index 0000000..630616d --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/HexConversions.h @@ -0,0 +1,48 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __HEX_CONVERSIONS_H_ +#define __HEX_CONVERSIONS_H_ + +#include +#include + +#include + +namespace testlib +{ + +std::string ByteToHex(uint8_t b); + +std::string ToHex(const uint8_t* pBuff, size_t length, bool spaced = false); + +std::string ToHex(const openpal::RSlice& buffer, bool spaced = true); + +std::string AppendHex(std::initializer_list segments); + +std::string SkipBytesHex(const std::string& input, uint32_t bytes); + +std::string RepeatHex(uint8_t byte, uint16_t count, bool spaced = true); + +std::string IncrementHex(uint8_t start, uint16_t count, bool spaced = true); + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.cpp new file mode 100644 index 0000000..3822759 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.cpp @@ -0,0 +1,208 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MockExecutor.h" + +#include + +using namespace openpal; + +namespace testlib +{ + +MockExecutor::MockExecutor() : + mPostIsSynchronous(false), + mCurrentTime(0) +{ + +} + +MockExecutor::~MockExecutor() +{ + for(auto pTimer : timers) delete pTimer; +} + +openpal::MonotonicTimestamp MockExecutor::NextTimerExpiration() +{ + auto lt = [](MockTimer * pLHS, MockTimer * pRHS) + { + return pLHS->ExpiresAt() < pRHS->ExpiresAt(); + }; + auto min = std::min_element(timers.begin(), timers.end(), lt); + if (min == timers.end()) + { + return MonotonicTimestamp::Max(); + } + else + { + return (*min)->ExpiresAt(); + } +} + +size_t MockExecutor::CheckForExpiredTimers() +{ + size_t count = 0; + while (FindExpiredTimer()) + { + ++count; + } + return count; +} + +bool MockExecutor::FindExpiredTimer() +{ + auto expired = [this](MockTimer * pTimer) + { + return pTimer->ExpiresAt().milliseconds <= this->mCurrentTime.milliseconds; + }; + auto iter = std::find_if(timers.begin(), timers.end(), expired); + if (iter == timers.end()) + { + return false; + } + else + { + this->postQueue.push_back((*iter)->runnable); + delete (*iter); + timers.erase(iter); + return true; + } +} + +size_t MockExecutor::AdvanceTime(TimeDuration aDuration) +{ + this->AddTime(aDuration); + return this->CheckForExpiredTimers(); +} + +// doesn't check timers +void MockExecutor::AddTime(openpal::TimeDuration aDuration) +{ + mCurrentTime = mCurrentTime.Add(aDuration); +} + +bool MockExecutor::AdvanceToNextTimer() +{ + if (timers.empty()) + { + return false; + } + else + { + auto timestamp = NextTimerExpiration(); + if (timestamp > mCurrentTime) + { + mCurrentTime = timestamp; + return true; + } + else + { + return false; + } + } +} + +bool MockExecutor::RunOne() +{ + this->CheckForExpiredTimers(); + + if(postQueue.size() > 0) + { + postQueue.front()(); + postQueue.pop_front(); + return true; + } + else + { + return false; + } +} + +size_t MockExecutor::RunMany(size_t aMaximum) +{ + size_t num = 0; + while(num < aMaximum && this->RunOne()) ++num; + return num; +} + +void MockExecutor::Post(const openpal::action_t& runnable) +{ + if (mPostIsSynchronous) + { + runnable(); + } + else + { + postQueue.push_back(runnable); + } +} + +openpal::MonotonicTimestamp MockExecutor::GetTime() +{ + return mCurrentTime; +} + +ITimer* MockExecutor::Start(const openpal::TimeDuration& aDelay, const openpal::action_t& runnable) +{ + auto expiration = mCurrentTime.Add(aDelay); + return Start(expiration, runnable); +} + +ITimer* MockExecutor::Start(const openpal::MonotonicTimestamp& arTime, const openpal::action_t& runnable) +{ + MockTimer* pTimer = new MockTimer(this, arTime, runnable); + timers.push_back(pTimer); + return pTimer; +} + +void MockExecutor::Cancel(ITimer* pTimer) +{ + for (TimerVector::iterator i = timers.begin(); i != timers.end(); ++i) + { + if(*i == pTimer) + { + delete pTimer; + timers.erase(i); + return; + } + } +} + +MockTimer::MockTimer(MockExecutor* source, const openpal::MonotonicTimestamp& time, const openpal::action_t& runnable) : + mTime(time), + mpSource(source), + runnable(runnable) +{ + +} + +void MockTimer::Cancel() +{ + mpSource->Cancel(this); +} + +openpal::MonotonicTimestamp MockTimer::ExpiresAt() +{ + return mTime; +} + +} + + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.h new file mode 100644 index 0000000..6bc36e9 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockExecutor.h @@ -0,0 +1,126 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_EXECUTOR_H_ +#define __MOCK_EXECUTOR_H_ + +#include + +#include +#include +#include +#include + +namespace testlib +{ + +class MockTimer; + +/** @section desc Test class that doles out MockTimer* */ +class MockExecutor : public openpal::IExecutor +{ + friend class MockTimer; + +public: + MockExecutor(); + ~MockExecutor(); + + // Implement IExecutor + virtual openpal::ITimer* Start(const openpal::MonotonicTimestamp&, const openpal::action_t& runnable) override; + virtual openpal::ITimer* Start(const openpal::TimeDuration&, const openpal::action_t& runnable) override; + virtual void Post(const openpal::action_t& runnable) override; + virtual openpal::MonotonicTimestamp GetTime() override; + + /** Turns the auto-post feature on/off. When Auto post is on, Post() is executed synchronously */ + void SetAutoPost(bool aAutoPost) + { + this->mPostIsSynchronous = aAutoPost; + } + + /** @return true if an action was run. */ + bool RunOne(); + + /** Calls RunOne() up to some maximum number of times continuing while + there are still events to dispatch + + @return the number of events dispatched + */ + size_t RunMany(size_t aMaximum = std::numeric_limits::max()); + + /** @return The number of active, pending timers and post operations */ + size_t NumActive() const + { + return postQueue.size(); + } + + size_t NumPendingTimers() const + { + return timers.size(); + } + + openpal::MonotonicTimestamp NextTimerExpiration(); + + size_t AdvanceTime(openpal::TimeDuration aDuration); + + // doesn't check timers + void AddTime(openpal::TimeDuration aDuration); + + bool AdvanceToNextTimer(); + +private: + + size_t CheckForExpiredTimers(); + + bool FindExpiredTimer(); + + void Cancel(openpal::ITimer* apTimer); + + typedef std::deque PostQueue; + typedef std::vector TimerVector; + + bool mPostIsSynchronous; + openpal::MonotonicTimestamp mCurrentTime; + + PostQueue postQueue; + TimerVector timers; +}; + +/** @section desc Test timer class used in conjunction with MockExecutor */ +class MockTimer : public openpal::ITimer +{ + friend class MockExecutor; + +public: + MockTimer(MockExecutor*, const openpal::MonotonicTimestamp&, const openpal::action_t& runnable); + + //implement ITimer + void Cancel(); + openpal::MonotonicTimestamp ExpiresAt(); + +private: + openpal::MonotonicTimestamp mTime; + MockExecutor* mpSource; + openpal::action_t runnable; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.cpp new file mode 100644 index 0000000..275004b --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.cpp @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#include "MockLogHandler.h" + +#include + +#include + +using namespace openpal; + +namespace testlib +{ + +LogRecord::LogRecord(const LogEntry& entry) : + id(entry.loggerid), + filters(entry.filters), + location(entry.location), + message(entry.message) +{ + +} + +void MockLogHandlerImpl::Log(const LogEntry& entry) +{ + std::lock_guard lock(this->mutex); + + if (outputToStdIO) + { + std::cout << entry.message << std::endl; + } + + this->messages.push_back(entry); +} + +void MockLogHandler::ClearLog() +{ + this->impl->messages.clear(); +} + +void MockLogHandler::Log(const std::string& location, const std::string& message) +{ + this->impl->Log( + LogEntry("test", openpal::logflags::EVENT, location.c_str(), message.c_str()) + ); +} + +void MockLogHandler::WriteToStdIo() +{ + this->impl->outputToStdIO = true; +} + +bool MockLogHandler::GetNextEntry(LogRecord& record) +{ + if (impl->messages.empty()) return false; + else + { + record = impl->messages.front(); + impl->messages.pop_front(); + return true; + } +} + +} + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.h new file mode 100644 index 0000000..20b268b --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockLogHandler.h @@ -0,0 +1,91 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ + +#ifndef OPENPAL_MOCKLOGHANDLER_H +#define OPENPAL_MOCKLOGHANDLER_H + +#include + +#include +#include +#include + +namespace testlib +{ + +class LogRecord +{ +public: + + LogRecord() = default; + LogRecord(const openpal::LogEntry& entry); + + std::string id; + openpal::LogFilters filters = 0; + std::string location; + std::string message; +}; + +struct MockLogHandlerImpl : public openpal::ILogHandler +{ + virtual void Log(const openpal::LogEntry& entry) override; + + std::mutex mutex; + bool outputToStdIO = false; + std::deque messages; +}; + +class MockLogHandler +{ + +public: + + MockLogHandler() : + impl(std::make_shared()), + logger(impl, "test", ~0) + {} + + void WriteToStdIo(); + + void Log(const std::string& location, const std::string& message); + + void ClearLog(); + + bool GetNextEntry(LogRecord& record); + +private: + + std::shared_ptr impl; + +public: + + openpal::Logger logger; + +}; + + + + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/MockUTCTimeSource.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockUTCTimeSource.h new file mode 100644 index 0000000..a0b90b1 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/MockUTCTimeSource.h @@ -0,0 +1,49 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_MOCKUTCTIMESOURCE_H_ +#define TESTLIB_MOCKUTCTIMESOURCE_H_ + +#include + +namespace testlib +{ + +class MockUTCTimeSource : public openpal::IUTCTimeSource +{ + +public: + + MockUTCTimeSource() : time(0) + {} + + virtual openpal::UTCTimestamp Now() override final + { + return openpal::UTCTimestamp(time); + } + + uint64_t time; +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/Random.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/Random.h new file mode 100644 index 0000000..67f5639 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/Random.h @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_RANDOM_H_ +#define TESTLIB_RANDOM_H_ + +#include + +namespace testlib +{ + +template +class Random +{ + +public: + Random(T min = std::numeric_limits::min(), T max = std::numeric_limits::max()) : + rng(), + dist(min, max) + { + + } + + T Next() + { + return dist(rng); + } + +private: + std::mt19937 rng; + std::uniform_int_distribution dist; +}; + +class RandomBool : private Random +{ +public: + RandomBool() : Random(0, 1) + {} + + bool NextBool() + { + return Next() ? true : false; + } +}; + + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomDouble.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomDouble.h new file mode 100644 index 0000000..a8c931e --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomDouble.h @@ -0,0 +1,51 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_RANDOM_DOUBLE_H_ +#define TESTLIB_RANDOM_DOUBLE_H_ + +#include + +namespace testlib +{ + +class RandomDouble +{ + +public: + RandomDouble() : + rng(), + dist(0.0, 1.0) + {} + + double Next() + { + return dist(rng); + } + +private: + std::mt19937 rng; + std::uniform_real_distribution dist; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.cpp new file mode 100644 index 0000000..4ced25c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.cpp @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "RandomizedBuffer.h" + +namespace testlib +{ + +RandomizedBuffer::RandomizedBuffer(uint32_t aSize) : + testlib::CopyableBuffer(aSize), + rand() +{ + Randomize(); +} + +void RandomizedBuffer::Randomize() +{ + for (uint32_t i = 0; i < this->Size(); ++i) mpBuff[i] = static_cast(rand.Next() % 256); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.h new file mode 100644 index 0000000..01e1f0a --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/RandomizedBuffer.h @@ -0,0 +1,47 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_RANDOMIZED_BUFFER_H_ +#define TESTLIB_RANDOMIZED_BUFFER_H_ + +#include "CopyableBuffer.h" +#include "Random.h" + +namespace testlib +{ + +class RandomizedBuffer : public testlib::CopyableBuffer +{ + +public: + + RandomizedBuffer(uint32_t aSize); + + void Randomize(); + +private: + Random rand; +}; + +} + +#endif + + diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.cpp new file mode 100644 index 0000000..fa4cdc1 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.cpp @@ -0,0 +1,43 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "StopWatch.h" + +using namespace std::chrono; + +namespace testlib +{ + +StopWatch::StopWatch() : mStartTime(std::chrono::steady_clock::now()) +{ + +} + +std::chrono::steady_clock::duration StopWatch::Elapsed(bool aReset) +{ + return std::chrono::steady_clock::now() - mStartTime; +} + +void StopWatch :: Restart() +{ + mStartTime = std::chrono::steady_clock::now(); +} + +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.h new file mode 100644 index 0000000..e47505a --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/StopWatch.h @@ -0,0 +1,52 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef TESTLIB_STOP_WATCH_H +#define TESTLIB_STOP_WATCH_H + +#include + +namespace testlib +{ + +/** + This class is designed to make it easier to do simple timing tests +*/ +class StopWatch +{ +public: + + StopWatch(); + + //get the elapsed time since creation or the last restart + //by default each call to Elapsed restarts the timer. + std::chrono::steady_clock::duration Elapsed(bool aReset = true); + + //restart or re-zero the StopWatch. + void Restart(); + +private: + std::chrono::steady_clock::time_point mStartTime; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.cpp b/utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.cpp new file mode 100644 index 0000000..cb4692a --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.cpp @@ -0,0 +1,44 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "Timeout.h" + +using namespace std::chrono; + +namespace testlib +{ + +Timeout::Timeout(std::chrono::steady_clock::duration aTimeout) + : mExpireTime(std::chrono::steady_clock::now() + aTimeout) +{ + +} + +bool Timeout :: IsExpired() +{ + return std::chrono::steady_clock::now() >= mExpireTime; +} + +std::chrono::steady_clock::duration Timeout::Remaining() +{ + return mExpireTime - std::chrono::steady_clock::now(); +} + +} diff --git a/utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.h b/utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.h new file mode 100644 index 0000000..09eebdb --- /dev/null +++ b/utils/dnp3_src/cpp/tests/libs/src/testlib/Timeout.h @@ -0,0 +1,69 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef _TIMEOUT_H__ +#define _TIMEOUT_H__ + +#include + +namespace testlib +{ + +// Use this class to simplify writing do loops with a timeout +// it minimizes the number of calls to get datetime and allows +// us to easily replace the implementation later if we find an +// even more effecient way to implement the timeout checking. +// +// Intended Usage: +// +// Timeout to(5000); +// do{ +// //call some subordinate slow function +// bool success = WaitForInput(to.Remaining()); +// +// //do something on success +// if(success) return or break; +// +// //or go back around the loop, the next call to +// //remaining will be guarnteed to be > 0 +// }while(!to.IsExpired()); +class Timeout +{ +public: + // constuctor, timeout will expire this many mills in the future + Timeout(std::chrono::steady_clock::duration aTimeout); + + // returns whether its expired + bool IsExpired(); + + // returns how much time is left + std::chrono::steady_clock::duration Remaining(); + + +private: + + std::chrono::steady_clock::time_point mExpireTime; + +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/CatchTestStart.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/CatchTestStart.cpp new file mode 100644 index 0000000..3da2194 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/CatchTestStart.cpp @@ -0,0 +1,22 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#define CATCH_CONFIG_MAIN +#include diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUParsing.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUParsing.cpp new file mode 100644 index 0000000..2e2ae8d --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUParsing.cpp @@ -0,0 +1,463 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MockAPDUHeaderHandler.h" +#include "mocks/MeasurementComparisons.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +void TestComplex(const std::string& hex, ParseResult expected, size_t numCalls, std::function validate) +{ + HexSequence buffer(hex); + MockApduHeaderHandler mock; + + testlib::MockLogHandler log; + auto result = APDUParser::Parse(buffer.ToRSlice(), mock, &log.logger); + + REQUIRE((result == expected)); + REQUIRE(numCalls == mock.records.size()); + + validate(mock); +} + +void TestSimple(const std::string& hex, ParseResult expected, size_t numCalls) +{ + TestComplex(hex, expected, numCalls, [](MockApduHeaderHandler&) {}); +} + +std::string BufferToString(const RSlice& buff) +{ + const uint8_t* pBuffer = buff; + return std::string(reinterpret_cast(pBuffer), buff.Size()); +} + +#define SUITE(name) "APDUParsingTestSuite - " name + +TEST_CASE(SUITE("HeaderParsingEmptySring")) +{ + HexSequence buffer(""); + APDUHeader header; + REQUIRE(!APDUHeaderParser::ParseRequest(buffer.ToRSlice(), header)); +} + +TEST_CASE(SUITE("HeaderParsesReqeust")) +{ + HexSequence buffer("C0 02 AB CD"); + APDUHeader header; + REQUIRE(APDUHeaderParser::ParseRequest(buffer.ToRSlice(), header)); + REQUIRE(header.control.ToByte() == AppControlField(true, true, false, false, 0).ToByte()); + REQUIRE(header.function == FunctionCode::WRITE); + REQUIRE("AB CD" == ToHex(buffer.ToRSlice().Skip(2))); +} + +TEST_CASE(SUITE("ResponseLessThanFour")) +{ + HexSequence buffer("C0 02 01"); + APDUResponseHeader header; + REQUIRE(!APDUHeaderParser::ParseResponse(buffer.ToRSlice(), header)); +} + +TEST_CASE(SUITE("HeaderParsesResponse")) +{ + HexSequence buffer("C0 02 01 02 BE EF"); + APDUResponseHeader header; + REQUIRE(APDUHeaderParser::ParseResponse(buffer.ToRSlice(), header)); + REQUIRE(header.control.ToByte() == AppControlField(true, true, false, false, 0).ToByte()); + REQUIRE(header.function == FunctionCode::WRITE); + REQUIRE(header.IIN == IINField(01, 02)); + REQUIRE("BE EF" == ToHex(buffer.ToRSlice().Skip(4))); +} + + +TEST_CASE(SUITE("EmptyStringParsesOK")) +{ + TestSimple("", ParseResult::OK, 0); +} + +TEST_CASE(SUITE("NotEnoughData")) +{ + TestSimple("AB CD", ParseResult::NOT_ENOUGH_DATA_FOR_HEADER, 0); +} + +TEST_CASE(SUITE("AllObjects")) +{ + // (2,2) all, (2,0) all + TestComplex("02 02 06 02 00 06", ParseResult::OK, 2, [](MockApduHeaderHandler & mock) + { + REQUIRE((GroupVariation::Group2Var2 == mock.records[0].enumeration)); + REQUIRE((GroupVariation::Group2Var0 == mock.records[1].enumeration)); + }); +} + +TEST_CASE(SUITE("TestUnknownQualifier")) +{ + // (2,2) unknown qualifier 0xAB + TestSimple("02 02 AB", ParseResult::UNKNOWN_QUALIFIER, 0); +} + +TEST_CASE(SUITE("NotEnoughDataForObjects")) +{ + // 1 byte start/stop 1->4, 3 octests data + TestSimple("01 02 00 01 04 FF FF FF", ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS, 0); +} + +TEST_CASE(SUITE("Group1Var2Range")) +{ + // 1 byte start/stop 3->5, 3 octests data + TestComplex("01 02 00 03 05 81 01 81", ParseResult::OK, 1, [](MockApduHeaderHandler & mock) + { + REQUIRE(3 == mock.staticBinaries.size()); + { + Indexed value(Binary(true), 3); + REQUIRE((value == mock.staticBinaries[0])); + } + { + Indexed value(Binary(false), 4); + REQUIRE((value == mock.staticBinaries[1])); + } + { + Indexed value(Binary(true), 5); + REQUIRE((value == mock.staticBinaries[2])); + } + }); +} + +TEST_CASE(SUITE("Group1Var2RangeAsReadRange")) +{ + HexSequence buffer("01 02 00 03 05"); + MockApduHeaderHandler mock; + auto result = APDUParser::Parse(buffer.ToRSlice(), mock, nullptr, ParserSettings::NoContents()); + REQUIRE((result == ParseResult::OK)); +} + + +TEST_CASE(SUITE("Group1Var2CountOfZero")) +{ + // 1 byte count == 0, 0 octets data + TestSimple("01 02 07 00", ParseResult::COUNT_OF_ZERO, 0); +} + +TEST_CASE(SUITE("Group1Var2With2Headers")) +{ + // 1 -> 1 & 2 -> 3 + TestComplex("01 02 00 01 01 81 01 02 00 02 03 81 81", ParseResult::OK, 2, [](MockApduHeaderHandler & mock) + { + REQUIRE(2 == mock.records.size()); + }); +} + + +TEST_CASE(SUITE("Group1Var2Range1to3")) +{ + // 1 byte start / stop, 1 -> 3, 3 octets data + TestComplex("01 02 00 01 03 81 01 81", ParseResult::OK, 1, [](MockApduHeaderHandler & mock) + { + REQUIRE(3 == mock.staticBinaries.size()); + { + Indexed value(Binary(true), 1); + REQUIRE((value == mock.staticBinaries[0])); + } + { + Indexed value(Binary(false), 2); + REQUIRE((value == mock.staticBinaries[1])); + } + { + Indexed value(Binary(true), 3); + REQUIRE((value == mock.staticBinaries[2])); + } + }); +} + +TEST_CASE(SUITE("Group1Var2Range16")) +{ + // 2 byte count == 1, 1 octet data + TestComplex("01 02 01 03 00 03 00 81", ParseResult::OK, 1, [](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.staticBinaries.size()); + Indexed value(Binary(true), 3); + REQUIRE((value == mock.staticBinaries[0])); + }); +} + +TEST_CASE(SUITE("Group1Var2AllCountQualifiers")) +{ + auto validator = [](MockApduHeaderHandler & mock) + { + REQUIRE(2 == mock.staticBinaries.size()); + { + Indexed value(Binary(true), 0); + REQUIRE((value == mock.staticBinaries[0])); + } + { + Indexed value(Binary(false), 1); + REQUIRE((value == mock.staticBinaries[1])); + } + }; + + TestComplex("01 02 00 00 01 81 01", ParseResult::OK, 1, validator); + TestComplex("01 02 01 00 00 01 00 81 01", ParseResult::OK, 1, validator); + TestSimple("01 02 09 02 00 00 00 81 01", ParseResult::UNKNOWN_QUALIFIER, 0); +} + +TEST_CASE(SUITE("FlippedRange")) +{ + // 1 byte start/stop w/ start > stop + TestSimple("01 02 00 05 03", ParseResult::BAD_START_STOP, 0); + TestSimple("01 02 00 FF 00", ParseResult::BAD_START_STOP, 0); +} + +TEST_CASE(SUITE("TestUnreasonableRanges")) +{ + // 2 byte start/stop 0->65535, no data - the default max objects is very low (32768) + TestSimple("01 02 01 00 00 FF FF", ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS, 0); +} + +TEST_CASE(SUITE("ParserDoesNotAllowEmptyOctetStrings")) +{ + HexSequence buffer("6E 00 00 00 FF"); // 255 + 256 + MockApduHeaderHandler mock; + + auto result = APDUParser::Parse(buffer.ToRSlice(), mock, nullptr); + + REQUIRE((result == ParseResult::INVALID_OBJECT)); + REQUIRE(0 == mock.records.size()); +} + +TEST_CASE(SUITE("Group1Var2CountWithIndexUInt8")) +{ + // 1 byte count, 1 byte index, index == 09, value = 0x81 + TestSimple("01 02 17 01 09 81", ParseResult::INVALID_OBJECT_QUALIFIER, 0); +} + +TEST_CASE(SUITE("Group2Var1CountWithAllIndexSizes")) +{ + auto validator = [](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.eventBinaries.size()); + Indexed value(Binary(true), 9); + REQUIRE((value == mock.eventBinaries[0])); + }; + + // 1 byte count, 1 byte index, index == 09, value = 0x81 + TestComplex("02 01 17 01 09 81", ParseResult::OK, 1, validator); + TestComplex("02 01 28 01 00 09 00 81", ParseResult::OK, 1, validator); +} + +TEST_CASE(SUITE("Group1Var1ByRange")) +{ + // 1 byte start/stop 3 -> 6 + TestComplex("01 01 00 03 06 09", ParseResult::OK, 1, [](MockApduHeaderHandler & mock) + { + REQUIRE(4 == mock.staticBinaries.size()); + { + Indexed value(Binary(true), 3); + REQUIRE((value == mock.staticBinaries[0])); + } + { + Indexed value(Binary(false), 4); + REQUIRE((value == mock.staticBinaries[1])); + } + { + Indexed value(Binary(false), 5); + REQUIRE((value == mock.staticBinaries[2])); + } + { + Indexed value(Binary(true), 6); + REQUIRE((value == mock.staticBinaries[3])); + } + }); +} + +TEST_CASE(SUITE("Group12Var1WithIndexSizesLatchOn")) +{ + auto hex = "0C 01 17 01 09 03 01 64 00 00 00 C8 00 00 00 00"; + + auto validator = [&](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.crobRequests.size()); + ControlRelayOutputBlock crob(ControlCode::LATCH_ON, 1, 100, 200); + Indexed value(crob, 9); + REQUIRE((value == mock.crobRequests[0])); + + REQUIRE(1 == mock.records.size()); + }; + + + TestComplex(hex, ParseResult::OK, 1, validator); +} + +TEST_CASE(SUITE("Group12Var1WithIndexSizesLatchOff")) +{ + auto hex = "0C 01 17 01 09 04 01 64 00 00 00 C8 00 00 00 00"; + + auto validator = [&](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.crobRequests.size()); + ControlRelayOutputBlock crob(ControlCode::LATCH_OFF, 1, 100, 200); + Indexed value(crob, 9); + REQUIRE((value == mock.crobRequests[0])); + + REQUIRE(1 == mock.records.size()); + }; + + + TestComplex(hex, ParseResult::OK, 1, validator); +} + +TEST_CASE(SUITE("TestIINValue")) +{ + TestComplex("50 01 00 07 07 00", ParseResult::OK, 1, [&](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.iinBits.size()); + REQUIRE_FALSE(mock.iinBits[0].value.value); + }); +} + +TEST_CASE(SUITE("Group60Var1Var2Var3Var4")) +{ + TestComplex("3C 01 06 3C 02 06 3C 03 06 3C 04 06", ParseResult::OK, 4, [&](MockApduHeaderHandler & mock) + { + REQUIRE(4 == mock.records.size()); + REQUIRE((GroupVariation::Group60Var1 == mock.records[0].enumeration)); + REQUIRE((GroupVariation::Group60Var2 == mock.records[1].enumeration)); + REQUIRE((GroupVariation::Group60Var3 == mock.records[2].enumeration)); + REQUIRE((GroupVariation::Group60Var4 == mock.records[3].enumeration)); + }); +} + +TEST_CASE(SUITE("TestDoubleBitCTO")) +{ + TestComplex("04 03 17 02 03 C1 07 00 05 41 09 00", ParseResult::OK, 1, [&](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.records.size()); + REQUIRE(2 == mock.eventDoubleBinaries.size()); + + Indexed event1(DoubleBitBinary(DoubleBit::INDETERMINATE, 0x01, DNPTime(7)), 3); + Indexed event2(DoubleBitBinary(DoubleBit::DETERMINED_OFF, 0x01, DNPTime(9)), 5); + + REQUIRE((event1 == mock.eventDoubleBinaries[0])); + REQUIRE((event2 == mock.eventDoubleBinaries[1])); + }); +} + +// "hello" == [0x68, 0x65, 0x6C, 0x6C, 0x6F] +// "world" == [0x77, 0x6F, 0x72, 0x6C, 0x64] + +TEST_CASE(SUITE("OctetStringEvents")) +{ + // Group 111 (0x6F) Variation (length == 5), 1 byte count / 1 byte index (4), count of 1, "hello" == [0x68, 0x65, 0x6C, 0x6C, 0x6F] + TestComplex("6F 05 17 02 04 68 65 6C 6C 6F FF 77 6F 72 6C 64", ParseResult::OK, 1, [&](MockApduHeaderHandler & mock) + { + REQUIRE(2 == mock.indexPrefixedOctets.size()); + REQUIRE(4 == mock.indexPrefixedOctets[0].index); + REQUIRE("hello" == BufferToString(mock.indexPrefixedOctets[0].value.ToRSlice())); + REQUIRE(255 == mock.indexPrefixedOctets[1].index); + REQUIRE("world" == BufferToString(mock.indexPrefixedOctets[1].value.ToRSlice())); + }); +} + +TEST_CASE(SUITE("OctetStringStatic")) +{ + // Group 110 (0x6E) Variation (length == 5), 1 byte start/stop (7), count of 1, "hello" == [0x68, 0x65, 0x6C, 0x6C, 0x6F] + TestComplex("6E 05 00 07 08 68 65 6C 6C 6F 77 6F 72 6C 64", ParseResult::OK, 1, [&](MockApduHeaderHandler & mock) + { + REQUIRE(2 == mock.rangedOctets.size()); + REQUIRE(7 == mock.rangedOctets[0].index); + REQUIRE("hello" == BufferToString(mock.rangedOctets[0].value.ToRSlice())); + REQUIRE(8 == mock.rangedOctets[1].index); + REQUIRE("world" == BufferToString(mock.rangedOctets[1].value.ToRSlice())); + }); +} + +TEST_CASE(SUITE("Group13Var1CountWithAllIndexSizes")) +{ + auto validator = [](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.binaryCommandEvents.size()); + Indexed value(BinaryCommandEvent(true, CommandStatus::TIMEOUT), 9); + REQUIRE((value == mock.binaryCommandEvents[0])); + }; + + // 1 byte count, 1 byte index, index == 09, value = 0x81 + TestComplex("0D 01 17 01 09 81", ParseResult::OK, 1, validator); + TestComplex("0D 01 28 01 00 09 00 81", ParseResult::OK, 1, validator); +} + +TEST_CASE(SUITE("Group13Var2CountWithAllIndexSizes")) +{ + auto validator = [](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.binaryCommandEvents.size()); + DNPTime time(1419802341000); + Indexed value(BinaryCommandEvent(true, CommandStatus::TIMEOUT, time), 9); + REQUIRE((value == mock.binaryCommandEvents[0])); + }; + + // 1 byte count, 1 byte index, index == 09, value = 0x81, time = 1419802341000 (014A92D06E88 in hex / 886ED0924A01 little endian) + TestComplex("0D 02 17 01 09 81 88 6E D0 92 4A 01", ParseResult::OK, 1, validator); + TestComplex("0D 02 28 01 00 09 00 81 88 6E D0 92 4A 01", ParseResult::OK, 1, validator); +} + +TEST_CASE(SUITE("Group43Var1CountWithAllIndexSizes")) +{ + auto validator = [](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.analogCommandEvents.size()); + Indexed value(AnalogCommandEvent(50, CommandStatus::TIMEOUT), 9); + REQUIRE((value == mock.analogCommandEvents[0])); + }; + + // 1 byte count, 1 byte index, index == 09, status = 0x01, value = 0x32 + TestComplex("2B 01 17 01 09 01 32 00 00 00", ParseResult::OK, 1, validator); + TestComplex("2B 01 28 01 00 09 00 01 32 00 00 00", ParseResult::OK, 1, validator); +} + +TEST_CASE(SUITE("Group43Var3CountWithAllIndexSizes")) +{ + auto validator = [](MockApduHeaderHandler & mock) + { + REQUIRE(1 == mock.analogCommandEvents.size()); + Indexed value(AnalogCommandEvent(50, CommandStatus::TIMEOUT, DNPTime(1419802341000)), 9); + REQUIRE((value == mock.analogCommandEvents[0])); + }; + + // 1 byte count, 1 byte index, index == 09, status = 0x01, value = 0x32, time = 1419802341000 (014A92D06E88 in hex / 886ED0924A01 little endian) + TestComplex("2B 03 17 01 09 01 32 00 00 00 88 6E D0 92 4A 01", ParseResult::OK, 1, validator); + TestComplex("2B 03 28 01 00 09 00 01 32 00 00 00 88 6E D0 92 4A 01", ParseResult::OK, 1, validator); +} diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUWriting.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUWriting.cpp new file mode 100644 index 0000000..af04f21 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestAPDUWriting.cpp @@ -0,0 +1,297 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mocks/APDUHelpers.h" + +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "APDUWritingTestSuite - " name + +TEST_CASE(SUITE("AllObjectsAndRollback")) +{ + APDURequest request(APDUHelpers::Request(FunctionCode::READ)); + auto writer = request.GetWriter(); + writer.WriteHeader(Group60Var1::ID(), QualifierCode::ALL_OBJECTS); + writer.WriteHeader(Group60Var2::ID(), QualifierCode::ALL_OBJECTS); + writer.Mark(); + writer.WriteHeader(Group60Var3::ID(), QualifierCode::ALL_OBJECTS); + writer.WriteHeader(Group60Var4::ID(), QualifierCode::ALL_OBJECTS); + + REQUIRE("C0 01 3C 01 06 3C 02 06 3C 03 06 3C 04 06" == ToHex(request.ToRSlice())); + + writer.Rollback(); + + REQUIRE("C0 01 3C 01 06 3C 02 06" == ToHex(request.ToRSlice())); +} + +TEST_CASE(SUITE("AllObjectsReturnsFalseWhenFull")) +{ + APDURequest request(APDUHelpers::Request(FunctionCode::READ, 6)); + auto writer = request.GetWriter(); + + REQUIRE(writer.WriteHeader(Group60Var1::ID(), QualifierCode::ALL_OBJECTS)); + REQUIRE(!writer.WriteHeader(Group60Var1::ID(), QualifierCode::ALL_OBJECTS)); + + REQUIRE("C0 01 3C 01 06" == ToHex(request.ToRSlice())); +} + + +TEST_CASE(SUITE("RangeWriteIteratorStartStop")) +{ + APDUResponse response(APDUHelpers::Response()); + auto writer = response.GetWriter(); + + { + auto iterator = writer.IterateOverRange(QualifierCode::UINT8_START_STOP, Group20Var6::Inst(), 2); + REQUIRE(iterator.Write(Counter(9))); + REQUIRE(iterator.Write(Counter(7))); + } + + REQUIRE("C0 81 00 00 14 06 00 02 03 09 00 07 00" == ToHex(response.ToRSlice())); +} + +TEST_CASE(SUITE("RangeIterator UInt8 boundary condition")) +{ + APDUResponse response(APDUHelpers::Response()); + auto writer = response.GetWriter(); + + { + auto iterator = writer.IterateOverRange(QualifierCode::UINT8_START_STOP, Group1Var2::Inst(), 0); + + for (int i = 0; i < 256; ++i) + { + REQUIRE(iterator.Write(Binary(true))); + } + + REQUIRE_FALSE(iterator.Write(Binary(true))); + } + + std::string beginsWith("C0 81 00 00 01 02 00 00 FF"); + auto truncated = ToHex(response.ToRSlice()).substr(0, beginsWith.size()); + + REQUIRE(beginsWith == truncated); +} + +TEST_CASE(SUITE("CountIterator UInt8 boundary condition")) +{ + APDUResponse response(APDUHelpers::Response()); + auto writer = response.GetWriter(); + + { + auto iterator = writer.IterateOverCount(QualifierCode::UINT8_CNT, Group1Var2::Inst()); + + for (int i = 0; i < 255; ++i) + { + REQUIRE(iterator.Write(Binary(true))); + } + + REQUIRE_FALSE(iterator.Write(Binary(true))); + } + + std::string beginsWith("C0 81 00 00 01 02 07 FF"); + auto truncated = ToHex(response.ToRSlice()).substr(0, beginsWith.size()); + + REQUIRE(beginsWith == truncated); +} + +TEST_CASE(SUITE("EmptyHeadersWhenNotEnoughSpaceForSingleValue")) +{ + APDUResponse response(APDUHelpers::Response(8)); + auto writer = response.GetWriter(); + + auto iterator = writer.IterateOverRange(QualifierCode::UINT8_START_STOP, Group20Var6::Inst(), 2); + + REQUIRE(!iterator.IsValid()); + + REQUIRE("C0 81 00 00" == ToHex(response.ToRSlice())); +} + +TEST_CASE(SUITE("CountWriteIteratorAllowsCountOfZero")) +{ + APDUResponse response(APDUHelpers::Response()); + auto writer = response.GetWriter(); + + writer.IterateOverCount(QualifierCode::UINT16_CNT, Group30Var1::Inst()); + + REQUIRE("C0 81 00 00 1E 01 08 00 00" == ToHex(response.ToRSlice())); + +} + +TEST_CASE(SUITE("CountWriteIteratorFillsUpCorrectly")) +{ + APDUResponse response(APDUHelpers::Response(15)); + auto writer = response.GetWriter(); + + { + auto iter = writer.IterateOverCount(QualifierCode::UINT8_CNT, Group30Var2::Inst()); + + REQUIRE(iter.Write(Analog(9, 0xFF))); + REQUIRE(iter.Write(Analog(7, 0xFF))); + REQUIRE(!iter.Write(Analog(7, 0xFF))); //we're full + } + + REQUIRE("C0 81 00 00 1E 02 07 02 FF 09 00 FF 07 00" == ToHex(response.ToRSlice())); +} + +TEST_CASE(SUITE("PrefixWriteIteratorWithSingleCROB")) +{ + APDUResponse response(APDUHelpers::Response()); + auto writer = response.GetWriter(); + + { + auto iter = writer.IterateOverCountWithPrefix(QualifierCode::UINT8_CNT_UINT8_INDEX, Group12Var1::Inst()); + REQUIRE(iter.IsValid()); + ControlRelayOutputBlock crob(ControlCode::LATCH_ON, 0x1F, 0x10, 0xAA, CommandStatus::LOCAL); + REQUIRE(iter.Write(crob, 0x21)); + } + + REQUIRE("C0 81 00 00 0C 01 17 01 21 03 1F 10 00 00 00 AA 00 00 00 07" == ToHex(response.ToRSlice())); +} + +TEST_CASE(SUITE("PrefixWriteIteratorCTO")) +{ + APDUResponse response(APDUHelpers::Response()); + auto writer = response.GetWriter(); + + Group51Var1 cto; + cto.time = DNPTime(0xAA); + + { + auto iter = writer.IterateOverCountWithPrefixAndCTO(QualifierCode::UINT16_CNT_UINT16_INDEX, Group2Var3::Inst(), cto); + REQUIRE(iter.IsValid()); + + REQUIRE(iter.Write(Binary(true, 0x01, DNPTime(0x0B)), 6)); + REQUIRE(iter.Write(Binary(true, 0x01, DNPTime(0x0C)), 7)); + } + + REQUIRE("C0 81 00 00 33 01 07 01 AA 00 00 00 00 00 02 03 28 02 00 06 00 81 0B 00 07 00 81 0C 00" == ToHex(response.ToRSlice())); +} + +TEST_CASE(SUITE("PrefixWriteIteratorCTOSpaceForOnly1Value")) +{ + APDUResponse response(APDUHelpers::Response(26)); + auto writer = response.GetWriter(); + + Group51Var1 cto; + cto.time = DNPTime(0xAA); + + { + auto iter = writer.IterateOverCountWithPrefixAndCTO(QualifierCode::UINT16_CNT_UINT16_INDEX, Group2Var3::Inst(), cto); + REQUIRE(iter.IsValid()); + REQUIRE(iter.Write(Binary(true, 0x01, DNPTime(0x0B)), 6)); + REQUIRE(!iter.Write(Binary(true, 0x01, DNPTime(0x0C)), 7)); + } + + REQUIRE("C0 81 00 00 33 01 07 01 AA 00 00 00 00 00 02 03 28 01 00 06 00 81 0B 00" == ToHex(response.ToRSlice())); +} + +TEST_CASE(SUITE("PrefixWriteIteratorNotEnoughSpaceForAValue")) +{ + APDUResponse response(APDUHelpers::Response(23)); + auto writer = response.GetWriter(); + + Group51Var1 cto; + cto.time = DNPTime(0xAA); + + { + auto iter = writer.IterateOverCountWithPrefixAndCTO(QualifierCode::UINT16_CNT_UINT16_INDEX, Group2Var3::Inst(), cto); + REQUIRE(!iter.IsValid()); + } + + REQUIRE("C0 81 00 00" == ToHex(response.ToRSlice())); +} + + +TEST_CASE(SUITE("SingleValueWithIndexCROBLatchOn")) +{ + APDURequest request(APDUHelpers::Request(FunctionCode::SELECT)); + auto writer = request.GetWriter(); + + ControlRelayOutputBlock crob(ControlCode::LATCH_ON, 0x1F, 0x10, 0xAA, CommandStatus::LOCAL); + + REQUIRE(writer.WriteSingleIndexedValue(QualifierCode::UINT16_CNT, Group12Var1::Inst(), crob, 0x21)); + + REQUIRE("C0 03 0C 01 08 01 00 21 00 03 1F 10 00 00 00 AA 00 00 00 07" == ToHex(request.ToRSlice())); +} + +TEST_CASE(SUITE("SingleValueWithIndexCROBLatchOff")) +{ + APDURequest request(APDUHelpers::Request(FunctionCode::SELECT)); + auto writer = request.GetWriter(); + + ControlRelayOutputBlock crob(ControlCode::LATCH_OFF, 0x1F, 0x10, 0xAA, CommandStatus::LOCAL); + + REQUIRE(writer.WriteSingleIndexedValue(QualifierCode::UINT16_CNT, Group12Var1::Inst(), crob, 0x21)); + + REQUIRE("C0 03 0C 01 08 01 00 21 00 04 1F 10 00 00 00 AA 00 00 00 07" == ToHex(request.ToRSlice())); +} + + +TEST_CASE(SUITE("WriteSingleValue")) +{ + APDURequest request(APDUHelpers::Request(FunctionCode::WRITE)); + auto writer = request.GetWriter(); + + Group50Var1 obj; + obj.time = DNPTime(0x1234); + REQUIRE(writer.WriteSingleValue(QualifierCode::UINT8_CNT, obj)); + + REQUIRE("C0 02 32 01 07 01 34 12 00 00 00 00" == ToHex(request.ToRSlice())); +} + +TEST_CASE(SUITE("WriteIINRestart")) +{ + APDURequest request(APDUHelpers::Request(FunctionCode::WRITE)); + auto writer = request.GetWriter(); + + { + auto iter = writer.IterateOverSingleBitfield(GroupVariationID(80, 1), QualifierCode::UINT8_START_STOP, 7); + iter.Write(true); + iter.Write(true); + } + + REQUIRE("C0 02 50 01 00 07 08 03" == ToHex(request.ToRSlice())); +} + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestAuthRequestParser.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestAuthRequestParser.cpp new file mode 100644 index 0000000..20cd072 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestAuthRequestParser.cpp @@ -0,0 +1,106 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include "mocks/MockAPDUHeaderHandler.h" + +#include + +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace openpal; +using namespace opendnp3; +using namespace asiodnp3; +using namespace testlib; + +#define SUITE(name) "AuthRequestParserTestSuite - " name + + +TEST_CASE(SUITE("RejectsInsufficientDataForHeader")) +{ + HexSequence buffer("78 01"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::NOT_ENOUGH_DATA_FOR_HEADER); +} + +TEST_CASE(SUITE("RejectsUnknownQualifier")) +{ + HexSequence buffer("78 01 FF FF"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::UNKNOWN_QUALIFIER); +} + +TEST_CASE(SUITE("RejectsInsufficientFreeFormatData")) +{ + HexSequence buffer("78 01 5B 01 08 00 FF FF FF FF FF FF FF"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::NOT_ENOUGH_DATA_FOR_OBJECTS); +} + +TEST_CASE(SUITE("RejectsTrailingData")) +{ + HexSequence buffer("78 01 5B 01 08 00 FF FF FF FF FF FF FF FF FF"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::NOT_ENOUGH_DATA_FOR_HEADER); +} + +TEST_CASE(SUITE("AcceptsMatchingFreeFormatData")) +{ + HexSequence buffer("78 01 5B 01 08 00 11 22 33 44 FF FF FF FF"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::OK); + REQUIRE(handler.records.size() == 1); + REQUIRE(handler.authChallenges.size() == 1); + REQUIRE(handler.authChallenges[0].challengeSeqNum == 0x44332211); +} + +TEST_CASE(SUITE("ParsersKeyStatusRequest")) +{ + HexSequence buffer("78 04 07 01 00 00"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::OK); +} + +TEST_CASE(SUITE("AcceptsKeyStatusRequest")) +{ + HexSequence buffer("78 04 07 01 09 00"); + MockApduHeaderHandler handler; + auto result = APDUParser::Parse(buffer.ToRSlice(), handler, nullptr); + REQUIRE(result == ParseResult::OK); + REQUIRE(handler.authStatusRequests.size() == 1); + REQUIRE(handler.authStatusRequests[0].userNum == 9); +} diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestCRC.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestCRC.cpp new file mode 100644 index 0000000..51969ec --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestCRC.cpp @@ -0,0 +1,46 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + + +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "CRC - " name + +TEST_CASE(SUITE("CrcTest")) +{ + HexSequence hs("05 64 05 C0 01 00 00 04 E9 21"); + REQUIRE(hs.Size() == 10); + REQUIRE(CRC::CalcCrc(hs, 8) == 0x21E9); +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestCastLongLongDouble.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestCastLongLongDouble.cpp new file mode 100644 index 0000000..e8ad558 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestCastLongLongDouble.cpp @@ -0,0 +1,81 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include + + +#define SUITE(name) "Casting - " name +template +T2 TestCast(T1 input) +{ + return static_cast(input); +} + +template +bool IsEqual(T1 a, T1 b) +{ + return a == b; +} + +#define CHECK_CAST(t1, t2, a, b)\ + {t2 amod = TestCast(a);\ + if(!IsEqual(amod,(b))){\ + std::ostringstream oss; \ + oss << (#t1)<< "->" << (#t2) << " doesn't cast correctly: " << (amod) << " != " << (b); \ + std::cout << "Failure: " << oss.str() << std::endl;\ + }} + + +TEST_CASE(SUITE("Casting")) +{ + CHECK_CAST(double, int, 1000.0, 1000); + CHECK_CAST(double, float, 1001.0, 1001.0f); + CHECK_CAST(double, long, 1002.0, 1002); + //these 2 tests fail on the arm device and fail strangley, there + //is definatley something weird going on here, probably because + //the 64 bit long long is the same size as a double so just gets + //shifted into the double strangley. This means that the results + //of an operation can be different if the casting is done and the + //result is stored to memory or if the value stays in a register + //(as an intermediate calculation value), very nasty. + CHECK_CAST(double, int64_t, 1003.0, 1003); + + CHECK_CAST(int64_t, double, 1004, 1004.0); + + CHECK_CAST(double, float, 1012.0, 1012.0f); + CHECK_CAST(int64_t, double, 1006, 1006.0); + + CHECK_CAST(int, double, 1007, 1007.0); + CHECK_CAST(long, double, 1008, 1008.0); + CHECK_CAST(int, float, 1009, 1009.0f); + + CHECK_CAST(float, int64_t, 1010.0f, 1010); + CHECK_CAST(float, int, 1011.0f, 1011); + + CHECK_CAST(int64_t, double, 4294967296LL, 4294967296.0); + CHECK_CAST(double, int64_t, 4294967296.0, 4294967296LL); + +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestCollectionTransform.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestCollectionTransform.cpp new file mode 100644 index 0000000..0cef1f9 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestCollectionTransform.cpp @@ -0,0 +1,51 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include + +using namespace opendnp3; + +#define SUITE(name) "CollectionTransformTestSuite - " name + +TEST_CASE(SUITE("Map integers to booleans")) +{ + int values[4] = { 1, 2, 3, 4 }; + ArrayCollection collectionInt(values, 4); + auto greaterThanTwo = [](const int& x) -> bool { return x > 2; }; + auto collectionBool = Map(collectionInt, greaterThanTwo); + + std::vector items; + auto fillVector = [&items](const bool & item) + { + items.push_back(item); + }; + collectionBool.ForeachItem(fillVector); + + REQUIRE(items.size() == 4); + REQUIRE_FALSE(items[0]); + REQUIRE_FALSE(items[1]); + REQUIRE(items[2]); + REQUIRE(items[3]); + +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestDatabase.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestDatabase.cpp new file mode 100644 index 0000000..3ca2172 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestDatabase.cpp @@ -0,0 +1,182 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MeasurementComparisons.h" +#include "mocks/DatabaseTestObject.h" + +#include + +#include + +using namespace std; +using namespace openpal; +using namespace opendnp3; + +template +void TestBufferForEvent(bool isEvent, const typename Spec::meas_t& newVal, DatabaseTestObject& test, std::deque< Event >& queue) +{ + test.db.Update(newVal, 0); + + if(isEvent) + { + REQUIRE((queue.size() == 1)); + REQUIRE((newVal == queue.front().value)); + REQUIRE((0 == queue.front().index)); + queue.pop_front(); + } + else + { + REQUIRE((queue.size() == 0)); + } +} + +bool IsAnalogEvent(double val1, double val2, double deadband) +{ + Analog a1(val1); + Analog a2(val2); + return AnalogSpec::IsEvent(a1, a2, deadband); +} + +bool IsCounterEvent(uint32_t val1, uint32_t val2, uint32_t deadband) +{ + Counter c1(val1); + Counter c2(val2); + return CounterSpec::IsEvent(c1, c2, deadband); +} + +#define SUITE(name) "DatabaseTestSuite - " name + +// tests for the various analog event conditions +TEST_CASE(SUITE("AnalogEventZeroDeadband")) +{ + REQUIRE_FALSE(IsAnalogEvent(0, 0, 0)); +} + +TEST_CASE(SUITE("AnalogEventOnDeadband")) +{ + REQUIRE_FALSE(IsAnalogEvent(0, 1, 1)); +} + +TEST_CASE(SUITE("AnalogEventNegative")) +{ + REQUIRE(IsAnalogEvent(-34, -36, 1)); +} + +TEST_CASE(SUITE("AnalogInfiniteChange")) +{ + auto maxAnalog = std::numeric_limits::max(); + auto minAnalog = -maxAnalog; + + REQUIRE(IsAnalogEvent(minAnalog, maxAnalog, 1)); +} + +TEST_CASE(SUITE("CounterMaxChange")) +{ + auto max = std::numeric_limits::max(); + REQUIRE(IsCounterEvent(0, max, max - 1)); +} + +TEST_CASE(SUITE("AnalogNoEventNegative")) +{ + REQUIRE_FALSE(IsAnalogEvent(-34, -36, 2)); +} + +// Next 3 tests prove that "no change" doesn't get forwared to IEventBuffer +TEST_CASE(SUITE("BinaryNoChange")) +{ + DatabaseTestObject t(DatabaseSizes::BinaryOnly(1)); + auto view = t.db.GetConfigView(); + view.binaries[0].config.clazz = PointClass::Class1; + TestBufferForEvent(false, Binary(false, ToUnderlying(BinaryQuality::RESTART)), t, t.buffer.binaryEvents); +} + +TEST_CASE(SUITE("AnalogNoChange")) +{ + DatabaseTestObject t(DatabaseSizes::AnalogOnly(1)); + auto view = t.db.GetConfigView(); + view.analogs[0].config.clazz = PointClass::Class1; + TestBufferForEvent(false, Analog(0, ToUnderlying(AnalogQuality::RESTART)), t, t.buffer.analogEvents); +} + +TEST_CASE(SUITE("CounterNoChange")) +{ + DatabaseTestObject t(DatabaseSizes::CounterOnly(1)); + auto view = t.db.GetConfigView(); + view.counters[0].config.clazz = PointClass::Class1; + TestBufferForEvent(false, Counter(0, ToUnderlying(CounterQuality::RESTART)), t, t.buffer.counterEvents); +} + +// Next 3 tests prove that a change detection will forward to the buffer +TEST_CASE(SUITE("BinaryChange")) +{ + DatabaseTestObject t(DatabaseSizes::BinaryOnly(1)); + auto view = t.db.GetConfigView(); + view.binaries[0].config.clazz = PointClass::Class1; + TestBufferForEvent(true, Binary(false, ToUnderlying(BinaryQuality::ONLINE)), t, t.buffer.binaryEvents); +} + +TEST_CASE(SUITE("AnalogChange")) +{ + DatabaseTestObject t(DatabaseSizes::AnalogOnly(1)); + auto view = t.db.GetConfigView(); + view.analogs[0].config.clazz = PointClass::Class1; + TestBufferForEvent(true, Analog(0, ToUnderlying(AnalogQuality::ONLINE)), t, t.buffer.analogEvents); +} + +TEST_CASE(SUITE("CounterChange")) +{ + DatabaseTestObject t(DatabaseSizes::CounterOnly(1)); + auto view = t.db.GetConfigView(); + view.counters[0].config.clazz = PointClass::Class1; + TestBufferForEvent(true, Counter(0, ToUnderlying(CounterQuality::ONLINE)), t, t.buffer.counterEvents); +} + +//show that the last reported change gets recorded correctly and applied correctly for each type +TEST_CASE(SUITE("AnalogLastReportedChange")) +{ + DatabaseTestObject t(DatabaseSizes::AnalogOnly(1)); + auto view = t.db.GetConfigView(); + view.analogs[0].config.clazz = PointClass::Class1; + view.analogs[0].config.deadband = 5; //value must change by more than 5 before being reported + + TestBufferForEvent(false, Analog(-2, ToUnderlying(AnalogQuality::RESTART)), t, t.buffer.analogEvents); + TestBufferForEvent(false, Analog(5, ToUnderlying(AnalogQuality::RESTART)), t, t.buffer.analogEvents); + TestBufferForEvent(true, Analog(6, ToUnderlying(AnalogQuality::RESTART)), t, t.buffer.analogEvents); //change by 6, so 6 should get recorded + TestBufferForEvent(false, Analog(1, ToUnderlying(AnalogQuality::RESTART)), t, t.buffer.analogEvents); + TestBufferForEvent(true, Analog(-1, ToUnderlying(AnalogQuality::RESTART)), t, t.buffer.analogEvents); +} + +TEST_CASE(SUITE("CounterLastReportedChange")) +{ + DatabaseTestObject t(DatabaseSizes::CounterOnly(1)); + auto view = t.db.GetConfigView(); + view.counters[0].config.clazz = PointClass::Class1; + view.counters[0].config.deadband = 5; + + TestBufferForEvent(false, Counter(1, ToUnderlying(CounterQuality::RESTART)), t, t.buffer.counterEvents); + TestBufferForEvent(false, Counter(5, ToUnderlying(CounterQuality::RESTART)), t, t.buffer.counterEvents); + TestBufferForEvent(true, Counter(6, ToUnderlying(CounterQuality::RESTART)), t, t.buffer.counterEvents); //change by 6, so 6 should get recorded + TestBufferForEvent(false, Counter(1, ToUnderlying(CounterQuality::RESTART)), t, t.buffer.counterEvents); + TestBufferForEvent(true, Counter(0, ToUnderlying(CounterQuality::RESTART)), t, t.buffer.counterEvents); +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var1.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var1.cpp new file mode 100644 index 0000000..8993e44 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var1.cpp @@ -0,0 +1,104 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include + +#include +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "Group120Var1TestSuite - " name + +TEST_CASE(SUITE("Parser rejects empty buffer")) +{ + HexSequence buffer(""); + + Group120Var1 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} + +TEST_CASE(SUITE("Parser correctly interprets challenge data")) +{ + // SEQ = 1, USER = 7, HMAC = 5 (SHA-1-8), REASON = 1, challenge = 0xDEADBEEF + HexSequence buffer("01 00 00 00 07 00 05 01 DE AD BE EF"); + + Group120Var1 output; + REQUIRE(output.Read(buffer.ToRSlice())); + REQUIRE(output.challengeSeqNum == 1); + REQUIRE(output.userNum == 7); + REQUIRE(output.hmacAlgo == HMACType::HMAC_SHA1_TRUNC_8); + REQUIRE(output.challengeReason == ChallengeReason::CRITICAL); + REQUIRE(ToHex(output.challengeData) == "DE AD BE EF"); +} + +TEST_CASE(SUITE("Parser accepts empty challenge data")) +{ + // SEQ = 1, USER = 7, HMAC = 5 (SHA-1-8), REASON = 1, challenge length of 3 + HexSequence buffer("01 00 00 00 07 00 05 01"); + + Group120Var1 output; + REQUIRE(output.Read(buffer.ToRSlice())); + REQUIRE(output.challengeData.Size() == 0); +} + +TEST_CASE(SUITE("Parser rejects one less than minimum required data")) +{ + // SEQ = 1, USER = 7, HMAC = 5 (SHA-1-8), REASON = ???? missing + HexSequence buffer("01 00 00 00 07 00 05"); + + Group120Var1 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} + +TEST_CASE(SUITE("Formatter correctly writes when sufficient space")) +{ + HexSequence challengeData("DE AD BE EF AB BA"); // 6 bytes + + Group120Var1 challenge(9, 3, HMACType::HMAC_SHA256_TRUNC_16, ChallengeReason::CRITICAL, challengeData.ToRSlice()); + const uint32_t SIZE = challenge.Size(); + + Buffer output(64); + auto dest = output.GetWSlice(); + REQUIRE(challenge.Write(dest)); + auto written = output.Size() - dest.Size(); + + REQUIRE(written == SIZE); + REQUIRE(ToHex(output.ToRSlice().Take(SIZE)) == "09 00 00 00 03 00 04 01 DE AD BE EF AB BA"); +} + +TEST_CASE(SUITE("Formatter return false when insufficient space")) +{ + HexSequence challengeData("DE AD BE EF AB BA"); // 6 bytes + + Group120Var1 challenge(9, 3, HMACType::HMAC_SHA256_TRUNC_16, ChallengeReason::CRITICAL, challengeData.ToRSlice()); + const uint32_t SIZE = challenge.Size(); + + Buffer output(SIZE - 1); + auto dest = output.GetWSlice(); + REQUIRE_FALSE(challenge.Write(dest)); +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var2.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var2.cpp new file mode 100644 index 0000000..794464a --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var2.cpp @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include + +#include +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "Group120Var2TestSuite - " name + +TEST_CASE(SUITE("Parser rejects empty buffer")) +{ + HexSequence buffer(""); + + Group120Var2 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} + +TEST_CASE(SUITE("Parser identifies data field")) +{ + HexSequence buffer("04 00 00 00 09 01 AB BA"); + + Group120Var2 output; + REQUIRE(output.Read(buffer.ToRSlice())); + REQUIRE(output.challengeSeqNum == 4); + REQUIRE(output.userNum == 265); + REQUIRE(ToHex(output.hmacValue) == "AB BA"); +} + +TEST_CASE(SUITE("Parser allows empty data field")) +{ + HexSequence buffer("04 00 00 00 09 01"); + + Group120Var2 output; + REQUIRE(output.Read(buffer.ToRSlice())); + REQUIRE(output.challengeSeqNum == 4); + REQUIRE(output.userNum == 265); + REQUIRE(output.hmacValue.IsEmpty()); +} + +TEST_CASE(SUITE("Parser rejects one less than min length")) +{ + HexSequence buffer("04 00 00 00 09"); + Group120Var2 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var5.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var5.cpp new file mode 100644 index 0000000..0fd59d3 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestGroup120Var5.cpp @@ -0,0 +1,125 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include + +#include +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "Group120Var5TestSuite - " name + +TEST_CASE(SUITE("Parser rejects empty buffer")) +{ + HexSequence buffer(""); + + Group120Var5 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} + +TEST_CASE(SUITE("Parser accepts empty challenge data and hmac")) +{ + // SEQ = 1, USER = 7, KeyWrap = 2 (AES256), KeyStatus = 1 (OK), MacAlgo = 4 (SHA-256 trunc 16), challenge len = 0 + HexSequence buffer("01 00 00 00 07 00 02 01 04 00 00"); + + Group120Var5 output; + REQUIRE(output.Read(buffer.ToRSlice())); + REQUIRE(output.keyChangeSeqNum == 1); + REQUIRE(output.userNum == 7); + REQUIRE(output.keyWrapAlgo == KeyWrapAlgorithm::AES_256); + REQUIRE(output.keyStatus == KeyStatus::OK); + REQUIRE(output.hmacAlgo == HMACType::HMAC_SHA256_TRUNC_16); + REQUIRE(output.challengeData.Size() == 0); + REQUIRE(output.hmacValue.Size() == 0); +} + +TEST_CASE(SUITE("Parser correctly interprets challenge data and hmac value")) +{ + // SEQ = 1, USER = 7, KeyWrap = 2 (AES256), KeyStatus = 1 (OK), MacAlgo = 4 (SHA-256 trunc 16), challenge len = 3 + HexSequence buffer("01 00 00 00 07 00 02 01 04 03 00 DE AD BE EF"); + + Group120Var5 output; + REQUIRE(output.Read(buffer.ToRSlice())); + REQUIRE(ToHex(output.challengeData) == "DE AD BE"); + REQUIRE(ToHex(output.hmacValue) == "EF"); +} + +TEST_CASE(SUITE("Parser rejects one less than minimum required data")) +{ + // SEQ = 1, USER = 7, KeyWrap = 2 (AES256), KeyStatus = 1 (OK), MacAlgo = 4 (SHA-256 trunc 16), challenge len = ??? missing + HexSequence buffer("01 00 00 00 07 00 02 01 04 00"); + + Group120Var5 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} + +TEST_CASE(SUITE("Parser rejects if specified challenge data is missing")) +{ + // SEQ = 1, USER = 7, KeyWrap = 2 (AES256), KeyStatus = 1 (OK), MacAlgo = 4 (SHA-256 trunc 16), challenge len = 1, missing data + HexSequence buffer("01 00 00 00 07 00 02 01 04 01 00"); + + Group120Var5 output; + REQUIRE_FALSE(output.Read(buffer.ToRSlice())); +} + +TEST_CASE(SUITE("Formatter correctly writes when sufficient space")) +{ + HexSequence challenge("DE AD"); + HexSequence hmac("BE EF"); + + Group120Var5 status(8, 3, KeyWrapAlgorithm::AES_256, KeyStatus::OK, HMACType::HMAC_SHA1_TRUNC_8, challenge, hmac); + const uint32_t SIZE = status.Size(); + + REQUIRE(SIZE == 15); + + Buffer output(SIZE); + + auto dest = output.GetWSlice(); + REQUIRE(status.Write(dest)); + uint32_t numWritten = output.Size() - dest.Size(); + + REQUIRE(numWritten == SIZE); + REQUIRE(ToHex(output.ToRSlice().Take(SIZE)) == "08 00 00 00 03 00 02 01 05 02 00 DE AD BE EF"); +} + +TEST_CASE(SUITE("Formatter rejects when one less than required space")) +{ + HexSequence challenge("DE AD BE EF"); + HexSequence hmac("AB BA"); + + Group120Var5 status(8, 3, KeyWrapAlgorithm::AES_256, KeyStatus::OK, HMACType::HMAC_SHA1_TRUNC_8, challenge, hmac); + const uint32_t SIZE = status.Size(); + + REQUIRE(SIZE == 17); + + Buffer output(SIZE - 1); + + auto dest = output.GetWSlice(); + REQUIRE_FALSE(status.Write(dest)); + REQUIRE(dest.Size() == output.Size()); +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestIndexSearch.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestIndexSearch.cpp new file mode 100644 index 0000000..2682007 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestIndexSearch.cpp @@ -0,0 +1,156 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include +#include + +using namespace openpal; +using namespace opendnp3; + +#define SUITE(name) "IndexSearch - " name + +IndexSearch::Result TestResultLengthFour(uint16_t index) +{ + Array, uint16_t> values(4); + values[0].config.vIndex = 1; + values[1].config.vIndex = 3; + values[2].config.vIndex = 7; + values[3].config.vIndex = 9; + + return IndexSearch::FindClosestRawIndex(values.ToView(), index); +} + +TEST_CASE(SUITE("FindsExactMatchForLastValue")) +{ + auto result = TestResultLengthFour(9); + REQUIRE(result.match); + REQUIRE(result.index == 3); +} + +TEST_CASE(SUITE("FindsExactMatchForFirstValue")) +{ + auto result = TestResultLengthFour(1); + REQUIRE(result.match); + REQUIRE(result.index == 0); +} + +TEST_CASE(SUITE("StopsOnFirstValueIfIndexLessThanFirst")) +{ + auto result = TestResultLengthFour(0); + REQUIRE(!result.match); + REQUIRE(result.index == 0); +} + +TEST_CASE(SUITE("StopsOnLastValueIfIndexGreaterThanLast")) +{ + auto result = TestResultLengthFour(11); + REQUIRE(!result.match); + REQUIRE(result.index == 3); +} + +TEST_CASE(SUITE("FindsNextSmallestIndex")) +{ + auto result = TestResultLengthFour(2); + REQUIRE(!result.match); + REQUIRE(result.index == 0); +} + +TEST_CASE(SUITE("FindsNextBiggestIndex")) +{ + auto result = TestResultLengthFour(8); + REQUIRE(!result.match); + REQUIRE(result.index == 3); +} + +Range TestRangeSearch(const Range& range) +{ + Array, uint16_t> values(4); + values[0].config.vIndex = 1; + values[1].config.vIndex = 3; + values[2].config.vIndex = 7; + values[3].config.vIndex = 9; + + return IndexSearch::FindRawRange(values.ToView(), range); +} + +TEST_CASE(SUITE("FindsFullRangeIfInputBracketsEntireRange")) +{ + auto range = TestRangeSearch(Range::From(0, 20)); + REQUIRE(range.start == 0); + REQUIRE(range.stop == 3); +} + +TEST_CASE(SUITE("FindsInvalidRangeIfBeneathRange")) +{ + auto range = TestRangeSearch(Range::From(0, 0)); + REQUIRE(!range.IsValid()); +} + +TEST_CASE(SUITE("FindsInvalidRangeIfAboveRange")) +{ + auto range = TestRangeSearch(Range::From(10, 10)); + REQUIRE(!range.IsValid()); +} + +TEST_CASE(SUITE("FindsInvalidRangeIfNoMatchInside")) +{ + auto range = TestRangeSearch(Range::From(4, 6)); + REQUIRE(!range.IsValid()); +} + +TEST_CASE(SUITE("FindsSingleValueExactMatch")) +{ + auto range = TestRangeSearch(Range::From(3, 3)); + REQUIRE(range.start == 1); + REQUIRE(range.stop == 1); +} + +TEST_CASE(SUITE("FindsSingleValuePartialMatch")) +{ + auto range = TestRangeSearch(Range::From(2, 6)); + REQUIRE(range.start == 1); + REQUIRE(range.stop == 1); +} + +TEST_CASE(SUITE("FindsSubRangeAtFront")) +{ + auto range = TestRangeSearch(Range::From(0, 8)); + REQUIRE(range.start == 0); + REQUIRE(range.stop == 2); +} + +TEST_CASE(SUITE("FindsSubRangeInMiddle")) +{ + auto range = TestRangeSearch(Range::From(3, 7)); + REQUIRE(range.start == 1); + REQUIRE(range.stop == 2); +} + +TEST_CASE(SUITE("FindsSubRangeAtEnd")) +{ + auto range = TestRangeSearch(Range::From(5, 11)); + REQUIRE(range.start == 2); + REQUIRE(range.stop == 3); +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkFrame.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkFrame.cpp new file mode 100644 index 0000000..22af7c2 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkFrame.cpp @@ -0,0 +1,179 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "mocks/DNPHelpers.h" + +using namespace testlib; +using namespace opendnp3; +using namespace openpal; + +std::string FormatUserData(bool aIsMaster, bool aIsConfirmed, int aDest, int aSrc, const std::string& data, bool aFcb = false) +{ + HexSequence hs(data); + REQUIRE(hs.Size() < 250); + + uint8_t buffer[292]; + WSlice wrapper(buffer, 292); + + if(aIsConfirmed) + { + return ToHex(LinkFrame::FormatConfirmedUserData(wrapper, aIsMaster, aFcb, aDest, aSrc, hs, hs.Size(), nullptr)); + } + else + { + return ToHex(LinkFrame::FormatUnconfirmedUserData(wrapper, aIsMaster, aDest, aSrc, hs, hs.Size(), nullptr)); + } +} + +#define SUITE(name) "DNPLinkFrame - " name + +TEST_CASE(SUITE("LinkHeaderChangeFCB")) +{ + LinkHeader hdr(5, 1, 1024, true, true, true, LinkFunction::PRI_CONFIRMED_USER_DATA); + + + REQUIRE(hdr.ControlByte(true, true, true, LinkFunction::PRI_CONFIRMED_USER_DATA) == hdr.GetControl()); + + hdr.ChangeFCB(false); + + REQUIRE(hdr.ControlByte(true, false, true, LinkFunction::PRI_CONFIRMED_USER_DATA) == hdr.GetControl()); +} + +TEST_CASE(SUITE("ResetLinks")) +{ + Buffer buffer(292); + + // ResetLinkStates - Master + auto write = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatResetLinkStates(write, true, 1, 1024, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 C0 01 00 00 04 E9 21"); +} + +TEST_CASE(SUITE("RequestLinkStates")) +{ + Buffer buffer(292); + + // ResetLinkStates - Master + auto write = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatRequestLinkStatus(write, false, 1, 1024, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 49 01 00 00 04 D2 36"); +} + +TEST_CASE(SUITE("ACK")) +{ + Buffer buffer(292); + + + { + // ACK - Outstation (DFC = false) + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatAck(writeTo, false, false, 1024, 1, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 00 00 04 01 00 19 A6"); //ACK - Outstation + } + + + { + // ACK - Outstation (DFC = true) + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatAck(writeTo, false, true, 1024, 1, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 10 00 04 01 00 8B 0C"); // ACK - Outstation (with DFC set) + } + + { + // ACK - Master (DFC = false) + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatAck(writeTo, true, false, 1, 1024, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 80 01 00 00 04 53 11"); + } + + { + // ACK - Master (DFC = true) + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatAck(writeTo, true, true, 1, 1024, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 90 01 00 00 04 C1 BB"); + } +} + +TEST_CASE(SUITE("ConfirmedUserData")) +{ + Buffer buffer(292); + + // Confirmed User Data - Master (FCB = true) + auto hex = FormatUserData(true, true, 1, 1024, "C0 C3 01 3C 02 06 3C 03 06 3C 04 06 3C 01 06", true); + REQUIRE(hex == "05 64 14 F3 01 00 00 04 0A 3B C0 C3 01 3C 02 06 3C 03 06 3C 04 06 3C 01 06 9A 12"); + + // Confirmed User Data - Outstation (FCB = true) + auto hex2 = FormatUserData(false, true, 1024, 1, "C1 E3 81 96 00 02 01 28 01 00 00 00 01 02 01 28 01 00 01 00 01 02 01 28 01 00 02 00 01 02 01 28 01 00 03 00 01 20 02 28 01 00 00 00 01 00 00 20 02 28 01 00 01 00 01 00 00 01 01 01 00 00 03 00 00 1E 02 01 00 00 01 00 01 00 00 01 00 00", true); + REQUIRE(hex2 == "05 64 53 73 00 04 01 00 03 FC C1 E3 81 96 00 02 01 28 01 00 00 00 01 02 01 28 05 24 01 00 01 00 01 02 01 28 01 00 02 00 01 02 01 28 B4 77 01 00 03 00 01 20 02 28 01 00 00 00 01 00 00 20 A5 25 02 28 01 00 01 00 01 00 00 01 01 01 00 00 03 00 2F AC 00 1E 02 01 00 00 01 00 01 00 00 01 00 00 16 ED"); +} + +TEST_CASE(SUITE("ResetLinkStates")) +{ + Buffer buffer(292); + + // Reset Link States - Outstation + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatResetLinkStates(writeTo, false, 1024, 1, nullptr); + REQUIRE(ToHex(wrapper) == "05 64 05 40 00 04 01 00 A3 96"); +} + +TEST_CASE(SUITE("UnconfirmedUserData")) +{ + auto hex = FormatUserData(false, false, 1024, 1, "C1 E3 81 96 00 02 01 28 01 00 00 00 01 02 01 28 01 00 01 00 01 02 01 28 01 00 02 00 01 02 01 28 01 00 03 00 01 20 02 28 01 00 00 00 01 00 00 20 02 28 01 00 01 00 01 00 00 01 01 01 00 00 03 00 00 1E 02 01 00 00 01 00 01 00 00 01 00 00"); + //take the packet from the test above, change the control byte to 44 , repair the crc + REQUIRE(hex == RepairCRC("05 64 53 44 00 04 01 00 FF FF C1 E3 81 96 00 02 01 28 01 00 00 00 01 02 01 28 FF FF 01 00 01 00 01 02 01 28 01 00 02 00 01 02 01 28 FF FF 01 00 03 00 01 20 02 28 01 00 00 00 01 00 00 20 FF FF 02 28 01 00 01 00 01 00 00 01 01 01 00 00 03 00 FF FF 00 1E 02 01 00 00 01 00 01 00 00 01 00 00 FF FF")); +} + +TEST_CASE(SUITE("LinkStatus")) +{ + Buffer buffer(292); + + // LinkStatus - Master (DFC = true) + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatLinkStatus(writeTo, true, true, 1, 1024, nullptr); + //take a length 10 frame, set the control to 9B and repair the CRC + REQUIRE(ToHex(wrapper) == RepairCRC("05 64 05 9B 01 00 00 04 E9 21")); +} + +TEST_CASE(SUITE("NotSupported")) +{ + Buffer buffer(292); + + // Not Supported - Outstation (DFC = true) + auto writeTo = buffer.GetWSlice(); + auto wrapper = LinkFrame::FormatNotSupported(writeTo, false, true, 1, 1024, nullptr); + REQUIRE(ToHex(wrapper) == RepairCRC("05 64 05 1F 01 00 00 04 28 5A")); +} + + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayer.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayer.cpp new file mode 100644 index 0000000..7438649 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayer.cpp @@ -0,0 +1,502 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include "mocks/BufferSegment.h" +#include "mocks/LinkLayerTest.h" +#include "mocks/LinkHex.h" + +#include + + +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "LinkLayerTestSuite - " name + +// All operations should fail except for OnLowerLayerUp, just a representative +// number of them +TEST_CASE(SUITE("ClosedState")) +{ + LinkLayerTest t; + BufferSegment segment(250, "00"); + REQUIRE_FALSE(t.upper->SendDown(segment)); + REQUIRE_FALSE(t.link.OnLowerLayerDown()); + REQUIRE_FALSE(t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 2)); +} + +// Prove that the upper layer is notified when the lower layer comes online +TEST_CASE(SUITE("ForwardsOnLowerLayerUp")) +{ + LinkLayerTest t; + + REQUIRE_FALSE(t.upper->IsOnline()); + REQUIRE(t.link.OnLowerLayerUp()); + REQUIRE(t.upper->IsOnline()); + REQUIRE_FALSE(t.link.OnLowerLayerUp()); +} + +// Check that once the layer comes up, validation errors can occur +TEST_CASE(SUITE("ValidatesMasterOutstationBit")) +{ + LinkLayerTest t; t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::SEC_ACK, true, false, false, 1, 1024); + REQUIRE(t.link.GetStatistics().numBadMasterBit == 1); +} + +// Only process frames from your designated remote address +TEST_CASE(SUITE("ValidatesSourceAddress")) +{ + LinkLayerTest t; t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1023); + REQUIRE(t.link.GetStatistics().numUnknownSource == 1); +} + +// This should actually never happen when using the LinkLayerRouter +// Only process frame addressed to you +TEST_CASE(SUITE("ValidatesDestinationAddress")) +{ + LinkLayerTest t; t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 2, 1024); + REQUIRE(t.link.GetStatistics().numUnknownDestination == 1); +} + +// Show that the base state of idle logs SecToPri frames as errors +TEST_CASE(SUITE("SecToPriNoContext")) +{ + LinkLayerTest t; t.link.OnLowerLayerUp(); + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + REQUIRE(t.link.GetStatistics().numUnexpectedFrame == 1); +} + +// Show that the base state of idle forwards unconfirmed user data +TEST_CASE(SUITE("UnconfirmedDataPassedUpFromIdleUnreset")) +{ + LinkLayerTest t; t.link.OnLowerLayerUp(); + ByteStr bs(250, 0); + t.OnFrame(LinkFunction::PRI_UNCONFIRMED_USER_DATA, false, false, false, 1, 1024, bs.ToRSlice()); + REQUIRE(t.upper->receivedQueue.front() == bs.ToHex()); +} + +// Show that the base state of idle forwards unconfirmed user data +TEST_CASE(SUITE("ConfirmedDataIgnoredFromIdleUnreset")) +{ + LinkLayerTest t; t.link.OnLowerLayerUp(); + ByteStr bs(250, 0); + t.OnFrame(LinkFunction::PRI_CONFIRMED_USER_DATA, false, false, false, 1, 1024, bs.ToRSlice()); + REQUIRE(t.upper->receivedQueue.empty()); + REQUIRE(t.link.GetStatistics().numUnexpectedFrame == 1); +} + +// Secondary Reset Links +TEST_CASE(SUITE("SecondaryResetLink")) +{ + LinkLayerTest t(LinkLayerTest::DefaultConfig()); + t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + + REQUIRE(t.NumTotalWrites() == 1); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::Ack(true, false, 1024, 1)); +} + +TEST_CASE(SUITE("SecAckWrongFCB")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); + t.link.OnLowerLayerUp(); + + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + ByteStr b(250, 0); + t.OnFrame(LinkFunction::PRI_CONFIRMED_USER_DATA, false, false, false, 1, 1024, b.ToRSlice()); + t.link.OnTransmitResult(true); + REQUIRE(t.NumTotalWrites() == 2); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::Ack(true, false, 1024, 1)); + REQUIRE(t.upper->receivedQueue.empty()); //data should not be passed up! +} + +// When we get another reset links when we're already reset, +// ACK it and reset the link state +TEST_CASE(SUITE("SecondaryResetResetLinkStates")) +{ + LinkLayerTest t; + t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 2); + t.link.OnTransmitResult(true); + + REQUIRE(t.NumTotalWrites() == 2); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::Ack(true, false, 1024, 1)); +} + +TEST_CASE(SUITE("SecondaryResetConfirmedUserData")) +{ + LinkLayerTest t; + t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + ByteStr bytes(250, 0); + t.OnFrame(LinkFunction::PRI_CONFIRMED_USER_DATA, false, true, false, 1, 1024, bytes.ToRSlice()); + REQUIRE(t.NumTotalWrites() == 2); + t.link.OnTransmitResult(true); + + REQUIRE(t.upper->receivedQueue.front() == bytes.ToHex()); + t.upper->receivedQueue.clear(); + + t.OnFrame(LinkFunction::PRI_CONFIRMED_USER_DATA, false, true, false, 1, 1024, bytes.ToRSlice()); //send with wrong FCB + REQUIRE(t.NumTotalWrites() == 3); //should still get an ACK + REQUIRE(t.upper->receivedQueue.empty()); //but no data +} + +TEST_CASE(SUITE("RequestStatusOfLink")) +{ + LinkLayerTest t; + t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::PRI_REQUEST_LINK_STATUS, false, false, false, 1, 1024); //should be able to request this before the link is reset + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::LinkStatus(true, false, 1024, 1)); + + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 2); + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::PRI_REQUEST_LINK_STATUS, false, false, false, 1, 1024); //should be able to request this before the link is reset + REQUIRE(t.NumTotalWrites() == 3); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::LinkStatus(true, false, 1024, 1)); +} + +TEST_CASE(SUITE("TestLinkStates")) +{ + LinkLayerTest t; + t.link.OnLowerLayerUp(); + t.OnFrame(LinkFunction::PRI_TEST_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 0); + + t.OnFrame(LinkFunction::PRI_RESET_LINK_STATES, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::PRI_TEST_LINK_STATES, false, true, false, 1, 1024); + + REQUIRE(t.NumTotalWrites() == 2); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::Ack(true, false, 1024, 1)); +} + +TEST_CASE(SUITE("SendUnconfirmed")) +{ + LinkLayerTest t; + t.link.OnLowerLayerUp(); + + BufferSegment segment(250, IncrementHex(0, 250)); + t.link.Send(segment); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.upper->GetState().successCnt == 1); + REQUIRE(t.NumTotalWrites() == 1); +} + + +TEST_CASE(SUITE("CloseBehavior")) +{ + LinkLayerTest t; + t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + t.link.OnTransmitResult(true); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.upper->CountersEqual(1, 0)); + t.link.OnLowerLayerDown(); //take it down during the middle of a send + REQUIRE_FALSE(t.upper->IsOnline()); + + + t.link.OnLowerLayerUp(); + REQUIRE(t.upper->IsOnline()); + segments.Reset(); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 2); + +} + +TEST_CASE(SUITE("ResetLinkTimerExpiration")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); + t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); // reset link + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ResetLinkStates(true, 1024, 1)); + REQUIRE(t.upper->CountersEqual(0, 0)); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.upper->CountersEqual(0, 1)); +} + +TEST_CASE(SUITE("ResetLinkTimerExpirationWithRetry")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.NumRetry = 1; + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); + t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); // timeout the wait for Ack + + REQUIRE(t.upper->CountersEqual(0, 0)); //check that the send is still occuring + REQUIRE(t.NumTotalWrites() == 2); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ResetLinkStates(true, 1024, 1)); // check that reset links got sent again + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); // this time Ack it + REQUIRE(t.NumTotalWrites() == 3); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ConfirmedUserData(true, true, 1024, 1, IncrementHex(0x00, 250))); // check that the data got sent + + t.link.OnTransmitResult(true); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); //timeout the ACK + REQUIRE(t.upper->CountersEqual(0, 1)); + + // Test retry reset + segments.Reset(); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 4); + t.link.OnTransmitResult(true); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.upper->CountersEqual(0, 1)); //check that the send is still occuring +} + +TEST_CASE(SUITE("ResetLinkTimerExpirationWithRetryResetState")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.NumRetry = 1; + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); + t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 2); + t.link.OnTransmitResult(true); + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.upper->CountersEqual(1, 0)); + + segments.Reset(); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 3); + t.link.OnTransmitResult(true); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunOne()); // timeout + REQUIRE(t.upper->CountersEqual(1, 0)); //check that the send is still occuring + REQUIRE(t.NumTotalWrites() == 4); + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.upper->CountersEqual(2, 0)); + + // Test retry reset + segments.Reset(); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 5); // Should now be waiting for an ACK with active timer + t.link.OnTransmitResult(true); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunOne()); + REQUIRE(t.upper->CountersEqual(2, 0)); //check that the send is still occuring +} + + +TEST_CASE(SUITE("ConfirmedDataRetry")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.NumRetry = 1; + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + t.link.OnTransmitResult(true); + REQUIRE(t.NumTotalWrites() == 1); // Should now be waiting for an ACK with active timer + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + REQUIRE(t.NumTotalWrites() == 2); + t.link.OnTransmitResult(true); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); //timeout the ConfData, check that it retransmits + REQUIRE(t.NumTotalWrites() == 3); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ConfirmedUserData(true, true, 1024, 1, IncrementHex(0x00, 250))); + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.NumTotalWrites() == 3); + REQUIRE(t.upper->CountersEqual(1, 0)); +} + +TEST_CASE(SUITE("ResetLinkRetries")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.NumRetry = 3; + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + + for(int i = 1; i < 5; ++i) + { + REQUIRE(t.NumTotalWrites() == i); // sends link retry + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ResetLinkStates(true, 1024, 1)); + t.link.OnTransmitResult(true); + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); //timeout + } + + REQUIRE(t.NumTotalWrites() == 4); +} + +TEST_CASE(SUITE("ConfirmedDataNackDFCClear")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.NumRetry = 1; + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + t.link.OnTransmitResult(true); + REQUIRE(t.NumTotalWrites() == 1); // Should now be waiting for an ACK with active timer + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + t.link.OnTransmitResult(true); + REQUIRE(t.NumTotalWrites() == 2); // num transmitting confirmed data + + t.OnFrame(LinkFunction::SEC_NACK, false, false, false, 1, 1024); // test that we try to reset the link again + t.link.OnTransmitResult(true); + REQUIRE(t.NumTotalWrites() == 3); + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); // ACK the link reset + REQUIRE(t.NumTotalWrites() == 4); +} + +TEST_CASE(SUITE("SendDataTimerExpiration")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); + t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + REQUIRE(t.NumTotalWrites() == 1); + t.link.OnTransmitResult(true); + + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); // ACK the reset links + REQUIRE(t.NumTotalWrites() == 2); + + REQUIRE(t.NumTotalWrites() == 2); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ConfirmedUserData(true, true, 1024, 1, IncrementHex(0x00, 250))); // check that data was sent + t.link.OnTransmitResult(true); + + t.exe->AdvanceTime(cfg.Timeout); + REQUIRE(t.exe->RunMany() > 0); //trigger the timeout callback + REQUIRE(t.upper->CountersEqual(0, 1)); +} + + +TEST_CASE(SUITE("SendDataSuccess")) +{ + LinkConfig cfg = LinkLayerTest::DefaultConfig(); + cfg.UseConfirms = true; + + LinkLayerTest t(cfg); + t.link.OnLowerLayerUp(); + + BufferSegment segments(250, IncrementHex(0, 250)); + t.link.Send(segments); + t.link.OnTransmitResult(true); + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + t.link.OnTransmitResult(true); + t.OnFrame(LinkFunction::SEC_ACK, false, false, false, 1, 1024); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.upper->CountersEqual(1, 0)); + + segments.Reset(); + t.link.Send(segments); // now we should be directly sending w/o having to reset, and the FCB should flip + + REQUIRE(t.NumTotalWrites() == 3); + REQUIRE(t.PopLastWriteAsHex() == LinkHex::ConfirmedUserData(true, false, 1024, 1, IncrementHex(0x00, 250))); +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayerKeepAlive.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayerKeepAlive.cpp new file mode 100644 index 0000000..2eff9a7 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkLayerKeepAlive.cpp @@ -0,0 +1,167 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include +#include + +#include "mocks/BufferSegment.h" +#include "mocks/LinkLayerTest.h" +#include "mocks/LinkHex.h" + +#include + +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "LinkLayerKeepAliveTestSuite - " name + +TEST_CASE(SUITE("Timers activated and canceled in response to layer up/down")) +{ + LinkLayerTest t; + REQUIRE(t.exe->NumPendingTimers() == 0); + t.link.OnLowerLayerUp(); + REQUIRE(t.exe->NumPendingTimers() == 1); + t.link.OnLowerLayerDown(); + REQUIRE(t.exe->NumPendingTimers() == 0); +} + +TEST_CASE(SUITE("ForwardsKeepAliveTimeouts")) +{ + LinkConfig config(true, false); + config.KeepAliveTimeout = TimeDuration::Seconds(5); + LinkLayerTest t(config); + + t.link.OnLowerLayerUp(); + + REQUIRE(t.exe->NumPendingTimers() == 1); + REQUIRE(t.listener->numKeepAliveTransmissions == 0); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.listener->numKeepAliveTransmissions == 1); +} + +TEST_CASE(SUITE("KeepAliveFailureCallbackIsInvokedOnTimeout")) +{ + LinkConfig config(true, false); + config.KeepAliveTimeout = TimeDuration::Seconds(5); + LinkLayerTest t(config); + + t.link.OnLowerLayerUp(); + + REQUIRE(t.exe->NumPendingTimers() == 1); + REQUIRE(t.listener->numKeepAliveTransmissions == 0); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::RequestLinkStatus(true, 1024, 1)); + REQUIRE(t.exe->NumPendingTimers() == 1); + t.link.OnTransmitResult(true); + REQUIRE(t.exe->NumPendingTimers() == 2); + t.exe->AdvanceTime(config.Timeout); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.listener->numKeepAliveFailure == 1); +} + +TEST_CASE(SUITE("KeepAliveSuccessCallbackIsInvokedWhenLinkStatusReceived")) +{ + LinkConfig config(true, false); + config.KeepAliveTimeout = TimeDuration::Seconds(5); + LinkLayerTest t(config); + + t.link.OnLowerLayerUp(); + + REQUIRE(t.exe->NumPendingTimers() == 1); + REQUIRE(t.listener->numKeepAliveTransmissions == 0); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::RequestLinkStatus(true, 1024, 1)); + REQUIRE(t.exe->NumPendingTimers() == 1); + t.link.OnTransmitResult(true); + REQUIRE(t.exe->NumPendingTimers() == 2); + t.OnFrame(LinkFunction::SEC_LINK_STATUS, false, false, false, 1, 1024); + REQUIRE(t.listener->numKeepAliveReplys == 1); + REQUIRE(t.exe->NumPendingTimers() == 1); +} + +TEST_CASE(SUITE("KeepAliveIsPeriodicOnFailure")) +{ + LinkConfig config(true, false); + config.KeepAliveTimeout = TimeDuration::Seconds(5); + LinkLayerTest t(config); + + t.link.OnLowerLayerUp(); + + for (int count = 0; count < 3; ++count) + { + REQUIRE(t.exe->NumPendingTimers() == 1); + REQUIRE(t.listener->numKeepAliveTransmissions == count); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::RequestLinkStatus(true, 1024, 1)); + REQUIRE(t.exe->NumPendingTimers() == 1); + t.link.OnTransmitResult(true); + REQUIRE(t.exe->NumPendingTimers() == 2); + + t.exe->AdvanceTime(config.Timeout); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.listener->numKeepAliveFailure == (count + 1)); + } +} + +TEST_CASE(SUITE("KeepAliveIsPeriodicOnSuccess")) +{ + LinkConfig config(true, false); + config.KeepAliveTimeout = TimeDuration::Seconds(5); + LinkLayerTest t(config); + + t.link.OnLowerLayerUp(); + + for (int count = 0; count < 3; ++count) + { + REQUIRE(t.exe->NumPendingTimers() == 1); + REQUIRE(t.listener->numKeepAliveTransmissions == count); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.PopLastWriteAsHex() == LinkHex::RequestLinkStatus(true, 1024, 1)); + REQUIRE(t.exe->NumPendingTimers() == 1); + t.link.OnTransmitResult(true); + REQUIRE(t.exe->NumPendingTimers() == 2); + t.OnFrame(LinkFunction::SEC_LINK_STATUS, false, false, false, 1, 1024); + REQUIRE(t.listener->numKeepAliveReplys == (count + 1)); + } +} + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkReceiver.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkReceiver.cpp new file mode 100644 index 0000000..d480d60 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkReceiver.cpp @@ -0,0 +1,310 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/LinkReceiverTest.h" +#include "mocks/DNPHelpers.h" + +#include + +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + + +#define SUITE(name) "LinkParserTestSuite - " name + +TEST_CASE(SUITE("InitializationState")) +{ + LinkParserTest t; + REQUIRE(t.sink.m_num_frames == 0); +} + +////////////////////////////////////////// +// CRC Failures +////////////////////////////////////////// + +TEST_CASE(SUITE("HeaderCRCError")) +{ + LinkParserTest t; + t.WriteData("05 64 05 C0 01 00 00 04 E9 20"); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numHeaderCrcError == 1); +} + +TEST_CASE(SUITE("BodyCRCError")) +{ + LinkParserTest t; + t.WriteData("05 64 14 F3 01 00 00 04 0A 3B C0 C3 01 3C 02 06 3C 03 06 3C 04 06 3C 01 06 9A 11"); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBodyCrcError == 1); +} + +////////////////////////////////////////// +// Illegal packets of one form or another +////////////////////////////////////////// + +// Change the length to something from 5 to something in [0,4] and recalc the crc +// A valid reset link states packet would be: 05 64 05 C0 01 00 00 04 E9 21 +TEST_CASE(SUITE("BadLengthError")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 01 C0 01 00 00 04 E9 21")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadLength == 1); +} + +//Test that the presence of user data disagrees with the function code +TEST_CASE(SUITE("UnexpectedData")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 08 C0 01 00 00 04 E9 21")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadLength == 1); +} + +// Test that the absence of user data disagrees with the function code +// This is the first 10 bytes of an unconfirmed user data packet w/ the length set to 5 +TEST_CASE(SUITE("AbsenceOfData")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 05 73 00 04 01 00 03 FC")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadLength == 1); +} + +// Test that the parser can handle an unknown PriToSec function code +// Reset Links w/ function code changed from 0 to 6 +TEST_CASE(SUITE("UnknownFunction")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 05 C6 01 00 00 04 E9 21")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadFunctionCode == 1); +} + +// Test that the parser can handle an unexpected FCV bit +// Reset Links w/ FCV toggled on +TEST_CASE(SUITE("UnexpectedFCV")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 05 D0 01 00 00 04 E9 21")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadFCV == 1); +} + +// Test that the parser can handle an unexpected FCB bit for SecToPri +// ACK w/ FCB toggled on +TEST_CASE(SUITE("UnexpectedFCB")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 05 20 00 04 01 00 19 A6")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadFCB == 1); +} + +// Write two bad packets back-to-back tests that this produces +// back to back errors with a single write call +TEST_CASE(SUITE("CombinedFailures")) +{ + LinkParserTest t; + t.WriteData(RepairCRC("05 64 05 20 00 04 01 00 19 A6") + + " " + RepairCRC("05 64 05 D0 01 00 00 04 E9 21")); + REQUIRE(t.sink.m_num_frames == 0); + REQUIRE(t.parser.Statistics().numBadFCV == 1); + REQUIRE(t.parser.Statistics().numBadFCB == 1); +} + +////////////////////////////////////////// +// Successful packets - Sec to Pri +////////////////////////////////////////// + +TEST_CASE(SUITE("ReadACK")) +{ + Buffer buffer(292); + + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatAck(writeTo, true, false, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLastWithDFC(LinkFunction::SEC_ACK, true, false, 1, 2)); +} + +TEST_CASE(SUITE("ReadNACK")) +{ + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatNack(writeTo, false, true, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLastWithDFC(LinkFunction::SEC_NACK, false, true, 1, 2)); +} + +TEST_CASE(SUITE("LinkStatus")) +{ + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatLinkStatus(writeTo, true, true, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLastWithDFC(LinkFunction::SEC_LINK_STATUS, true, true, 1, 2)); +} + +TEST_CASE(SUITE("NotSupported")) +{ + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatNotSupported(writeTo, true, false, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLastWithDFC(LinkFunction::SEC_NOT_SUPPORTED, true, false, 1, 2)); +} + +////////////////////////////////////////// +// Successful packets - Pri To Sec +////////////////////////////////////////// + +TEST_CASE(SUITE("TestLinkStates")) +{ + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatTestLinkStatus(writeTo, false, true, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLastWithFCB(LinkFunction::PRI_TEST_LINK_STATES, false, true, 1, 2)); +} + +TEST_CASE(SUITE("ResetLinkStates")) +{ + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatResetLinkStates(writeTo, false, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLast(LinkFunction::PRI_RESET_LINK_STATES, false, 1, 2)); +} + +TEST_CASE(SUITE("RequestLinkStatus")) +{ + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatRequestLinkStatus(writeTo, true, 1, 2, nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLast(LinkFunction::PRI_REQUEST_LINK_STATUS, true, 1, 2)); +} + +TEST_CASE(SUITE("UnconfirmedUserData")) +{ + ByteStr data(250, 0); //initializes a buffer with increasing value + + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatUnconfirmedUserData(writeTo, true, 1, 2, data, data.Size(), nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLast(LinkFunction::PRI_UNCONFIRMED_USER_DATA, true, 1, 2)); + REQUIRE(t.sink.BufferEquals(data, data.Size())); +} + +TEST_CASE(SUITE("ConfirmedUserData")) +{ + ByteStr data(250, 0); //initializes a buffer with increasing value + + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatConfirmedUserData(writeTo, true, true, 1, 2, data, data.Size(), nullptr); + + LinkParserTest t; + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLastWithFCB(LinkFunction::PRI_CONFIRMED_USER_DATA, true, true, 1, 2)); + REQUIRE(t.sink.BufferEquals(data, data.Size())); +} + +////////////////////////////////////////// +// multi packets +////////////////////////////////////////// + +TEST_CASE(SUITE("TestTwoPackets")) +{ + LinkParserTest t; + // back to back reset link + t.WriteData("05 64 05 C0 01 00 00 04 E9 21 05 64 05 C0 01 00 00 04 E9 21"); + REQUIRE(t.sink.m_num_frames == 2); + REQUIRE(t.sink.CheckLast(LinkFunction::PRI_RESET_LINK_STATES, true, 1, 1024)); +} + +////////////////////////////////////////// +// framing errors +////////////////////////////////////////// + +// Test that the parser is able to resync without discarding +TEST_CASE(SUITE("Resync0564")) +{ + LinkParserTest t; + t.WriteData("05 64 05 64 05 C0 01 00 00 04 E9 21"); + REQUIRE(t.parser.Statistics().numHeaderCrcError == 1); + REQUIRE(t.sink.m_num_frames == 1); + REQUIRE(t.sink.CheckLast(LinkFunction::PRI_RESET_LINK_STATES, true, 1, 1024)); +} + +////////////////////////////////////////// +// many packets +////////////////////////////////////////// + +// Test that the parser is able to handle many packets successively without +// doing something stupid like overflowing it's buffer +TEST_CASE(SUITE("ManyReceives")) +{ + + Buffer buffer(292); + auto writeTo = buffer.GetWSlice(); + auto frame = LinkFrame::FormatAck(writeTo, true, false, 1, 2, nullptr); + + LinkParserTest t; + + for(size_t i = 1; i < 100; ++i) + { + t.WriteData(frame); + REQUIRE(t.sink.m_num_frames == i); + REQUIRE(t.sink.CheckLastWithDFC(LinkFunction::SEC_ACK, true, false, 1, 2)); + } +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkRoute.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkRoute.cpp new file mode 100644 index 0000000..e677868 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLinkRoute.cpp @@ -0,0 +1,40 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +using namespace std; +using namespace opendnp3; + +#define SUITE(name) "LinkRouteSuite - " name + +TEST_CASE(SUITE("LinkRouteEqualityComparison")) +{ + Route lr1(1, 2); + Route lr2(1, 3); + Route lr3(1, 3); + + REQUIRE(!(lr1.Equals(lr2))); + REQUIRE(lr3.Equals(lr2)); + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestLog.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLog.cpp new file mode 100644 index 0000000..a82537c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestLog.cpp @@ -0,0 +1,51 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include + +#include + +#include +#include + +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "LogTest - " name + +TEST_CASE(SUITE("FORMAT_SAFE macro truncates and null terminates")) +{ + char buffer[10]; + auto text1 = "hello"; + auto text2 = "my little friend"; + + SAFE_STRING_FORMAT(buffer, 10, "%s %s", text1, text2); + + std::string result(buffer); + + REQUIRE(result.size() == 9); + + REQUIRE(result == "hello my "); +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMaster.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMaster.cpp new file mode 100644 index 0000000..f4a828c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMaster.cpp @@ -0,0 +1,639 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MasterTestObject.h" +#include "mocks/MeasurementComparisons.h" + +#include +#include +#include +#include + +#include +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "MasterTestSuite - " name + +TEST_CASE(SUITE("notifies application of state changes")) +{ + MasterParams params; + params.disableUnsolOnStartup = false; + MasterTestObject t(params); + + REQUIRE(t.application->stateChanges.empty()); + t.context->OnLowerLayerUp(); + + REQUIRE(t.application->stateChanges.size() == 1); + REQUIRE(t.application->stateChanges.front() == MockMasterApplication::State::OPEN); + t.application->stateChanges.pop_front(); + + t.context->OnLowerLayerDown(); + + REQUIRE(t.application->stateChanges.size() == 1); + REQUIRE(t.application->stateChanges.front() == MockMasterApplication::State::CLOSED); + t.application->stateChanges.pop_front(); +} + +TEST_CASE(SUITE("IntegrityOnStartup")) +{ + MasterParams params; + params.disableUnsolOnStartup = false; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); +} + +TEST_CASE(SUITE("SolicitedResponseWithData")) +{ + MasterParams params; + params.disableUnsolOnStartup = false; + params.unsolClassMask = 0; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + REQUIRE(t.exe->NumPendingTimers() == 2); + t.SendToMaster("C0 81 00 00 01 02 00 02 02 81"); //group 2 var 1, index = 2, 0x81 = Online, true + REQUIRE(t.meas->TotalReceived() == 1); + REQUIRE((Binary(true, 0x01) == t.meas->binarySOE[2].meas)); +} + +TEST_CASE(SUITE("UnsolDisableEnableOnStartup")) +{ + MasterParams params; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + // disable unsol on grp 60 var2, var3, var4 + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(0)); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(1)); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(1)); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::ENABLE_UNSOLICITED, 2, ClassField::AllEventClasses())); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(2)); + + t.exe->RunMany(); + + REQUIRE(t.exe->NumPendingTimers() == 1); +} + +TEST_CASE(SUITE("TimeoutDuringStartup")) +{ + MasterParams params; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + t.context->OnSendResult(true); + + // timeout the task + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany()); + + REQUIRE(t.lower->NumWrites() == 0); + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany()); + + // repeat the disable unsol + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 1, ClassField::AllEventClasses())); +} + +TEST_CASE(SUITE("SolicitedResponseTimeout")) +{ + MasterTestObject t(NoStartupTasks()); + auto scan = t.context->AddClassScan(ClassField::AllClasses(), TimeDuration::Seconds(5)); + t.context->OnLowerLayerUp(); + + t.exe->RunMany(); + REQUIRE(t.exe->AdvanceToNextTimer()); + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.exe->NumPendingTimers() == 2); + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(1)); +} + +TEST_CASE(SUITE("AllObjectsScan")) +{ + MasterTestObject t(NoStartupTasks()); + auto scan = t.context->AddAllObjectsScan(GroupVariationID(110, 0), TimeDuration::Seconds(1)); + t.context->OnLowerLayerUp(); + + t.exe->RunMany(); + REQUIRE(t.exe->AdvanceToNextTimer()); + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 01 6E 00 06"); +} + +TEST_CASE(SUITE("ClassScanCanRepeat")) +{ + MasterParams params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.exe->RunMany(); + + auto scan = t.context->AddClassScan(~0, TimeDuration::Seconds(10)); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(0)); + + t.exe->RunMany(); + + // 2nd poll + REQUIRE(t.exe->NumPendingTimers() == 2); + REQUIRE(t.exe->NextTimerExpiration().milliseconds == 10000); + t.exe->AdvanceTime(TimeDuration::Seconds(10)); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(1)); +} + +TEST_CASE(SUITE("SolicitedResponseLayerDown")) +{ + MasterTestObject t(NoStartupTasks()); + auto scan = t.context->AddClassScan(ClassField::AllClasses(), TimeDuration::Seconds(5)); + t.context->OnLowerLayerUp(); + + t.exe->RunMany(); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnLowerLayerDown(); + + t.context->OnLowerLayerUp(); + t.exe->RunMany(); + + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); +} + +TEST_CASE(SUITE("SolicitedMultiFragResponse")) +{ + auto config = NoStartupTasks(); + config.startupIntegrityClassMask = ClassField::AllClasses(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + t.SendToMaster("80 81 00 00 01 02 00 02 02 81"); // partial response FIR = 1, FIN = 0 + REQUIRE(1 == t.meas->TotalReceived()); + REQUIRE((Binary(true, 0x01) == t.meas->binarySOE[2].meas)); + REQUIRE(0 == t.lower->NumWrites()); + t.SendToMaster("41 81 00 00 01 02 00 03 03 02"); // final response FIR = 0, FIN = 1 + REQUIRE(2 == t.meas->TotalReceived()); + REQUIRE((Binary(false, 0x02) == t.meas->binarySOE[3].meas)); +} + +TEST_CASE(SUITE("EventPoll")) +{ + MasterTestObject t(NoStartupTasks()); + + auto class12 = t.context->AddClassScan(ClassField(ClassField::CLASS_1 | ClassField::CLASS_2), TimeDuration::Milliseconds(10)); + auto class3 = t.context->AddClassScan(ClassField(ClassField::CLASS_3), TimeDuration::Milliseconds(20)); + + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 01 3C 02 06 3C 03 06"); + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00 02 01 17 01 02 81"); //group 2 var 1, index = 2, 0x81 = Online, true + + REQUIRE(t.meas->TotalReceived() == 1); + REQUIRE((Binary(true, 0x01) == t.meas->binarySOE[2].meas)); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == "C1 01 3C 04 06"); + t.context->OnSendResult(true); + t.SendToMaster("C1 81 00 00 02 01 17 01 03 01"); //group 2 var 1, index = 3, 0x81 = Online, true + + REQUIRE(t.meas->TotalReceived() == 2); + REQUIRE((Binary(false, 0x01) == t.meas->binarySOE[3].meas)); +} + +TEST_CASE(SUITE("ParsesOctetStringResponseWithFiveCharacters")) +{ + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + // Group 111 (0x6F) Variation (length), 1 byte count / 1 byte index (4), count of 1, "hello" == [0x68, 0x65, 0x6C, 0x6C, 0x6F] + t.SendToMaster("D0 82 00 00 6F 05 17 01 04 68 65 6C 6C 6F"); + + REQUIRE("68 65 6C 6C 6F" == ToHex(t.meas->octetStringSOE[4].meas.ToRSlice())); +} + +TEST_CASE(SUITE("ParsesOctetStringResponseSizeOfOne")) +{ + MasterTestObject t(NoStartupTasks()); + t.context->AddClassScan(~0, TimeDuration::Seconds(1)); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + + // octet strings shouldn't be found in class 0 polls, but we'll test that we can process them anyway + // Group 110 (0x6E) Variation(length), start = 3, stop = 3 + t.SendToMaster("C0 81 00 00 6E 01 00 03 03 AA"); + + REQUIRE("AA" == ToHex(t.meas->octetStringSOE[3].meas.ToRSlice())); +} + +TEST_CASE(SUITE("ParsesGroup2Var3Correctly")) +{ + auto config = NoStartupTasks(); + config.startupIntegrityClassMask = ClassField(~0); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + + // g51v1, t = 3, + // g2v3, index 7, t = 2, true/online + // g2v3, index 8, t = 3, true/online + t.SendToMaster("C0 81 00 00 33 01 07 01 03 00 00 00 00 00 02 03 17 01 07 81 02 00 02 03 17 01 08 81 03 00"); + + REQUIRE(t.meas->binarySOE.size() == 2); + { + auto record = t.meas->binarySOE[7]; + REQUIRE(record.meas.time == 5); + REQUIRE(record.info.gv == GroupVariation::Group2Var3); + } + { + auto record = t.meas->binarySOE[8]; + REQUIRE(record.meas.time == 6); + REQUIRE(record.info.gv == GroupVariation::Group2Var3); + } +} + +TEST_CASE(SUITE("ParsesGroup50Var4")) +{ + auto config = NoStartupTasks(); + config.startupIntegrityClassMask = ClassField(~0); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + + t.SendToMaster("C0 81 00 00 32 04 00 00 00 09 00 00 00 00 00 03 00 00 00 05"); + + REQUIRE(1 == t.meas->timeAndIntervalSOE.size()); + REQUIRE(t.meas->timeAndIntervalSOE[0].meas.interval == 3); + REQUIRE(t.meas->timeAndIntervalSOE[0].meas.time == 9); + REQUIRE(t.meas->timeAndIntervalSOE[0].meas.GetUnitsEnum() == IntervalUnits::Days); +} + +TEST_CASE(SUITE("RestartViaNullUnsol")) +{ + MasterParams params; + + // disable all the automated behaviors except for restart IIN + params.disableUnsolOnStartup = false; + params.startupIntegrityClassMask = ClassField::None(); + params.unsolClassMask = ClassField::None(); + params.startupIntegrityClassMask = ClassField::None(); //disable integrity poll + + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->NumWrites() == 0); + t.SendToMaster("F0 82 80 00"); + REQUIRE(t.lower->PopWriteAsHex() == hex::Confirm(0, true)); + t.context->OnSendResult(true); + REQUIRE(t.lower->PopWriteAsHex() == "C0 02 50 01 00 07 07 00"); +} + +TEST_CASE(SUITE("DisableAutomatedRestartClear")) +{ + MasterParams params; + + // disable all the automated behaviors + params.ignoreRestartIIN = true; + params.disableUnsolOnStartup = false; + params.startupIntegrityClassMask = ClassField::None(); + params.unsolClassMask = ClassField::None(); + params.startupIntegrityClassMask = ClassField::None(); //disable integrity poll + + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->NumWrites() == 0); + t.SendToMaster("F0 82 80 00"); + REQUIRE(t.lower->PopWriteAsHex() == hex::Confirm(0, true)); + t.context->OnSendResult(true); + REQUIRE(t.lower->NumWrites() == 0); +} + +TEST_CASE(SUITE("RestartDuringStartup")) +{ + + MasterParams params; + params.startupIntegrityClassMask = 0; //disable integrity poll + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + t.context->OnSendResult(false); + + t.SendToMaster(hex::EmptyResponse(0, IINField(IINBit::DEVICE_RESTART))); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClearRestartIIN(1)); + t.context->OnSendResult(false); + t.SendToMaster(hex::EmptyResponse(1)); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::ENABLE_UNSOLICITED, 2, ClassField::AllEventClasses())); +} + +TEST_CASE(SUITE("RestartAndTimeBits")) +{ + auto params = NoStartupTasks(); + params.timeSyncMode = TimeSyncMode::SerialTimeSync; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.application->time = 100; + t.exe->RunMany(); + + REQUIRE(t.lower->NumWrites() == 0); + + t.SendToMaster(hex::NullUnsolicited(0, IINField(IINBit::DEVICE_RESTART) | IINField(IINBit::NEED_TIME))); + + REQUIRE(t.lower->PopWriteAsHex() == hex::UnsolConfirm(0)); + t.context->OnSendResult(true); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClearRestartIIN(0)); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(0, IINField::Empty())); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::MeasureDelay(1)); + t.context->OnSendResult(true); + t.application->time += 100; //advance time by 100ms so that the master sees 100ms for a response + t.SendToMaster("C1 81 10 00 34 02 07 01 0A 00"); // still need time, 52 Var 2, delay == 10ms + + t.exe->RunMany(); + + // Write group 50 var 1 + // 200-100-10/2 = 45 => 45 + 200 - 0xF5 + REQUIRE(t.lower->PopWriteAsHex() == "C2 02 32 01 07 01 F5 00 00 00 00 00"); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(0, IINField::Empty())); // time bit is now clear + + t.exe->RunMany(); + + REQUIRE(t.lower->NumWrites() == 0); // no more packets +} + +TEST_CASE(SUITE("ReceiveCTOSynchronized")) +{ + auto params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.SendToMaster("D0 82 00 00 33 01 07 01 03 00 00 00 00 00 02 03 28 01 00 07 00 81 01 00"); + + REQUIRE(t.meas->TotalReceived() == 1); + auto record = t.meas->binarySOE[7]; + bool equal = record.meas == Binary(true, 0x01, DNPTime(0x04)); //timestamp is 4 + REQUIRE(equal); + REQUIRE(record.info.tsmode == TimestampMode::SYNCHRONIZED); +} + +TEST_CASE(SUITE("ReceiveCTOUnsynchronized")) +{ + auto params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + // same as above, but with Group 51 Var 2 + t.SendToMaster("D0 82 00 00 33 02 07 01 03 00 00 00 00 00 02 03 28 01 00 07 00 81 01 00"); + + REQUIRE(t.meas->TotalReceived() == 1); + auto record = t.meas->binarySOE[7]; + bool equal = record.meas == Binary(true, 0x01, DNPTime(0x04)); //timestamp is 4 + REQUIRE(equal); + REQUIRE(record.info.tsmode == TimestampMode::UNSYNCHRONIZED); +} + +TEST_CASE(SUITE("ReceiveIINinResponses")) +{ + auto params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + auto scan = t.context->AddClassScan(ClassField(~0), TimeDuration::Seconds(1)); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + + // response with IIN retart bit + t.SendToMaster("C0 81 80 00"); + + REQUIRE(t.application->rxIIN.size() == 1); + REQUIRE(t.application->rxIIN[0].IsSet(IINBit::DEVICE_RESTART)); +} + +TEST_CASE(SUITE("ReceiveIINUnsol")) +{ + auto params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.SendToMaster(hex::NullUnsolicited(0, IINField(IINBit::DEVICE_TROUBLE))); + + REQUIRE(t.application->rxIIN.size() == 1); + REQUIRE(t.application->rxIIN[0].IsSet(IINBit::DEVICE_TROUBLE)); +} + +TEST_CASE(SUITE("EventScanOnEventsAvailableIIN")) +{ + auto params = NoStartupTasks(); + params.eventScanOnEventsAvailableClassMask = ClassField::CLASS_1 | ClassField::CLASS_2; + MasterTestObject t(params); + + t.context->OnLowerLayerUp(); + + t.SendToMaster(hex::EmptyResponse(0, IINField(IINBit::CLASS1_EVENTS))); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::EventPoll(0, params.eventScanOnEventsAvailableClassMask)); + t.context->OnSendResult(true); + + t.SendToMaster(hex::EmptyResponse(0, IINField(IINBit::CLASS2_EVENTS))); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::EventPoll(1, params.eventScanOnEventsAvailableClassMask)); + t.context->OnSendResult(true); + + t.SendToMaster(hex::EmptyResponse(1, IINField(IINBit::CLASS3_EVENTS))); + + t.exe->RunMany(); + + REQUIRE(t.lower->NumWrites() == 0); +} + +TEST_CASE(SUITE("AdhocScanWorksWithUnsolicitedDisabled")) +{ + MasterParams params = NoStartupTasks(); + params.disableUnsolOnStartup = true; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.context->ScanClasses(ClassField::AllEventClasses()); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + t.context->OnSendResult(true); + t.SendToMaster(hex::EmptyResponse(0)); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::READ, 1, ClassField::AllEventClasses())); +} + +TEST_CASE(SUITE("AdhocScanFailsImmediatelyIfMasterOffline")) +{ + MasterParams params = NoStartupTasks(); + MasterTestObject t(params); + + MockTaskCallback callback; + t.context->ScanClasses(ClassField::AllEventClasses(), TaskConfig::With(callback)); + + REQUIRE(callback.numStart == 0); + REQUIRE(callback.results.size() == 1); + REQUIRE(callback.results[0] == TaskCompletion::FAILURE_NO_COMMS); + REQUIRE(callback.numDestroyed == 1); +} + +TEST_CASE(SUITE("MasterWritesTimeAndInterval")) +{ + MasterParams params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + MockTaskCallback callback; + + t.context->Write(TimeAndInterval(DNPTime(3), 4, IntervalUnits::Days), 7, TaskConfig::With(callback)); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == "C0 02 32 04 28 01 00 07 00 03 00 00 00 00 00 04 00 00 00 05"); + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == ""); + + REQUIRE(callback.numStart == 1); + REQUIRE(callback.results.size() == 1); + REQUIRE(callback.results[0] == TaskCompletion::SUCCESS); +} + +TEST_CASE(SUITE("Cold restart fails with empty response")) +{ + MasterParams params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + CallbackQueue queue; + + t.context->Restart(RestartType::COLD, queue.Callback()); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == "C0 0D"); // cold restart + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == ""); + + REQUIRE(queue.responses.size() == 1); + REQUIRE(queue.responses[0].summary == TaskCompletion::FAILURE_BAD_RESPONSE); +} + +TEST_CASE(SUITE("Warm restart fails with empty response")) +{ + MasterParams params = NoStartupTasks(); + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + CallbackQueue queue; + + t.context->Restart(RestartType::WARM, queue.Callback()); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == "C0 0E"); // warm restart + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00 34 01 07 01 BB BB"); + REQUIRE(t.lower->PopWriteAsHex() == ""); + + REQUIRE(queue.responses.size() == 1); + REQUIRE(queue.responses[0].summary == TaskCompletion::SUCCESS); + REQUIRE(queue.responses[0].restartTime.GetMilliseconds() == (0xBBBB * 1000)); +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterAssignClass.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterAssignClass.cpp new file mode 100644 index 0000000..4080e85 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterAssignClass.cpp @@ -0,0 +1,77 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MasterTestObject.h" + +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "MasterAssignClassTestSuite - " name + +TEST_CASE(SUITE("AssignsClassAfterConnect")) +{ + MasterTestObject t(NoStartupTasks()); + + // configure the mock application to do assign class on startup + t.application->assignClassHeaders.push_back(Header::AllObjects(60, 2)); + t.application->assignClassHeaders.push_back(Header::AllObjects(3, 0)); + + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 16 3C 02 06 03 00 06"); + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00"); + + t.exe->RunMany(); + REQUIRE(t.exe->NumPendingTimers() == 1); + REQUIRE(t.lower->PopWriteAsHex() == ""); + + REQUIRE(t.application->taskStartEvents.size() == 1); + REQUIRE(t.application->taskStartEvents[0] == MasterTaskType::ASSIGN_CLASS); + + REQUIRE(t.application->taskCompletionEvents.size() == 1); + REQUIRE(t.application->taskCompletionEvents[0].result == TaskCompletion::SUCCESS); +} + +TEST_CASE(SUITE("DisableUnsolBeforeAssignClass")) +{ + auto params = NoStartupTasks(); + params.disableUnsolOnStartup = true; + MasterTestObject t(params); + + // configure the mock application to do assign class on startup + t.application->assignClassHeaders.push_back(Header::AllObjects(60, 2)); + t.application->assignClassHeaders.push_back(Header::AllObjects(3, 0)); + + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterCommandRequests.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterCommandRequests.cpp new file mode 100644 index 0000000..53b99db --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterCommandRequests.cpp @@ -0,0 +1,440 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MasterTestObject.h" +#include "mocks/MeasurementComparisons.h" + +#include + +#include +#include + +#include +#include + +using namespace opendnp3; +using namespace openpal; + +// Group 12 Var1, 1 byte count/index, index = 1, time on/off = 1000, CommandStatus::SUCCESS +std::string crob = "0C 01 28 01 00 01 00 01 01 64 00 00 00 64 00 00 00 00"; + +#define SUITE(name) "MasterCommandRequestsTestSuite - " name + +TEST_CASE(SUITE("ControlExecutionClosedState")) +{ + MasterParams params; + MasterTestObject t(params); + + ControlRelayOutputBlock crob(ControlCode::PULSE_ON); + CommandCallbackQueue queue; + + + for (int i = 0; i < 10; ++i) + { + CommandSet commands({ WithIndex(crob, 7) }); + + t.context->SelectAndOperate(std::move(commands), queue.Callback(), TaskConfig::Default()); + REQUIRE(1 == queue.values.size()); + + auto& rsp = queue.values.front(); + REQUIRE(rsp.summary == TaskCompletion::FAILURE_NO_COMMS); + + // even though it has failed, there should be an entry for the command + REQUIRE(rsp.results.size() == 1); + REQUIRE(rsp.results[0].Equals(CommandPointResult(0, 7, CommandPointState::INIT, CommandStatus::UNDEFINED))); + + queue.values.pop_front(); + } +} + +TEST_CASE(SUITE("ControlsTimeoutAfterStartPeriodElapses")) +{ + MasterParams params; + params.taskStartTimeout = TimeDuration::Milliseconds(100); // set to an intentionally value so that is < response timeout + MasterTestObject t(params); + + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + + // while we're waiting for a reponse, submit a control + CommandCallbackQueue queue; + + for(int i = 0; i < 5; ++i) + { + CommandSet commands({ WithIndex(ControlRelayOutputBlock(ControlCode::PULSE_ON), 1) }); + t.context->SelectAndOperate(std::move(commands), queue.Callback(), TaskConfig::Default()); + t.exe->AdvanceTime(params.taskStartTimeout); + REQUIRE(t.exe->RunMany() > 0); + REQUIRE(1 == queue.values.size()); + REQUIRE(TaskCompletion::FAILURE_START_TIMEOUT == queue.values.front().summary); + queue.values.pop_front(); + } +} + +TEST_CASE(SUITE("SelectAndOperate")) +{ + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + ControlRelayOutputBlock command(ControlCode::PULSE_ON); + + CommandCallbackQueue queue; + t.context->SelectAndOperate(CommandSet({ WithIndex(command, 1) }), queue.Callback(), TaskConfig::Default()); + + // Group 12 Var1, 1 byte count/index, index = 1, time on/off = 1000, CommandStatus::SUCCESS + std::string crob = "0C 01 28 01 00 01 00 01 01 64 00 00 00 64 00 00 00 00"; + + REQUIRE(t.lower->PopWriteAsHex() == "C0 03 " + crob); // SELECT + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00 " + crob); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == "C1 04 " + crob); // OPERATE + t.context->OnSendResult(true); + t.SendToMaster("C1 81 00 00 " + crob); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == ""); //nore more packets + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::SUCCESS, + CommandPointResult(0, 1, CommandPointState::SUCCESS, CommandStatus::SUCCESS) + )); +} + +TEST_CASE(SUITE("SelectAndOperateWithConfirmResponse")) +{ + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + ControlRelayOutputBlock bo(ControlCode::PULSE_ON); + + CommandCallbackQueue queue; + t.context->SelectAndOperate(CommandSet({ WithIndex(bo, 1) }), queue.Callback(), TaskConfig::Default()); + + // Group 12 Var1, 1 byte count/index, index = 1, time on/off = 1000, CommandStatus::SUCCESS + std::string crob = "0C 01 28 01 00 01 00 01 01 64 00 00 00 64 00 00 00 00"; + + REQUIRE(t.lower->PopWriteAsHex() == "C0 03 " + crob); // SELECT + t.context->OnSendResult(true); + t.SendToMaster("E0 81 00 00 " + crob); // confirm bit set + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 00"); // confirm + t.context->OnSendResult(true); + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == "C1 04 " + crob); // OPERATE + t.context->OnSendResult(true); + t.SendToMaster("C1 81 00 00 " + crob); + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == ""); //nore more packets + REQUIRE( + queue.PopOnlyEqualValue( + TaskCompletion::SUCCESS, + CommandPointResult(0, 1, CommandPointState::SUCCESS, CommandStatus::SUCCESS) + ) + ); +} + +TEST_CASE(SUITE("ControlExecutionSelectResponseTimeout")) +{ + auto config = NoStartupTasks(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + CommandCallbackQueue queue; + t.context->SelectAndOperate( + CommandSet({ WithIndex(ControlRelayOutputBlock(ControlCode::PULSE_ON), 1) }), + queue.Callback(), TaskConfig::Default() + ); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 03 " + crob); // SELECT + t.context->OnSendResult(true); + + t.exe->AdvanceTime(config.responseTimeout); + t.exe->RunMany(); + + REQUIRE( + queue.PopOnlyEqualValue( + TaskCompletion::FAILURE_RESPONSE_TIMEOUT, + CommandPointResult(0, 1, CommandPointState::INIT, CommandStatus::UNDEFINED) + ) + ); +} + +TEST_CASE(SUITE("ControlExecutionSelectLayerDown")) +{ + auto config = NoStartupTasks(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + CommandCallbackQueue queue; + t.context->SelectAndOperate( + CommandSet({ WithIndex(ControlRelayOutputBlock(ControlCode::PULSE_ON), 1) }), + queue.Callback(), TaskConfig::Default() + ); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 03 " + crob); // SELECT + t.context->OnSendResult(true); + + t.context->OnLowerLayerDown(); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::FAILURE_NO_COMMS, + CommandPointResult(0, 1, CommandPointState::INIT, CommandStatus::UNDEFINED) + )); +} + +TEST_CASE(SUITE("ControlExecutionSelectErrorResponse")) +{ + auto config = NoStartupTasks(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + CommandCallbackQueue queue; + t.context->SelectAndOperate( + CommandSet({ WithIndex(ControlRelayOutputBlock(ControlCode::PULSE_ON), 1) }), + queue.Callback(), TaskConfig::Default() + ); + + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00 0C 01 28 01 00 01 00 01 01 64 00 00 00 64 00 00 00 04"); // not supported + + t.exe->RunMany(); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::SUCCESS, + CommandPointResult(0, 1, CommandPointState::SELECT_FAIL, CommandStatus::NOT_SUPPORTED) + )); +} + +TEST_CASE(SUITE("ControlExecutionSelectBadFIRFIN")) +{ + auto config = NoStartupTasks(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + CommandCallbackQueue queue; + + t.context->SelectAndOperate( + CommandSet({ WithIndex(ControlRelayOutputBlock(ControlCode::PULSE_ON), 1) }), + queue.Callback(), TaskConfig::Default() + ); + t.context->OnSendResult(true); + + t.SendToMaster("80 81 00 00 0C 01 28 01 00 01 00 01 01 64 00 00 00 64 00 00 00 00"); + + t.exe->RunMany(); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::FAILURE_BAD_RESPONSE, + CommandPointResult(0, 1, CommandPointState::INIT, CommandStatus::UNDEFINED) + )); +} + +TEST_CASE(SUITE("DeferredControlExecution")) +{ + MasterParams params; + params.disableUnsolOnStartup = false; + params.unsolClassMask = 0; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.exe->RunMany(); + + // check that a read request was made on startup + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + t.context->OnSendResult(true); + + //issue a command while the master is waiting for a response from the outstation + + CommandCallbackQueue queue; + t.context->SelectAndOperate( + CommandSet({ WithIndex(ControlRelayOutputBlock(ControlCode::PULSE_ON), 1) }), + queue.Callback(), TaskConfig::Default() + ); + + t.SendToMaster("C0 81 00 00"); //now master gets response to integrity + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == "C1 03 " + crob); //select +} + +TEST_CASE(SUITE("CloseWhileWaitingForCommandResponse")) +{ + auto config = NoStartupTasks(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + AnalogOutputInt16 ao(100); + CommandCallbackQueue queue; + + t.context->DirectOperate( + CommandSet({ WithIndex(ao, 1) }), + queue.Callback(), TaskConfig::Default() + ); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 05 29 02 28 01 00 01 00 64 00 00"); // DIRECT OPERATE + REQUIRE(t.lower->NumWrites() == 0); //nore more packets + REQUIRE(queue.values.empty()); + t.context->OnLowerLayerDown(); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::FAILURE_NO_COMMS, + CommandPointResult(0, 1, CommandPointState::INIT, CommandStatus::UNDEFINED) + )); +} + +TEST_CASE(SUITE("ResponseTimeout")) +{ + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + AnalogOutputInt16 ao(100); + CommandCallbackQueue queue; + + t.context->DirectOperate( + CommandSet({ WithIndex(ao, 1) }), + queue.Callback(), TaskConfig::Default() + ); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 05 29 02 28 01 00 01 00 64 00 00"); // DIRECT OPERATE + REQUIRE(t.lower->NumWrites() == 0); //nore more packets + REQUIRE(queue.values.empty()); + + REQUIRE(t.exe->AdvanceToNextTimer()); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::FAILURE_RESPONSE_TIMEOUT, + CommandPointResult(0, 1, CommandPointState::INIT, CommandStatus::UNDEFINED) + )); +} + +TEST_CASE(SUITE("SendCommandDuringFailedStartup")) +{ + auto params = NoStartupTasks(); + params.disableUnsolOnStartup = true; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(t.lower->PopWriteAsHex() == hex::ClassTask(FunctionCode::DISABLE_UNSOLICITED, 0, ClassField::AllEventClasses())); + t.context->OnSendResult(true); + REQUIRE(t.exe->AdvanceToNextTimer()); + REQUIRE(t.exe->RunMany() > 0); + + // while we're waiting for a response to the disable unsol, initiate a command seqeunce + CommandCallbackQueue queue; + AnalogOutputInt16 ao(100); + t.context->DirectOperate( + CommandSet({ WithIndex(ao, 1) }), + queue.Callback(), TaskConfig::Default() + ); + + + REQUIRE(t.lower->PopWriteAsHex() == "C1 05 29 02 28 01 00 01 00 64 00 00"); // DIRECT OPERATE + REQUIRE(t.lower->NumWrites() == 0); //nore more packets + REQUIRE(queue.values.empty()); + + REQUIRE(t.exe->AdvanceToNextTimer()); + + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::FAILURE_RESPONSE_TIMEOUT, + CommandPointResult(0, 1, CommandPointState::INIT, CommandStatus::UNDEFINED) + )); +} + +template +void TestAnalogOutputExecution(const std::string& hex, const T& command) +{ + auto config = NoStartupTasks(); + MasterTestObject t(config); + t.context->OnLowerLayerUp(); + + CommandCallbackQueue queue; + + t.context->SelectAndOperate(CommandSet({WithIndex(command, 1)}), queue.Callback(), TaskConfig::Default()); + REQUIRE(t.exe->RunMany() > 0); + + REQUIRE((t.lower->PopWriteAsHex() == ("C0 03 " + hex))); + t.context->OnSendResult(true); + REQUIRE(queue.values.empty()); + t.SendToMaster("C0 81 00 00 " + hex); + + t.exe->RunMany(); + + REQUIRE((t.lower->PopWriteAsHex() == ("C1 04 " + hex))); + t.context->OnSendResult(true); + REQUIRE(queue.values.empty()); + t.SendToMaster("C1 81 00 00 " + hex); + + t.exe->RunMany(); + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::SUCCESS, + CommandPointResult(0, 1, CommandPointState::SUCCESS, CommandStatus::SUCCESS) + )); +} + +TEST_CASE(SUITE("SingleSetpointExecution"))// Group 41 Var4 +{ + // 100.0 + TestAnalogOutputExecution("29 03 28 01 00 01 00 00 00 C8 42 00", AnalogOutputFloat32(100.0f)); + + // 95.6 + TestAnalogOutputExecution("29 03 28 01 00 01 00 33 33 BF 42 00", AnalogOutputFloat32(95.6f)); +} + +TEST_CASE(SUITE("DoubleSetpointExecution")) +{ + TestAnalogOutputExecution("29 04 28 01 00 01 00 00 00 00 E7 FF FF 58 48 00", AnalogOutputDouble64(SingleFloat::Max * 100.0)); +} + +TEST_CASE(SUITE("Int32SetpointExecution")) +{ + // Group 41 Var1, Int32, 65536 + TestAnalogOutputExecution("29 01 28 01 00 01 00 00 00 01 00 00", AnalogOutputInt32(65536)); +} + +TEST_CASE(SUITE("Int16SetpointExecution")) +{ + // Group 41 Var2, Int16, 100 + TestAnalogOutputExecution("29 02 28 01 00 01 00 64 00 00", AnalogOutputInt16(100)); +} + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultiCommandRequests.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultiCommandRequests.cpp new file mode 100644 index 0000000..e783068 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultiCommandRequests.cpp @@ -0,0 +1,136 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MasterTestObject.h" +#include "mocks/MeasurementComparisons.h" + +#include + +#include +#include + +#include +#include + +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "MasterMultiCommandRequestsTestSuite - " name + +TEST_CASE(SUITE("command set ignores empty headers")) +{ + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + ControlRelayOutputBlock crob(ControlCode::PULSE_ON); + + CommandSet commands; + commands.Add({}); + commands.Add({ WithIndex(crob, 1) }); + + CommandCallbackQueue queue; + t.context->DirectOperate(std::move(commands), queue.Callback(), TaskConfig::Default()); + + // writes just the 2nd call to Add() + REQUIRE(t.lower->PopWriteAsHex() == "C0 05 0C 01 28 01 00 01 00 01 01 64 00 00 00 64 00 00 00 00"); +} + +TEST_CASE(SUITE("DirectOperateTwoCROB")) +{ + // Group 12 Var1, 1 byte count/index, index = 1, time on/off = 1000, CommandStatus::SUCCESS + std::string crobstr = "0C 01 28 02 00 01 00 01 01 64 00 00 00 64 00 00 00 00 07 00 01 01 64 00 00 00 64 00 00 00 00"; + + + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + ControlRelayOutputBlock crob(ControlCode::PULSE_ON); + + CommandSet commands; + commands.Add({ WithIndex(crob, 1), WithIndex(crob, 7) }); + + CommandCallbackQueue queue; + t.context->DirectOperate(std::move(commands), queue.Callback(), TaskConfig::Default()); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 05 " + crobstr); // DO + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00 " + crobstr); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == ""); //nore more packets + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::SUCCESS, + { + CommandPointResult(0, 1, CommandPointState::SUCCESS, CommandStatus::SUCCESS), + CommandPointResult(0, 7, CommandPointState::SUCCESS, CommandStatus::SUCCESS) + } + )); +} + +TEST_CASE(SUITE("SelectAndOperateTwoCROBSOneAO")) +{ + // Group 12 Var1, 1 byte count/index, index = 1, time on/off = 1000, CommandStatus::SUCCESS + // Group 41 Var2 - index 8, value 0x1234 + std::string crobstr = "0C 01 28 02 00 01 00 01 01 64 00 00 00 64 00 00 00 00 07 00 01 01 64 00 00 00 64 00 00 00 00"; + std::string aostr = "29 02 28 01 00 08 00 34 12 00"; + std::string headers = crobstr + " " + aostr; + + + MasterTestObject t(NoStartupTasks()); + t.context->OnLowerLayerUp(); + + ControlRelayOutputBlock crob(ControlCode::PULSE_ON); + AnalogOutputInt16 ao(0x1234); + + CommandSet commands; + commands.Add({ WithIndex(crob, 1), WithIndex(crob, 7) }); + commands.Add({ WithIndex(ao, 8) }); + + CommandCallbackQueue queue; + t.context->SelectAndOperate(std::move(commands), queue.Callback(), TaskConfig::Default()); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 03 " + headers); // select + t.context->OnSendResult(true); + t.SendToMaster("C0 81 00 00 " + headers); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == "C1 04 " + headers); // operate + t.context->OnSendResult(true); + t.SendToMaster("C1 81 00 00 " + headers); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == ""); //nore more packets + + REQUIRE(queue.PopOnlyEqualValue( + TaskCompletion::SUCCESS, + { + CommandPointResult(0, 1, CommandPointState::SUCCESS, CommandStatus::SUCCESS), + CommandPointResult(0, 7, CommandPointState::SUCCESS, CommandStatus::SUCCESS), + CommandPointResult(1, 8, CommandPointState::SUCCESS, CommandStatus::SUCCESS) + } + )); +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultidrop.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultidrop.cpp new file mode 100644 index 0000000..24f5168 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterMultidrop.cpp @@ -0,0 +1,104 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MasterTestObject.h" + +#include +#include + +#include + +using namespace openpal; +using namespace opendnp3; + +#define SUITE(name) "MasterMultidropTestSuite - " name + +TEST_CASE(SUITE("MultidropRoundRobinStartupSequence")) +{ + MultidropTaskLock taskLock; + taskLock.SetOnline(); + + MasterParams params; + params.disableUnsolOnStartup = false; + + MasterTestObject t1(params, taskLock); + MasterTestObject t2(params, taskLock); + + t1.context->OnLowerLayerUp(); + t2.context->OnLowerLayerUp(); + + t1.exe->RunMany(); + t2.exe->RunMany(); + + REQUIRE(t1.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + REQUIRE(t2.lower->PopWriteAsHex() == ""); + + t1.context->OnSendResult(true); + t1.SendToMaster(hex::EmptyResponse(0, IINField(IINBit::DEVICE_RESTART))); + + t1.exe->RunMany(); + t2.exe->RunMany(); + + REQUIRE(t1.lower->PopWriteAsHex() == ""); + REQUIRE(t2.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + + t2.context->OnSendResult(true); + t2.SendToMaster(hex::EmptyResponse(0)); + + t1.exe->RunMany(); + t2.exe->RunMany(); + + REQUIRE(t1.lower->PopWriteAsHex() == hex::ClearRestartIIN(1)); + REQUIRE(t2.lower->PopWriteAsHex() == ""); +} + +TEST_CASE(SUITE("Shutting down a master causes 2nd master to acquire task lock")) +{ + MultidropTaskLock taskLock; + taskLock.SetOnline(); + + MasterParams params; + params.disableUnsolOnStartup = false; + + MasterTestObject t1(params, taskLock); + MasterTestObject t2(params, taskLock); + + t1.context->OnLowerLayerUp(); + t2.context->OnLowerLayerUp(); + + t1.exe->RunMany(); + t2.exe->RunMany(); + + REQUIRE(t1.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); + REQUIRE(t2.lower->PopWriteAsHex() == ""); + + t1.context->OnSendResult(true); + // instead of sending a reply, shutdown the first master + t1.context->OnLowerLayerDown(); + + t1.exe->RunMany(); + t2.exe->RunMany(); + + REQUIRE(t1.lower->PopWriteAsHex() == ""); + REQUIRE(t2.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterUnsolBehaviors.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterUnsolBehaviors.cpp new file mode 100644 index 0000000..ece6985 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMasterUnsolBehaviors.cpp @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/MasterTestObject.h" +#include "mocks/MeasurementComparisons.h" + +#include + +#include +#include + +#include +#include + +using namespace openpal; +using namespace opendnp3; + + +#define SUITE(name) "MasterUnsolTestSuite - " name + +TEST_CASE(SUITE("ReceiveUnsolBeforeTransmit")) +{ + MasterParams params; + params.disableUnsolOnStartup = false; + MasterTestObject t(params); + t.context->OnLowerLayerUp(); + + t.SendToMaster(hex::NullUnsolicited(0, IINField::Empty())); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::UnsolConfirm(0)); + t.context->OnSendResult(true); + + t.exe->RunMany(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::IntegrityPoll(0)); +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestMeasurementHandler.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMeasurementHandler.cpp new file mode 100644 index 0000000..32d7235 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestMeasurementHandler.cpp @@ -0,0 +1,144 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include + +#include +#include + +#include + +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +/** +* Test that the measurement handler correctly interprets measurement values in response data +*/ +#define SUITE(name) "MeasurementHandlerTestSuite - " name + +// Parse some input and verify that the ISOEHandler is invoked with expected results +ParseResult TestObjectHeaders(const std::string& objects, ParseResult expectedResult, const std::function& verify); + +TEST_CASE(SUITE("accepts empty response")) +{ + auto verify = [](MockSOEHandler & soe) + { + REQUIRE(soe.TotalReceived() == 0); + }; + + TestObjectHeaders("", ParseResult::OK, verify); +} + +TEST_CASE(SUITE("parses g121v1 correctly")) +{ + auto verify = [](MockSOEHandler & soe) + { + REQUIRE(soe.TotalReceived() == 1); + + auto& stat = soe.securityStatSOE[2]; + + REQUIRE(stat.info.tsmode == TimestampMode::INVALID); + REQUIRE(stat.info.gv == GroupVariation::Group121Var1); + REQUIRE_FALSE(stat.info.isEventVariation); + REQUIRE(stat.meas.value.count == 8); + REQUIRE(stat.meas.value.assocId == 7); + }; + + // g121v1 - 1 byte start/stop - 2->2 - flags: 0x01, assoc = 0x0007, count = 0x00000008 + auto header = "79 01 00 02 02 01 07 00 08 00 00 00"; + + TestObjectHeaders(header, ParseResult::OK, verify); +} + +TEST_CASE(SUITE("parses g122v1 correctly")) +{ + auto verify = [](MockSOEHandler & soe) + { + REQUIRE(soe.TotalReceived() == 1); + + auto& stat = soe.securityStatSOE[3]; + + REQUIRE(stat.info.tsmode == TimestampMode::INVALID); + REQUIRE(stat.info.gv == GroupVariation::Group122Var1); + REQUIRE(stat.meas.value.count == 8); + REQUIRE(stat.meas.value.assocId == 7); + }; + + // g122v1 - 1 byte count and prefix - 1 count - index: 3, flags: 0x01, assoc = 7, count = 8 + auto header = "7A 01 17 01 03 01 07 00 08 00 00 00"; + + TestObjectHeaders(header, ParseResult::OK, verify); +} + +TEST_CASE(SUITE("parses g122v2 correctly")) +{ + auto verify = [](MockSOEHandler & soe) + { + REQUIRE(soe.TotalReceived() == 1); + + auto& stat = soe.securityStatSOE[3]; + + REQUIRE(stat.info.tsmode == TimestampMode::SYNCHRONIZED); + REQUIRE(stat.info.gv == GroupVariation::Group122Var2); + REQUIRE(stat.info.isEventVariation); + REQUIRE(stat.meas.value.count == 8); + REQUIRE(stat.meas.value.assocId == 7); + REQUIRE(stat.meas.time == 9); + }; + + // g122v1 - 1 byte count and prefix - 1 count - index: 3, flags: 0x01, assoc = 7, count = 8, time = 9 + auto header = "7A 02 17 01 03 01 07 00 08 00 00 00 09 00 00 00 00 00"; + + TestObjectHeaders(header, ParseResult::OK, verify); +} + +TEST_CASE(SUITE("parses g50v1 correctly")) +{ + auto verify = [](MockSOEHandler & soe) + { + REQUIRE(soe.TotalReceived() == 2); + REQUIRE(soe.timeSOE.size() == 2); + REQUIRE(soe.timeSOE[0].value == 0xABABABABABAB); + REQUIRE(soe.timeSOE[1].value == 0xBCBCBCBCBCBC); + }; + + // g50v1 count of 2 + auto objects = "32 01 07 02 AB AB AB AB AB AB BC BC BC BC BC BC"; + + TestObjectHeaders(objects, ParseResult::OK, verify); +} + +ParseResult TestObjectHeaders(const std::string& objects, ParseResult expectedResult, const std::function& verify) +{ + MockSOEHandler soe; + testlib::MockLogHandler log; + + HexSequence hex(objects); + + auto result = MeasurementHandler::ProcessMeasurements(hex.ToRSlice(), log.logger, &soe); + REQUIRE(result == expectedResult); + verify(soe); + return result; +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstation.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstation.cpp new file mode 100644 index 0000000..b2ee8a9 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstation.cpp @@ -0,0 +1,743 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/OutstationTestObject.h" + +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; +using namespace testlib; + +#define SUITE(name) "OutstationTestSuite - " name + +TEST_CASE(SUITE("UnsupportedFunction")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 10"); // func = initialize application (16) + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); // IIN = device restart + func not supported +} + +TEST_CASE(SUITE("ApplicationIINBits")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.application->appIIN.deviceTrouble = true; + t.application->appIIN.localControl = true; + t.application->appIIN.configCorrupt = true; + t.application->appIIN.needTime = true; + + t.SendToOutstation("C0 01"); // blank read + // All 4 bits + restart + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 F0 20"); +} + +TEST_CASE(SUITE("ReadUnknownObject")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // from the conformance tests, respond with IIN 2-1 + t.SendToOutstation("C0 01 00 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 02"); // IIN = device restart + unknown object +} + +TEST_CASE(SUITE("ColdRestart")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // try first with support turned off + t.SendToOutstation("C0 0D"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); // IIN = device restart + function not supported + t.OnSendResult(true); + + t.application->coldRestartSupport = RestartMode::SUPPORTED_DELAY_FINE; + t.application->coldRestartTimeDelay = 1; + + + t.SendToOutstation("C1 0D"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 34 02 07 01 01 00"); +} + +TEST_CASE(SUITE("WarmRestart")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // try first with support turned off + t.SendToOutstation("C0 0E"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); // IIN = device restart + function not supported + t.OnSendResult(true); + + t.application->warmRestartSupport = RestartMode::SUPPORTED_DELAY_COARSE; + t.application->warmRestartTimeDelay = 65535; + + + t.SendToOutstation("C1 0E"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 34 01 07 01 FF FF"); +} + + +TEST_CASE(SUITE("NoResponseToNoAckCodes")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // outstation shouldn't respond to any of these + std::vector codes; + codes.push_back(FunctionCode::DIRECT_OPERATE_NR); + codes.push_back(FunctionCode::FREEZE_AT_TIME_NR); + codes.push_back(FunctionCode::FREEZE_CLEAR_NR); + codes.push_back(FunctionCode::FREEZE_AT_TIME_NR); + + uint8_t sequence = 0; + + for (auto code : codes) + { + uint8_t bytes[2]; + AppControlField control(true, true, false, false, sequence); + bytes[0] = control.ToByte(); + bytes[1] = static_cast(code); + auto request = ToHex(bytes, 2, true); + + t.SendToOutstation(request); + REQUIRE(t.lower->PopWriteAsHex() == ""); + + ++sequence; + } +} + +TEST_CASE(SUITE("WriteIIN")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation(hex::ClearRestartIIN(0)); + REQUIRE(t.lower->PopWriteAsHex() == hex::EmptyResponse(0)); +} + +TEST_CASE(SUITE("WriteIINEnabled")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 02 50 01 00 07 07 01"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); +} + +TEST_CASE(SUITE("WriteIINWrongBit")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 02 50 01 00 04 04 01"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); +} + +TEST_CASE(SUITE("WriteNonWriteObject")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 02 01 02 00 07 07 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); +} + +TEST_CASE(SUITE("DelayMeasure")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 17"); //delay measure + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 34 02 07 01 00 00"); // response, Grp51Var2, count 1, value == 00 00 +} + +TEST_CASE(SUITE("DelayMeasureExtraData")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 17 DE AD BE EF"); //delay measure + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); // param error +} + +TEST_CASE(SUITE("WriteTimeDate")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + + t.SendToOutstation("C1 02 32 01 07 01 D2 04 00 00 00 00"); // write Grp50Var1, value = 1234 ms after epoch + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00"); + REQUIRE(t.application->timestamps.size() == 1); + REQUIRE(t.application->timestamps.front().msSinceEpoch == 1234); + +} + +TEST_CASE(SUITE("WriteTimeDateNotAsking")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.application->allowTimeWrite = false; + t.SendToOutstation("C0 02 32 01 07 01 D2 04 00 00 00 00"); //write Grp50Var1, value = 1234 ms after epoch + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); // param error + REQUIRE(t.application->timestamps.size() == 0); +} + +TEST_CASE(SUITE("WriteTimeDateMultipleObjects")) +{ + OutstationConfig cfg; + OutstationTestObject t(cfg, DatabaseSizes::Empty()); + t.LowerLayerUp(); + + t.SendToOutstation("C0 02 32 01 07 02 D2 04 00 00 00 00 D2 04 00 00 00 00"); //write Grp50Var1, value = 1234 ms after epoch + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); // param error + need time still set + REQUIRE(t.application->timestamps.empty()); +} + +TEST_CASE(SUITE("BlankIntegrityPoll")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); +} + +TEST_CASE(SUITE("MixedVariationAssignments")) +{ + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::AnalogOnly(2)); + + { + // configure two different default variations + auto view = t.context.GetConfigView(); + view.analogs[0].config.svariation = StaticAnalogVariation::Group30Var1; + view.analogs[1].config.svariation = StaticAnalogVariation::Group30Var2; + } + + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + + // check that the response uses both g30v1 & g30v2 + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 1E 01 00 00 00 02 00 00 00 00 1E 02 00 01 01 02 00 00"); +} + +TEST_CASE(SUITE("TypesCanBeOmittedFromClass0ViaConfig")) +{ + OutstationConfig config; + config.params.typesAllowedInClass0 = StaticTypeBitField::AllTypes().Except(StaticTypeBitmask::DoubleBinaryInput); + OutstationTestObject t(config, DatabaseSizes(1, 1, 0, 0, 0, 0, 0, 0)); // 1 binary and 1 double binary + + t.LowerLayerUp(); + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 01 02 00 00 00 02"); +} + +TEST_CASE(SUITE("ReadClass0MultiFragAnalog")) +{ + OutstationConfig config; + config.params.maxTxFragSize = 20; // override to use a fragment length of 20 + OutstationTestObject t(config, DatabaseSizes::AnalogOnly(8)); + t.LowerLayerUp(); + + + t.Transaction([](IUpdateHandler & db) + { + for (uint16_t i = 0; i < 8; i++) + { + db.Update(Analog(0, 0x01), i); + } + }); + + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + + // Response should be (30,1)x2 per fragment, quality ONLINE, value 0 + // 4 fragment response, first 3 fragments should be confirmed, last one shouldn't be + REQUIRE(t.lower->PopWriteAsHex() == "A0 81 80 00 1E 01 00 00 01 01 00 00 00 00 01 00 00 00 00"); + t.OnSendResult(true); + t.SendToOutstation("C0 00"); + REQUIRE(t.lower->PopWriteAsHex() == "21 81 80 00 1E 01 00 02 03 01 00 00 00 00 01 00 00 00 00"); + t.OnSendResult(true); + t.SendToOutstation("C1 00"); + REQUIRE(t.lower->PopWriteAsHex() == "22 81 80 00 1E 01 00 04 05 01 00 00 00 00 01 00 00 00 00"); + t.OnSendResult(true); + t.SendToOutstation("C2 00"); + REQUIRE(t.lower->PopWriteAsHex() == "43 81 80 00 1E 01 00 06 07 01 00 00 00 00 01 00 00 00 00"); + t.OnSendResult(true); + t.SendToOutstation("C3 00"); + + REQUIRE(t.lower->PopWriteAsHex() == ""); +} + +TEST_CASE(SUITE("ReadFuncNotSupported")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 0C 01 06"); //try to read 12/1 (control block) + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); //restart/func not supported +} + + +void NewTestStaticRead(const std::string& request, const std::string& response) +{ + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::AllTypes(1)); + t.LowerLayerUp(); + + t.SendToOutstation(request); + REQUIRE(t.lower->PopWriteAsHex() == response); +} + +// ---- Group50Var4 TimeAndInterval support ----- // + +void TestTimeAndIntervalRead(const std::string& request) +{ + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::TimeAndIntervalOnly(1)); + t.LowerLayerUp(); + + t.Transaction( + [](IUpdateHandler & db) + { + db.Update(TimeAndInterval(DNPTime(9), 3, IntervalUnits::Days), 0); + } + ); + + t.SendToOutstation(request); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 32 04 00 00 00 09 00 00 00 00 00 03 00 00 00 05"); +} + +TEST_CASE(SUITE("TimeAndIntervalViaIntegrity")) +{ + TestTimeAndIntervalRead(hex::IntegrityPoll(0)); +} + +TEST_CASE(SUITE("TimeAndIntervalViaDirectRequest")) +{ + TestTimeAndIntervalRead("C0 01 32 04 06"); +} + +TEST_CASE(SUITE("TimeAndIntervalViaDirectRangeRequest")) +{ + TestTimeAndIntervalRead("C0 01 32 04 00 00 00"); +} + +TEST_CASE(SUITE("TestTimeAndIntervalWrite")) +{ + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::TimeAndIntervalOnly(1)); + t.LowerLayerUp(); + + t.application->supportsWriteTimeAndInterval = true; + + // write g50v4 using 2-octet count & index prefix + t.SendToOutstation("C0 02 32 04 28 01 00 07 00 09 00 00 00 00 00 03 00 00 00 05"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); + + REQUIRE(t.application->timeAndIntervals.size() == 1); + REQUIRE(t.application->timeAndIntervals[0].index == 7); + REQUIRE(t.application->timeAndIntervals[0].value.time == 9); +} + +// ---- Static data reads ----- // + +TEST_CASE(SUITE("ReadGrp1Var0ViaIntegrity")) +{ + NewTestStaticRead("C0 01 01 00 06", "C0 81 80 00 01 02 00 00 00 02"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadGrp1Var2ViaIntegrity")) +{ + NewTestStaticRead("C0 01 01 02 06", "C0 81 80 00 01 02 00 00 00 02"); // 1 byte start/stop, packed format +} + +TEST_CASE(SUITE("ReadGrp10Var0ViaIntegrity")) +{ + NewTestStaticRead("C0 01 0A 00 06", "C0 81 80 00 0A 02 00 00 00 02"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadGrp20Var0ViaIntegrity")) +{ + NewTestStaticRead("C0 01 14 00 06", "C0 81 80 00 14 01 00 00 00 02 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("RreadGrp20Var1ViaIntegrity")) +{ + NewTestStaticRead("C0 01 14 01 06", "C0 81 80 00 14 01 00 00 00 02 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("RreadGrp20Var5ViaIntegrity")) +{ + NewTestStaticRead("C0 01 14 05 06", "C0 81 80 00 14 05 00 00 00 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadGrp30Var0ViaIntegrity")) +{ + NewTestStaticRead("C0 01 1E 00 06", "C0 81 80 00 1E 01 00 00 00 02 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadGrp30Var1ViaIntegrity")) +{ + NewTestStaticRead("C0 01 1E 01 06", "C0 81 80 00 1E 01 00 00 00 02 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadGrp30Var3ViaIntegrity")) +{ + NewTestStaticRead("C0 01 1E 03 06", "C0 81 80 00 1E 03 00 00 00 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadGrp40Var0ViaIntegrity")) +{ + NewTestStaticRead("C0 01 28 00 06", "C0 81 80 00 28 01 00 00 00 02 00 00 00 00"); // 1 byte start/stop, RESTART quality +} + +TEST_CASE(SUITE("ReadByRangeHeader")) +{ + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::AnalogOnly(10)); + t.LowerLayerUp(); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Analog(42, 0x01), 5); + db.Update(Analog(41, 0x01), 6); + }); + + t.SendToOutstation("C2 01 1E 02 00 05 06"); // read 30 var 2, [05 : 06] + REQUIRE(t.lower->PopWriteAsHex() == "C2 81 80 00 1E 02 00 05 06 01 2A 00 01 29 00"); +} + +TEST_CASE(SUITE("ContiguousIndexesInDiscontiguousModeIntegrityScan")) +{ + // this will tell the outstation to use discontiguous index mode, but we won't change the address assignments + OutstationConfig config; + config.params.indexMode = IndexMode::Discontiguous; + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(2)); + t.LowerLayerUp(); + + t.SendToOutstation(hex::IntegrityPoll(0)); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 01 02 00 00 01 02 02"); +} + +TEST_CASE(SUITE("ContiguousIndexesInDiscontiguousModeRangeScan")) +{ + // this will tell the outstation to use discontiguous index mode, but we won't change the address assignments + OutstationConfig config; + config.params.indexMode = IndexMode::Discontiguous; + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(2)); + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 01 02 00 00 01"); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 01 02 00 00 01 02 02"); +} + +std::string QueryDiscontiguousBinary(const std::string& request) +{ + OutstationConfig config; + config.params.indexMode = IndexMode::Discontiguous; + + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(3)); + + // assign virtual indices to the database specified above + auto view = t.context.GetConfigView(); + view.binaries[0].config.vIndex = 2; + view.binaries[1].config.vIndex = 4; + view.binaries[2].config.vIndex = 5; + + t.LowerLayerUp(); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 2, EventMode::Suppress); + db.Update(Binary(false, 0x01), 4, EventMode::Suppress); + }); + + t.SendToOutstation(request); + return t.lower->PopWriteAsHex(); +} + +TEST_CASE(SUITE("ReadDiscontiguousClass0")) +{ + REQUIRE(QueryDiscontiguousBinary("C0 01 3C 01 06") == "C0 81 80 00 01 02 00 02 02 81 01 02 00 04 05 01 02"); +} + +TEST_CASE(SUITE("ReadDiscontiguousBadRangeBelow")) +{ + // read 01 var 2, [00 : 01] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 00 01") == "C0 81 80 04"); +} + +TEST_CASE(SUITE("ReadDiscontiguousBadRangeAbove")) +{ + // read 01 var 2, [06 : 09] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 06 09") == "C0 81 80 04"); +} + + +TEST_CASE(SUITE("ReadDiscontiguousSingleRange")) +{ + // read 01 var 2, [02 : 02] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 02 02") == "C0 81 80 00 01 02 00 02 02 81"); +} + +TEST_CASE(SUITE("ReadDiscontiguousDoubleRange")) +{ + // read 01 var 2, [04 : 05] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 04 05") == "C0 81 80 00 01 02 00 04 05 01 02"); +} + +TEST_CASE(SUITE("ReadDiscontiguousPastUpperBound")) +{ + // read 01 var 2, [05 : 06] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 05 06") == "C0 81 80 04 01 02 00 05 05 02"); +} + +TEST_CASE(SUITE("ReadDiscontiguousAllDataWithMultipleRanges")) +{ + // read 01 var 2, [02 : 02]; read 01 var 2, [04 : 05] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 02 02 01 02 00 04 05") == "C0 81 80 00 01 02 00 02 02 81 01 02 00 04 05 01 02"); +} + +TEST_CASE(SUITE("ReadDiscontiguousAllDataWithMultipleRangesAndRangeError")) +{ + // read 01 var 2, [02 : 03]; read 01 var 2, [04 : 05] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 02 03 01 02 00 04 05") == "C0 81 80 04 01 02 00 02 02 81 01 02 00 04 05 01 02"); +} + +TEST_CASE(SUITE("ReadDiscontiguousAllDataWithRangeError")) +{ + // read 01 var 2, [02 : 05] + REQUIRE(QueryDiscontiguousBinary("C0 01 01 02 00 02 05") == "C0 81 80 04 01 02 00 02 02 81 01 02 00 04 05 01 02"); +} + +template +void TestStaticType(const OutstationConfig& config, const DatabaseSizes& tmp, PointType value, const std::string& rsp, const std::function& configure) +{ + OutstationTestObject t(config, tmp); + + auto view = t.context.GetConfigView(); + configure(view); + + t.LowerLayerUp(); + + t.Transaction([value](IUpdateHandler & db) + { + db.Update(PointType(value), 0); + }); + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + + REQUIRE((t.lower->PopWriteAsHex() == rsp)); +} + +template +void TestStaticCounter(StaticCounterVariation variation, T value, const std::string& response) +{ + OutstationConfig cfg; + auto configure = [variation](DatabaseConfigView & view) + { + view.counters[0].config.svariation = variation; + }; + TestStaticType(cfg, DatabaseSizes::CounterOnly(1), value, response, configure); +} + +TEST_CASE(SUITE("ReadGrp1Var1")) +{ + OutstationConfig cfg; + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(10)); + + { + auto view = t.context.GetConfigView(); + auto setValue = [](Cell& cell) -> void + { + cell.value = Binary(false); + cell.config.svariation = StaticBinaryVariation::Group1Var1; + }; + + view.binaries.foreach(setValue); + } + + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 01 01 00 00 09 00 00"); +} + +TEST_CASE(SUITE("Grp1Var1IsPromotedToGrp1Var2IfQualityNotOnline")) +{ + OutstationConfig cfg; + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(2)); + + { + auto view = t.context.GetConfigView(); + auto setVariation = [](Cell& cell) -> void + { + cell.config.svariation = StaticBinaryVariation::Group1Var1; + }; + + view.binaries.foreach(setVariation); + } + + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 01 02 00 00 01 02 02"); +} + +TEST_CASE(SUITE("ReadGrp20Var1")) +{ + TestStaticCounter(StaticCounterVariation::Group20Var1, 5, "C0 81 80 00 14 01 00 00 00 01 05 00 00 00"); +} + +TEST_CASE(SUITE("ReadGrp20Var2")) +{ + TestStaticCounter(StaticCounterVariation::Group20Var2, 5, "C0 81 80 00 14 02 00 00 00 01 05 00"); +} + +TEST_CASE(SUITE("ReadGrp20Var5")) +{ + TestStaticCounter(StaticCounterVariation::Group20Var5, 5, "C0 81 80 00 14 05 00 00 00 05 00 00 00"); +} + +TEST_CASE(SUITE("ReadGrp20Var6")) +{ + TestStaticCounter(StaticCounterVariation::Group20Var6, 5, "C0 81 80 00 14 06 00 00 00 05 00"); +} + +template +void TestStaticAnalog(StaticAnalogVariation variation, T value, const std::string& response) +{ + OutstationConfig cfg; + auto configure = [variation](DatabaseConfigView & view) + { + view.analogs[0].config.svariation = variation; + }; + TestStaticType(cfg, DatabaseSizes::AnalogOnly(1), value, response, configure); +} + +TEST_CASE(SUITE("ReadGrp30Var2")) +{ + TestStaticAnalog(StaticAnalogVariation::Group30Var2, 100, "C0 81 80 00 1E 02 00 00 00 01 64 00"); +} + +TEST_CASE(SUITE("ReadGrp30Var3")) +{ + TestStaticAnalog(StaticAnalogVariation::Group30Var3, 65536, "C0 81 80 00 1E 03 00 00 00 00 00 01 00"); +} + +TEST_CASE(SUITE("ReadGrp30Var4")) +{ + TestStaticAnalog(StaticAnalogVariation::Group30Var4, 100, "C0 81 80 00 1E 04 00 00 00 64 00"); +} + +TEST_CASE(SUITE("ReadGrp30Var5")) +{ + TestStaticAnalog(StaticAnalogVariation::Group30Var5, 95.6, "C0 81 80 00 1E 05 00 00 00 01 33 33 BF 42"); +} + +TEST_CASE(SUITE("ReadGrp30Var6")) +{ + TestStaticAnalog(StaticAnalogVariation::Group30Var6, -20, "C0 81 80 00 1E 06 00 00 00 01 00 00 00 00 00 00 34 C0"); +} + +template +void TestStaticBinaryOutputStatus(T value, const std::string& response) +{ + OutstationConfig cfg; + OutstationTestObject t(cfg, DatabaseSizes::BinaryOutputStatusOnly(1)); + t.LowerLayerUp(); + + t.Transaction([value](IUpdateHandler & db) + { + db.Update(BinaryOutputStatus(value, 0x01), 0); + }); + + t.SendToOutstation("C0 01 3C 01 06"); // Read class 0 + REQUIRE((t.lower->PopWriteAsHex() == response)); +} + +TEST_CASE(SUITE("ReadGrp10Var2")) +{ + TestStaticBinaryOutputStatus(true, "C0 81 80 00 0A 02 00 00 00 81"); +} + +template +void TestStaticAnalogOutputStatus(StaticAnalogOutputStatusVariation variation, T value, const string& response) +{ + OutstationConfig cfg; + auto configure = [variation](DatabaseConfigView & view) + { + view.analogOutputStatii[0].config.svariation = variation; + }; + TestStaticType(cfg, DatabaseSizes::AnalogOutputStatusOnly(1), value, response, configure); +} + +TEST_CASE(SUITE("ReadGrp40Var1")) +{ + TestStaticAnalogOutputStatus(StaticAnalogOutputStatusVariation::Group40Var1, 100, "C0 81 80 00 28 01 00 00 00 01 64 00 00 00"); +} + +TEST_CASE(SUITE("ReadGrp40Var2")) +{ + TestStaticAnalogOutputStatus(StaticAnalogOutputStatusVariation::Group40Var2, 100, "C0 81 80 00 28 02 00 00 00 01 64 00"); +} + +TEST_CASE(SUITE("ReadGrp40Var3")) +{ + TestStaticAnalogOutputStatus(StaticAnalogOutputStatusVariation::Group40Var3, 95.6, "C0 81 80 00 28 03 00 00 00 01 33 33 BF 42"); +} + +TEST_CASE(SUITE("ReadGrp40Var4")) +{ + TestStaticAnalogOutputStatus(StaticAnalogOutputStatusVariation::Group40Var4, -20.0, "C0 81 80 00 28 04 00 00 00 01 00 00 00 00 00 00 34 C0"); +} diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationAssignClass.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationAssignClass.cpp new file mode 100644 index 0000000..d6008b7 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationAssignClass.cpp @@ -0,0 +1,155 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/OutstationTestObject.h" + +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "OutstationAssignClassTestSuite - " name + +TEST_CASE(SUITE("RejectsWithFuncNotSupportedIfAppDoesNotSupport")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // assign binaries to class 2 + t.SendToOutstation("C0 16 3C 03 06 01 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); + + REQUIRE(t.application->classAssignments.empty()); +} + +TEST_CASE(SUITE("RejectsWithParamErrorIfNoType")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.application->supportsAssignClass = true; + t.LowerLayerUp(); + + // assign binaries to class 2 + t.SendToOutstation("C0 16 3C 03 06 01 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); + REQUIRE(t.application->classAssignments.empty()); +} + +TEST_CASE(SUITE("AcceptsAssignClassViaAllObjects")) +{ + const uint16_t NUM_BINARY = 5; + + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(NUM_BINARY)); + t.application->supportsAssignClass = true; + t.LowerLayerUp(); + + // assign binaries to class 2 + t.SendToOutstation("C0 16 3C 03 06 01 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); + + auto view = t.context.GetConfigView(); + for (uint16_t i = 0; i < NUM_BINARY; ++i) + { + REQUIRE(view.binaries[0].config.clazz == PointClass::Class2); + } + + REQUIRE(t.application->classAssignments.size() == 1); + auto assignment = t.application->classAssignments.front(); + REQUIRE(assignment == std::make_tuple(AssignClassType::BinaryInput, PointClass::Class2, 0, 4)); +} + +TEST_CASE(SUITE("RejectsAssignClassWithParamErrorIfRangeIsInvalid")) +{ + const uint16_t NUM_BINARY = 5; + + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(NUM_BINARY)); + t.application->supportsAssignClass = true; + t.LowerLayerUp(); + + // assign binaries 0 -> 5 (invalid range) to class 2 + t.SendToOutstation("C0 16 3C 03 06 01 00 01 00 00 05 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04"); + + //despite the invalid range, the outstation should assign the values that it does have + auto view = t.context.GetConfigView(); + for (uint16_t i = 0; i < NUM_BINARY; ++i) + { + REQUIRE(view.binaries[0].config.clazz == PointClass::Class2); + } + + REQUIRE(t.application->classAssignments.size() == 1); +} + +TEST_CASE(SUITE("AcceptsAssignClassViaStartStop")) +{ + const uint16_t NUM_BINARY = 5; + + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(NUM_BINARY)); + t.application->supportsAssignClass = true; + t.LowerLayerUp(); + + // assign binaries 2 - 3 to class 2 + t.SendToOutstation("C0 16 3C 03 06 01 00 01 02 00 03 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); + + auto view = t.context.GetConfigView(); + + REQUIRE(view.binaries[0].config.clazz == PointClass::Class1); + for (uint16_t i = 2; i < 3; ++i) + { + REQUIRE(view.binaries[i].config.clazz == PointClass::Class2); + } + REQUIRE(view.binaries[4].config.clazz == PointClass::Class1); + + REQUIRE(t.application->classAssignments.size() == 1); + auto assignment = t.application->classAssignments.front(); + REQUIRE(assignment == std::make_tuple(AssignClassType::BinaryInput, PointClass::Class2, 2, 3)); +} + +TEST_CASE(SUITE("AcceptsMultipleAssignsmentPerMessage")) +{ + const uint16_t NUM_BINARY = 5; + const uint16_t NUM_ANALOG = 10; + + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes(NUM_BINARY, 0, NUM_ANALOG, 0, 0, 0, 0, 0)); + t.application->supportsAssignClass = true; + t.LowerLayerUp(); + + // assign binaries 2 - 3 to class 2 - assign all analogs to class 3 + t.SendToOutstation("C0 16 3C 03 06 01 00 01 02 00 03 00 3C 04 06 1E 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); + + REQUIRE(t.application->classAssignments.size() == 2); + auto assignment = t.application->classAssignments.front(); + REQUIRE(assignment == std::make_tuple(AssignClassType::BinaryInput, PointClass::Class2, 2, 3)); + t.application->classAssignments.pop_front(); + assignment = t.application->classAssignments.front(); + REQUIRE(assignment == std::make_tuple(AssignClassType::AnalogInput, PointClass::Class3, 0, 9)); + +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationCommandResponses.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationCommandResponses.cpp new file mode 100644 index 0000000..315a5c1 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationCommandResponses.cpp @@ -0,0 +1,408 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/OutstationTestObject.h" + +using namespace std; +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "OutstationCommandResponsesTestSuite - " name + +TEST_CASE(SUITE("SelectCROBNotSupported")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.cmdHandler->SetResponse(CommandStatus::NOT_SUPPORTED); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + + // conformance requires IIN 2.2 to be set whenever the command status is not supported + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 04"); // 0x04 status == CommandStatus::NOT_SUPPORTED + + REQUIRE(t.cmdHandler->numStart == 1); + REQUIRE(t.cmdHandler->numEnd == 1); +} + +TEST_CASE(SUITE("UnknownCodeIsEchoed")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.cmdHandler->SetResponse(CommandStatus::NOT_SUPPORTED); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 AA 01 01 00 00 00 01 00 00 00 00"); + + // conformance requires IIN 2.2 to be set whenever the command status is not supported + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 04 0C 01 17 01 03 AA 01 01 00 00 00 01 00 00 00 04"); // 0x04 status == CommandStatus::NOT_SUPPORTED +} + +TEST_CASE(SUITE("SelectCROBTooMany")) +{ + OutstationConfig config; + config.params.maxControlsPerRequest = 1; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 2, index = 3 & 4 + t.SendToOutstation("C0 03 0C 01 17 02 03 01 01 01 00 00 00 01 00 00 00 00 04 01 01 01 00 00 00 01 00 00 00 00"); + auto expected = "C0 81 80 00 0C 01 17 02 03 01 01 01 00 00 00 01 00 00 00 00 04 01 01 01 00 00 00 01 00 00 00 08"; + REQUIRE(t.lower->PopWriteAsHex() == expected); // 0x08 status == CommandStatus::TOO_MANY_OBJS +} + +TEST_CASE(SUITE("SelectOperateCROB")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // operate + t.SendToOutstation("C1 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectRetryAndOperateCROB")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // operate + t.SendToOutstation("C1 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectOperateTimeout")) +{ + OutstationConfig config; + config.params.selectTimeout = TimeDuration::Seconds(5); + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + t.AdvanceTime(TimeDuration::Milliseconds(5001)); + + // operate + t.SendToOutstation("C1 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 01"); // 0x01 timeout + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectOperateGapInSequenceNumber")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // operate + t.SendToOutstation("C2 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C2 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 02"); // 0x02 no select + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectOperateSameSequenceNumber")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // operate + t.SendToOutstation("C0 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 02"); // 0x02 no select + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectOperateNonMatchingRequests")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // operate + t.SendToOutstation("C1 04 0C 01 17 01 04 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 0C 01 17 01 04 01 01 01 00 00 00 01 00 00 00 02"); // 0x02 no select + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectOperateCROBSameSequenceNumber")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + REQUIRE(0 == t.cmdHandler->NumInvocations()); + + // Select group 12 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + REQUIRE(1 == t.cmdHandler->NumInvocations()); + t.OnSendResult(true); + + // operate the first time with correct sequence # + t.SendToOutstation("C1 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(2 == t.cmdHandler->NumInvocations()); + t.OnSendResult(true); + + // operate again with same sequence number, should respond success but not really do an operation + t.SendToOutstation("C1 04 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"); + REQUIRE(2 == t.cmdHandler->NumInvocations()); + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectGroup41Var1")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 29 01 17 01 03 00 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 01 17 01 03 00 00 00 00 00"); +} + +TEST_CASE(SUITE("SelectGroup41Var2")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 2, count = 1, index = 3 + t.SendToOutstation("C0 03 29 02 17 01 03 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 02 17 01 03 00 00 00"); +} + +TEST_CASE(SUITE("SelectGroup41Var3")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 3, count = 1, index = 1, value = 100.0 + t.SendToOutstation("C0 03 29 03 17 01 01 00 00 C8 42 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 03 17 01 01 00 00 C8 42 00"); +} + +TEST_CASE(SUITE("SelectGroup41Var4")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 4, count = 1, index = 1, value = 100.0 + t.SendToOutstation("C0 03 29 04 17 01 01 00 00 00 00 00 00 59 40 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 04 17 01 01 00 00 00 00 00 00 59 40 00"); +} + +TEST_CASE(SUITE("SelectOperateGroup41Var1")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 1, count = 1, index = 3 + t.SendToOutstation("C0 03 29 01 17 01 03 00 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 01 17 01 03 00 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // Select group 41 Var 1, count = 1, index = 3 + t.SendToOutstation("C1 04 29 01 17 01 03 00 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 01 17 01 03 00 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + +} + +TEST_CASE(SUITE("SelectOperateGroup41Var2")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 2, count = 1, index = 3 + t.SendToOutstation("C0 03 29 02 17 01 03 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 02 17 01 03 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + + // Select group 41 Var 1, count = 1, index = 3 + t.SendToOutstation("C1 04 29 02 17 01 03 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 02 17 01 03 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + +} + +TEST_CASE(SUITE("SelectOperateGroup41Var3")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 3, count = 1, index = 1 + t.SendToOutstation("C0 03 29 03 17 01 01 00 00 C8 42 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 03 17 01 01 00 00 C8 42 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + // operate group 41 Var 3, count = 1, index = 1 + t.SendToOutstation("C1 04 29 03 17 01 01 00 00 C8 42 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 03 17 01 01 00 00 C8 42 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); +} + +TEST_CASE(SUITE("SelectOperateGroup41Var4")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Select group 41 Var 4, count = 1, index = 1 + t.SendToOutstation("C0 03 29 04 17 01 01 00 00 00 00 00 00 59 40 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 29 04 17 01 01 00 00 00 00 00 00 59 40 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); + + + // operate group 41 Var 4, count = 1, index = 1 + t.SendToOutstation("C1 04 29 04 17 01 01 00 00 00 00 00 00 59 40 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 04 17 01 01 00 00 00 00 00 00 59 40 00"); // 0x00 status == CommandStatus::SUCCESS + t.OnSendResult(true); +} + +TEST_CASE(SUITE("DirectOperateNoResponseGroup12Var1")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Direct operate (no response) group 12 Var 1, count = 1, index = 3 + auto directOperateNoACK = "C1 06 0C 01 17 01 03 01 01 01 00 00 00 01 00 00 00 00"; + + /// no-ack codes ignore sequence numbers and repeat requests + for (uint32_t i = 1; i < 5; ++i) + { + t.SendToOutstation(directOperateNoACK); + REQUIRE(t.lower->PopWriteAsHex() == ""); + REQUIRE(t.cmdHandler->NumInvocations() == i); + } +} + +TEST_CASE(SUITE("DirectOperateGroup41Var1")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Direct operate group 41 Var 1, count = 1, index = 3 + t.SendToOutstation("C1 05 29 01 17 01 03 00 00 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 01 17 01 03 00 00 00 00 00"); // 0x00 status == CommandStatus::SUCCESS +} + +TEST_CASE(SUITE("DirectOperateGroup41Var2")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Direct operate group 41 Var 1, count = 1, index = 3 + t.SendToOutstation("C1 05 29 02 17 01 03 00 00 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 02 17 01 03 00 00 00"); // 0x00 status == CommandStatus::SUCCESS + +} + +TEST_CASE(SUITE("DirectOperateGroup41Var3")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Direct operate group 41 Var 3, count = 1, index = 1 + t.SendToOutstation("C1 05 29 03 17 01 01 00 00 C7 42 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 03 17 01 01 00 00 C7 42 00"); // 0x00 status == CommandStatus::SUCCESS + + REQUIRE(t.cmdHandler->aoFloat32Ops.size() == 1); + auto op = t.cmdHandler->aoFloat32Ops[0]; + + REQUIRE(op.value.value == Approx(99.5).epsilon(1e-6)); + REQUIRE(op.index == 1); + REQUIRE(op.opType == OperateType::DirectOperate); + +} + +TEST_CASE(SUITE("DirectOperateGroup41Var4")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + // Direct operate group 41 Var 4, count = 1, index = 1 + t.SendToOutstation("C1 05 29 04 17 01 01 00 00 00 00 00 00 58 40 00"); + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00 29 04 17 01 01 00 00 00 00 00 00 58 40 00"); // 0x00 status == CommandStatus::SUCCESS + + + REQUIRE(t.cmdHandler->aoDouble64Ops.size() == 1); + auto op = t.cmdHandler->aoDouble64Ops[0]; + + REQUIRE(op.value.value == Approx(96.0).epsilon(1e-6)); + REQUIRE(op.index == 1); + REQUIRE(op.opType == OperateType::DirectOperate); +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationEventResponses.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationEventResponses.cpp new file mode 100644 index 0000000..383d90f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationEventResponses.cpp @@ -0,0 +1,388 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/OutstationTestObject.h" + +#include + +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "OutstationEventResponsesTestSuite - " name + +TEST_CASE(SUITE("BlankExceptionScan")) +{ + OutstationConfig config; + OutstationTestObject t(config); + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 3C 02 06"); // Read class 1 + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); +} + +TEST_CASE(SUITE("ReadDiscontiguousEvent")) +{ + OutstationConfig config; + config.eventBufferConfig = EventBufferConfig(5); + config.params.indexMode = IndexMode::Discontiguous; + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(1)); + t.LowerLayerUp(); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true), 0); + }); + + t.SendToOutstation("C0 01 3C 02 06"); // Read class 1 + REQUIRE(t.lower->PopWriteAsHex() == "E0 81 80 00 02 01 28 01 00 00 00 81"); +} + +TEST_CASE(SUITE("ReceiveNewRequestSolConfirmWait")) +{ + OutstationConfig config; + config.eventBufferConfig = EventBufferConfig::AllTypes(10); + OutstationTestObject t(config, DatabaseSizes::BinaryOnly(1)); + t.LowerLayerUp(); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 0); + }); + + t.SendToOutstation(hex::ClassPoll(0, PointClass::Class1)); + REQUIRE(t.lower->PopWriteAsHex() == "E0 81 80 00 02 01 28 01 00 00 00 81"); + t.OnSendResult(true); + + t.SendToOutstation(hex::ClassPoll(1, PointClass::Class1)); + REQUIRE(t.lower->PopWriteAsHex() == "E1 81 80 00 02 01 28 01 00 00 00 81"); +} + +TEST_CASE(SUITE("ReadClass1WithSOE")) +{ + OutstationConfig config; + config.eventBufferConfig = EventBufferConfig::AllTypes(10); + OutstationTestObject t(config, DatabaseSizes::AllTypes(100)); + + t.LowerLayerUp(); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Analog(0x1234, 0x01), 0x17); // 0x 12 34 00 00 in little endian + db.Update(Binary(true, 0x01), 0x10); + db.Update(Analog(0x2222, 0x01), 0x17); // 0x 22 22 00 00 in little endian + }); + + t.SendToOutstation(hex::ClassPoll(0, PointClass::Class1)); + REQUIRE(t.lower->PopWriteAsHex() == "E0 81 80 00 20 01 28 01 00 17 00 01 34 12 00 00 02 01 28 01 00 10 00 81 20 01 28 01 00 17 00 01 22 22 00 00"); + t.OnSendResult(true); + t.SendToOutstation(hex::SolicitedConfirm(0)); + + t.SendToOutstation(hex::ClassPoll(1, PointClass::Class1)); // Repeat read class 1 + REQUIRE(t.lower->PopWriteAsHex() == "C1 81 80 00"); // Buffer should have been cleared +} + +TEST_CASE(SUITE("EventBufferOverflowAndClear")) +{ + OutstationConfig config; + config.eventBufferConfig = EventBufferConfig::AllTypes(2); + OutstationTestObject t(config, DatabaseSizes::AllTypes(100)); + + t.LowerLayerUp(); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 0); // this event is lost in the overflow + db.Update(Binary(true, 0x01), 1); + db.Update(Binary(true, 0x01), 2); + }); + + t.SendToOutstation("C0 01"); + REQUIRE("C0 81 82 08" == t.lower->PopWriteAsHex()); + t.OnSendResult(true); + + t.SendToOutstation("C1 01 3C 02 07 01"); // class 1, count of 1 + REQUIRE("E1 81 82 08 02 01 28 01 00 01 00 81" == t.lower->PopWriteAsHex()); + t.OnSendResult(true); + t.SendToOutstation(hex::SolicitedConfirm(1)); + + t.SendToOutstation("C0 01"); + REQUIRE("C0 81 82 00" == t.lower->PopWriteAsHex()); +} + +TEST_CASE(SUITE("MultipleClasses")) +{ + OutstationConfig config; + config.eventBufferConfig = EventBufferConfig::AllTypes(10); + OutstationTestObject t(config, DatabaseSizes::AllTypes(1)); + t.LowerLayerUp(); + + auto view = t.context.GetConfigView(); + + view.binaries[0].config.clazz = PointClass::Class1; + view.analogs[0].config.clazz = PointClass::Class2; + view.counters[0].config.clazz = PointClass::Class3; + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true), 0); + db.Update(Analog(3), 0); + db.Update(Counter(7), 0); + }); + + t.SendToOutstation("C0 01"); // empty READ + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 8E 00"); // all event bits set + restart + t.OnSendResult(true); + + // ------ read 1 event at a time by class, until all events are gone ---- + + t.SendToOutstation(hex::ClassPoll(1, PointClass::Class2)); // Class 2 + REQUIRE(t.lower->PopWriteAsHex() == "E1 81 8A 00 20 01 28 01 00 00 00 01 03 00 00 00"); // restart + Class 1/3 + t.OnSendResult(true); + t.SendToOutstation("C1 00"); + + t.SendToOutstation("C2 01 3C 04 06"); // Class 3 + REQUIRE(t.lower->PopWriteAsHex() == "E2 81 82 00 16 01 28 01 00 00 00 01 07 00 00 00"); // restart + Class 1/3 + t.OnSendResult(true); + t.SendToOutstation("C2 00"); + + t.SendToOutstation("C3 01 3C 02 06"); // Class 1 + REQUIRE(t.lower->PopWriteAsHex() == "E3 81 80 00 02 01 28 01 00 00 00 81"); // restart only + t.OnSendResult(true); + t.SendToOutstation("C3 00"); + + t.SendToOutstation("C4 01"); // empty READ + REQUIRE(t.lower->PopWriteAsHex() == "C4 81 80 00"); // restart only +} + +void TestEventRead( const std::string& request, + const std::string& response, + const std::function& loadFun, +const std::function& configure = [](DatabaseConfigView& view) {} + ) +{ + + OutstationConfig config; + config.eventBufferConfig = EventBufferConfig::AllTypes(10); + OutstationTestObject t(config, DatabaseSizes::AllTypes(5)); + + auto view = t.context.GetConfigView(); + configure(view); + + t.LowerLayerUp(); + + t.Transaction([&](IUpdateHandler & db) + { + loadFun(db); + }); + + t.SendToOutstation(request); + REQUIRE(t.lower->PopWriteAsHex() == response); +} + +TEST_CASE(SUITE("Class1")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 0); + }; + + TestEventRead(hex::ClassPoll(0, PointClass::Class1), "E0 81 80 00 02 01 28 01 00 00 00 01", update); +} + +TEST_CASE(SUITE("Class1OneByteLimitedCount")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 2); + db.Update(Binary(true, 0x01), 1); + }; + + // reads a single event, IIB bit indicates more events present + TestEventRead("C0 01 3C 02 07 01", "E0 81 82 00 02 01 28 01 00 02 00 01", update); +} + +TEST_CASE(SUITE("Class1TwoByteLimitedCount")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 2); + db.Update(Binary(true, 0x01), 1); + db.Update(Binary(true, 0x01), 3); + }; + + // reads a single event, IIB bit indicates more events present + TestEventRead("C0 01 3C 02 08 02 00", "E0 81 82 00 02 01 28 02 00 02 00 01 01 00 81", update); +} + +TEST_CASE(SUITE("MixedClassLimitedCount")) +{ + auto configure = [](DatabaseConfigView & view) + { + view.binaries[0].config.clazz = PointClass::Class1; + view.binaries[1].config.clazz = PointClass::Class2; + view.binaries[2].config.clazz = PointClass::Class3; + }; + + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 0); + + db.Update(Binary(true, 0x01), 1); + db.Update(Binary(false, 0x01), 1); + + db.Update(Binary(true, 0x01), 2); + db.Update(Binary(false, 0x01), 2); + }; + + // read 1 class 2 event and 1 class 3 event, 1 of each event type left in buffer + // get back two g2v1 events in the same header for indices 1 & 2 + TestEventRead("C0 01 3C 03 07 01 3C 04 07 01", "E0 81 8E 00 02 01 28 02 00 01 00 81 02 00 81", update, configure); +} + +TEST_CASE(SUITE("ReadGrp2Var0")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 0); + }; + + TestEventRead("C0 01 02 00 06", "E0 81 80 00 02 01 28 01 00 00 00 01", update); +} + + +TEST_CASE(SUITE("ReadGrp22Var0")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Counter(0, 0x01), 0); + }; + + TestEventRead("C0 01 16 00 06", "E0 81 80 00 16 01 28 01 00 00 00 01 00 00 00 00", update); +} + +TEST_CASE(SUITE("ReadGrp32Var0")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Analog(0.0, 0x01), 0); + }; + + TestEventRead("C0 01 20 00 06", "E0 81 80 00 20 01 28 01 00 00 00 01 00 00 00 00", update); +} + +TEST_CASE(SUITE("ReadGrp2Var1")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 3); + }; + + TestEventRead("C0 01 02 01 06", "E0 81 80 00 02 01 28 01 00 03 00 01", update); // 1 byte count == 1, ONLINE quality +} + +TEST_CASE(SUITE("ReadGrp2Var1LimitedCount")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 3); + db.Update(Binary(true, 0x01), 2); + db.Update(Binary(false, 0x01), 1); + }; + + // read 2 events only, Class 1 data IIN still set + TestEventRead("C0 01 02 01 07 02", "E0 81 82 00 02 01 28 02 00 03 00 01 02 00 81", update); // 1 byte count == 1, ONLINE quality +} + +TEST_CASE(SUITE("ReadGrp2Var2")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01, DNPTime(0x4571)), 3); + }; + + TestEventRead("C0 01 02 02 06", "E0 81 80 00 02 02 28 01 00 03 00 01 71 45 00 00 00 00", update); // 1 byte count == 1, ONLINE quality +} + +TEST_CASE(SUITE("ReadGrp2Var3SingleValue")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01, DNPTime(0x4571)), 3); + }; + + TestEventRead("C0 01 02 03 06", "E0 81 80 00 33 01 07 01 71 45 00 00 00 00 02 03 28 01 00 03 00 01 00 00", update); +} + +TEST_CASE(SUITE("ReadGrp2Var3TwoValues")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01, DNPTime(0x4571)), 3); + db.Update(Binary(true, 0x01, DNPTime(0x4579)), 4); + }; + + auto rsp = "E0 81 80 00 33 01 07 01 71 45 00 00 00 00 02 03 28 02 00 03 00 01 00 00 04 00 81 08 00"; + + TestEventRead("C0 01 02 03 06", rsp, update); +} + +TEST_CASE(SUITE("ReadGrp2Var3TwoValuesNegativeDifference")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01, DNPTime(0x4571)), 3); + db.Update(Binary(true, 0x01, DNPTime(0x4570)), 4); + }; + + std::string header = "E0 81 80 00"; + std::string cto1 = " 33 01 07 01 71 45 00 00 00 00 02 03 28 01 00 03 00 01 00 00"; + std::string cto2 = " 33 01 07 01 70 45 00 00 00 00 02 03 28 01 00 04 00 81 00 00"; + + auto rsp = header + cto1 + cto2; + + TestEventRead("C0 01 02 03 06", rsp, update); +} + +TEST_CASE(SUITE("ReadGrp2Var3TwoValuesDifferenceTooBigForCTO")) +{ + auto update = [](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01, DNPTime(0x000000)), 3); + db.Update(Binary(true, 0x01, DNPTime(0x010000)), 4); + }; + + std::string header = "E0 81 80 00"; + std::string cto1 = " 33 01 07 01 00 00 00 00 00 00 02 03 28 01 00 03 00 01 00 00"; + std::string cto2 = " 33 01 07 01 00 00 01 00 00 00 02 03 28 01 00 04 00 81 00 00"; + + auto rsp = header + cto1 + cto2; + + TestEventRead("C0 01 02 03 06", rsp, update); +} + + + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationStateMachine.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationStateMachine.cpp new file mode 100644 index 0000000..a90863f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationStateMachine.cpp @@ -0,0 +1,73 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/OutstationTestObject.h" + +#include +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; +using namespace testlib; + +#define SUITE(name) "OutstationStateMachineTestSuite - " name + +TEST_CASE(SUITE("Responds to repeat READ request with same octets as last repsond")) +{ + OutstationConfig config; + OutstationTestObject t(config, DatabaseSizes::AnalogOnly(1)); + t.LowerLayerUp(); + + t.SendToOutstation("C0 01 1E 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 1E 01 00 00 00 02 00 00 00 00"); + t.OnSendResult(true); + + // change the value in the outstation + t.Transaction([](IUpdateHandler & db) + { + db.Update(Analog(1, 0x01), 0); + }); + + // repeat the read request + t.SendToOutstation("C0 01 1E 00 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00 1E 01 00 00 00 02 00 00 00 00"); +} + +TEST_CASE(SUITE("Responds to non-READ request while waiting for unsolicited confirm")) +{ + OutstationConfig config; + config.params.allowUnsolicited = true; + OutstationTestObject t(config, DatabaseSizes::AnalogOnly(1)); + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == "F0 82 80 00"); + t.OnSendResult(true); + + t.SendToOutstation("C0 02"); // empty write + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); //null response + t.OnSendResult(true); + + REQUIRE(t.lower->PopWriteAsHex() == ""); // shouldn't send anything else + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationUnsolicitedResponses.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationUnsolicitedResponses.cpp new file mode 100644 index 0000000..4882e74 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestOutstationUnsolicitedResponses.cpp @@ -0,0 +1,379 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/OutstationTestObject.h" + +#include + +using namespace std; +using namespace opendnp3; +using namespace openpal; + +#define SUITE(name) "OutstationUnsolicitedTestSuite - " name + +TEST_CASE(SUITE("sends null unsol on startup")) +{ + OutstationConfig cfg; cfg.params.allowUnsolicited = true; + OutstationTestObject t(cfg); + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0, IINField(IINBit::DEVICE_RESTART))); + REQUIRE(t.NumPendingTimers() == 1); +} + +TEST_CASE(SUITE("Non-read during null unsol")) +{ + OutstationConfig cfg; cfg.params.allowUnsolicited = true; + OutstationTestObject t(cfg); + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0, IINField(IINBit::DEVICE_RESTART))); + t.OnSendResult(true); + REQUIRE(t.lower->NumWrites() == 0); + + // send any non-read message + t.SendToOutstation(hex::ClearRestartIIN(0)); + REQUIRE(t.lower->PopWriteAsHex() == hex::EmptyResponse(0)); + REQUIRE(t.NumPendingTimers() == 1); +} + +TEST_CASE(SUITE("UnsolRetryDelay")) +{ + OutstationConfig cfg; cfg.params.allowUnsolicited = true; + OutstationTestObject t(cfg); + + t.LowerLayerUp(); + + + // check for the startup null unsol packet, but fail the transaction + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0, IINField(IINBit::DEVICE_RESTART))); + t.OnSendResult(true); + + REQUIRE(t.NumPendingTimers() == 1); // confirm timer + REQUIRE(t.AdvanceToNextTimer()); + + // immediately retries with new sequence # + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(1, IINField(IINBit::DEVICE_RESTART))); +} + +TEST_CASE(SUITE("UnsolData")) +{ + OutstationConfig cfg; cfg.params.allowUnsolicited = true; + cfg.params.unsolClassMask = ClassField::AllEventClasses(); // allows us to skip the "enable unsol" step + cfg.eventBufferConfig = EventBufferConfig::AllTypes(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(3)); + + auto view = t.context.GetConfigView(); + view.binaries[0].config.clazz = PointClass::Class1; + view.binaries[1].config.clazz = PointClass::Class2; + view.binaries[2].config.clazz = PointClass::Class3; + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0, IINField(IINBit::DEVICE_RESTART))); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + // do a transaction before the layer comes online to prove that the null transaction + // is occuring before unsol data is sent + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 2); + }); + + + // should immediately try to send another unsol packet, + // Grp2Var1, qual 0x17, count 1, index 2, quality+val == 0x01 + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 80 00 02 01 28 01 00 02 00 01"); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(1)); + REQUIRE(t.lower->PopWriteAsHex() == ""); +} + +TEST_CASE(SUITE("UnsolEventBufferOverflow")) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.params.unsolClassMask = ClassField(PointClass::Class1); + cfg.eventBufferConfig = EventBufferConfig(2); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(1)); + + t.LowerLayerUp(); + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0, IINField(IINBit::DEVICE_RESTART))); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 0); + db.Update(Binary(false, 0x01), 0); + db.Update(Binary(true, 0x01), 0); + }); + + // should immediately try to send 2 unsol events + // Grp2Var1, qual 0x17, count 2, index 0 + // The last two values should be published, 0x01 and 0x81 (false and true) + // the first value is lost off the front of the buffer + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 80 08 02 01 28 02 00 00 00 01 00 00 81"); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(1)); + + REQUIRE(t.lower->PopWriteAsHex() == ""); +} + +TEST_CASE(SUITE("UnsolMultiFragments")) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.params.maxTxFragSize = 20; //this will cause the unsol response to get fragmented + cfg.params.unsolClassMask = ClassField::AllEventClasses(); // this allows the EnableUnsol sequence to be skipped + cfg.eventBufferConfig = EventBufferConfig(0, 0, 5); + OutstationTestObject t(cfg, DatabaseSizes::AnalogOnly(5)); + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0)); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + REQUIRE(t.lower->PopWriteAsHex() == ""); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Analog(7, 0x01), 1); + db.Update(Analog(13, 0x01), 3); + }); + + + // Only enough room to in the APDU to carry a single value + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 82 00 20 01 28 01 00 01 00 01 07 00 00 00"); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(1)); + + // should immediately try to send another unsol packet + REQUIRE(t.lower->PopWriteAsHex() == "F2 82 80 00 20 01 28 01 00 03 00 01 0D 00 00 00"); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(2)); + + REQUIRE(t.lower->PopWriteAsHex() == ""); +} + +void WriteDuringUnsol(bool beforeTx) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.params.unsolClassMask = ClassField::AllEventClasses(); + cfg.eventBufferConfig = EventBufferConfig(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(5)); + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0)); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 0); + }); + + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 80 00 02 01 28 01 00 00 00 81"); + + if (beforeTx) + { + t.SendToOutstation(hex::ClearRestartIIN(0)); + t.OnSendResult(true); + } + else + { + t.OnSendResult(true); + t.SendToOutstation(hex::ClearRestartIIN(0)); + } + + // check that we get a response to this immediately without the confirm + REQUIRE(t.lower->PopWriteAsHex() == hex::EmptyResponse(0)); + + // now send the confirm to the outstation + t.SendToOutstation(hex::UnsolConfirm(1)); + REQUIRE(t.lower->PopWriteAsHex() == ""); +} + +// Test that non-read fragments are immediately responded to while +// waiting for a response to unsolicited data +TEST_CASE(SUITE("WriteDuringUnsolBeforeTx")) +{ + WriteDuringUnsol(true); +} + +TEST_CASE(SUITE("WriteDuringUnsolAfterTx")) +{ + WriteDuringUnsol(false); +} + + +TEST_CASE(SUITE("ReadDuringUnsol")) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.params.unsolClassMask = ClassField::AllEventClasses(); + cfg.eventBufferConfig = EventBufferConfig(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(5)); + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0)); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 0); + }); + + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 80 00 02 01 28 01 00 00 00 81"); + + auto readClass1 = "C0 01 3C 02 06"; + + if (true) + { + t.OnSendResult(true); + t.SendToOutstation(readClass1); + } + else + { + t.SendToOutstation(readClass1); + t.OnSendResult(true); + } + + t.SendToOutstation(hex::UnsolConfirm(1)); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 00"); +} + + +TEST_CASE(SUITE("ReadWriteDuringUnsol")) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.params.unsolClassMask = ClassField::AllEventClasses(); + cfg.eventBufferConfig = EventBufferConfig(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(5)); + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == "F0 82 80 00"); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 0); + }); + + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 80 00 02 01 28 01 00 00 00 81"); + t.OnSendResult(true); + + // send a read request that will be overwritten + t.SendToOutstation("C0 01 3C 01 06"); + + //now send a write IIN request, and test that the outstation answers immediately + t.SendToOutstation("C0 02 50 01 00 07 07 00"); + + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 00 00"); +} + +TEST_CASE(SUITE("RepeatRequestDuringUnsol")) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.params.unsolClassMask = ClassField::AllEventClasses(); + cfg.eventBufferConfig = EventBufferConfig(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(5)); + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == "F0 82 80 00"); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + t.SendToOutstation(hex::ClearRestartIIN(0)); + REQUIRE(t.lower->PopWriteAsHex() == hex::EmptyResponse(0)); + t.OnSendResult(true); + + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(true, 0x01), 1); + }); + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 00 00 02 01 28 01 00 01 00 81"); + t.OnSendResult(true); + + // while waiting for a confirm, repeat the previous request, byte-for-byte + t.SendToOutstation(hex::ClearRestartIIN(0)); + REQUIRE(t.lower->PopWriteAsHex() == hex::EmptyResponse(0)); + t.OnSendResult(true); + +} + + +TEST_CASE(SUITE("UnsolEnable")) +{ + OutstationConfig cfg; + cfg.params.allowUnsolicited = true; + cfg.eventBufferConfig = EventBufferConfig(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(5)); + + t.LowerLayerUp(); + + REQUIRE(t.lower->PopWriteAsHex() == hex::NullUnsolicited(0)); + t.OnSendResult(true); + t.SendToOutstation(hex::UnsolConfirm(0)); + + // do a transaction to show that unsol data is not being reported yet + t.Transaction([](IUpdateHandler & db) + { + db.Update(Binary(false, 0x01), 0); + }); + + REQUIRE(t.lower->PopWriteAsHex() == ""); + + // Enable unsol class 1 + t.SendToOutstation("C0 14 3C 02 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 82 00"); + t.OnSendResult(true); + + // should automatically send the previous data as unsol + REQUIRE(t.lower->PopWriteAsHex() == "F1 82 80 00 02 01 28 01 00 00 00 01"); +} + + +TEST_CASE(SUITE("UnsolEnableDisableFailure")) +{ + OutstationConfig cfg; + cfg.eventBufferConfig = EventBufferConfig(5); + OutstationTestObject t(cfg, DatabaseSizes::BinaryOnly(5)); + + t.LowerLayerUp(); + t.SendToOutstation("C0 14 3C 02 06"); + REQUIRE(t.lower->PopWriteAsHex() == "C0 81 80 01"); //FUNC_NOT_SUPPORTED +} + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestShiftableBuffer.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestShiftableBuffer.cpp new file mode 100644 index 0000000..4cd8de0 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestShiftableBuffer.cpp @@ -0,0 +1,161 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +#include + +#include + +using namespace opendnp3; +using namespace openpal; + + +#define SUITE(name) "ShiftableBufferSuite - " name + +const static uint8_t SYNC[] = {0x05, 0x64}; + +TEST_CASE(SUITE("ConstructDestruct")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); +} + +TEST_CASE(SUITE("InitialState")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + REQUIRE(b.NumBytesRead() == 0); + REQUIRE(b.NumWriteBytes() == 100); + REQUIRE(b.ReadBuffer() == b.WriteBuff()); +} + +TEST_CASE(SUITE("ReadingWriting")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + b.AdvanceWrite(40); + REQUIRE(b.NumWriteBytes() == 60); + REQUIRE(b.NumBytesRead() == 40); + + b.AdvanceWrite(60); + REQUIRE(b.NumWriteBytes() == 0); + REQUIRE(b.NumBytesRead() == 100); + + b.AdvanceRead(30); + REQUIRE(b.NumWriteBytes() == 0); + REQUIRE(b.NumBytesRead() == 70); + + b.AdvanceRead(70); + REQUIRE(b.NumWriteBytes() == 0); + REQUIRE(b.NumBytesRead() == 0); +} + +TEST_CASE(SUITE("Shifting")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + //initialize buffer to all zeros + for(size_t i = 0; i < b.NumWriteBytes(); ++i) b.WriteBuff()[i] = 0; + b.WriteBuff()[97] = 1; + b.WriteBuff()[98] = 2; + b.WriteBuff()[99] = 3; + + b.AdvanceWrite(100); + + b.AdvanceRead(97); + b.Shift(); +} + +TEST_CASE(SUITE("SyncNoPattern")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + for (size_t i = 0; i < b.NumWriteBytes(); ++i) + { + b.WriteBuff()[i] = 0; + } + + b.AdvanceWrite(100); + + uint32_t skipBytes = 0; + REQUIRE_FALSE(b.Sync(skipBytes)); + REQUIRE(b.NumBytesRead() == 1); // 1 byte left since need 2 bytes to sync + REQUIRE(b.NumWriteBytes() == 0); +} + +TEST_CASE(SUITE("SyncBeginning")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + for(size_t i = 0; i < b.NumWriteBytes(); ++i) b.WriteBuff()[i] = 0; + + memcpy(b.WriteBuff(), SYNC, 2); + b.AdvanceWrite(100); + + uint32_t skipBytes = 0; + REQUIRE(b.Sync(skipBytes)); + REQUIRE(b.NumBytesRead() == 100); + REQUIRE(b.NumWriteBytes() == 0); + +} + +TEST_CASE(SUITE("SyncFullPattern")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + //initialize buffer to all zeros + for(size_t i = 0; i < b.NumWriteBytes(); ++i) b.WriteBuff()[i] = 0; + uint8_t pattern[] = {0x05, 0x64}; + memcpy(b.WriteBuff() + 50, pattern, 2); //copy the pattern into the buffer + b.AdvanceWrite(100); + + uint32_t skipBytes = 0; + REQUIRE(b.Sync(skipBytes)); + REQUIRE(b.NumBytesRead() == 50); + REQUIRE(b.NumWriteBytes() == 0); +} + +TEST_CASE(SUITE("SyncPartialPattern")) +{ + Buffer buffer(100); + ShiftableBuffer b(buffer(), buffer.Size()); + + //initialize buffer to all zeros + for(size_t i = 0; i < b.NumWriteBytes(); ++i) b.WriteBuff()[i] = 0; + + b.WriteBuff()[97] = 0x05; + b.AdvanceWrite(98); + + uint32_t skipBytes = 0; + REQUIRE_FALSE(b.Sync(skipBytes)); + REQUIRE(b.NumBytesRead() == 1); + REQUIRE(b.NumWriteBytes() == 2); +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestTransportLayer.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestTransportLayer.cpp new file mode 100644 index 0000000..0c5410d --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestTransportLayer.cpp @@ -0,0 +1,273 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include "mocks/TransportTestObject.h" + +#include +#include + +#include +#include + +using namespace std; +using namespace openpal; +using namespace opendnp3; +using namespace testlib; + +#define SUITE(name) "TransportLayerTestSuite - " name + +TEST_CASE(SUITE("RepeatSendsDoNotLogOrChangeStatistics")) +{ + MockLogHandler log; + TransportTx tx(log.logger); + HexSequence hs("12 34 56"); + tx.Configure(hs.ToRSlice()); + + auto segment1 = tx.GetSegment(); + REQUIRE("C0 12 34 56" == ToHex(segment1)); + REQUIRE(tx.Statistics().numTransportTx == 1); + + auto segment2 = tx.GetSegment(); + REQUIRE("C0 12 34 56" == ToHex(segment2)); + REQUIRE(tx.Statistics().numTransportTx == 1); +} + +// make sure an invalid state exception gets thrown +// for every event other than LowerLayerUp() since +// the layer starts in the online state +TEST_CASE(SUITE("StateOffline")) +{ + TransportTestObject test; + + REQUIRE_FALSE(test.upper.SendDown("00")); + REQUIRE_FALSE(test.link.SendUp("")); + REQUIRE_FALSE(test.transport.OnSendResult(true)); + REQUIRE_FALSE(test.transport.OnLowerLayerDown()); +} + +TEST_CASE(SUITE("StateReady")) +{ + TransportTestObject test(true); //makes an implicit call to 'test.link.ThisLayerUp()' + + //check that that the transport layer is correctly forwarding up/down + REQUIRE(test.upper.IsOnline()); + test.transport.OnLowerLayerDown(); + REQUIRE_FALSE(test.upper.IsOnline()); + test.transport.OnLowerLayerUp(); + REQUIRE(test.upper.IsOnline()); + + + REQUIRE_FALSE(test.transport.OnLowerLayerUp()); + REQUIRE_FALSE(test.transport.OnSendResult(true)); +} + +TEST_CASE(SUITE("AllowsHeaderOnlyFinalFrame")) +{ + TransportTestObject test(true); + + test.link.SendUp("41 DE AD BE EF"); + test.link.SendUp("82"); + + REQUIRE(test.upper.GetBufferAsHexString() == "DE AD BE EF"); +} + +TEST_CASE(SUITE("ReceiveNoFIR")) +{ + TransportTestObject test(true); + //try sending a non-FIR w/ no prior packet + test.link.SendUp("80 77"); // _/FIN + REQUIRE(test.transport.GetStatistics().rx.numTransportIgnore == 1); +} + +TEST_CASE(SUITE("ReceiveWrongSequence")) +{ + TransportTestObject test(true); + //send a FIR, followed by a FIN w/ the wrong sequence + test.link.SendUp(test.GetData("40")); // FIR/_/0 + test.link.SendUp(test.GetData("82")); // _/FIN/2 + REQUIRE(test.transport.GetStatistics().rx.numTransportIgnore == 1); +} + +TEST_CASE(SUITE("PacketsCanBeOfVaryingSize")) +{ + TransportTestObject test(true); + test.link.SendUp("40 0A 0B 0C"); // FIR/_/0 + test.link.SendUp("81 0D 0E 0F"); // _/FIN/1 + REQUIRE("0A 0B 0C 0D 0E 0F" == test.upper.GetBufferAsHexString()); +} + +TEST_CASE(SUITE("ReceiveSinglePacket")) +{ + TransportTestObject test(true); + //now try receiving 1 a single FIR/FIN with a magic value + test.link.SendUp("C0 77"); + REQUIRE("77" == test.upper.GetBufferAsHexString()); +} + +TEST_CASE(SUITE("ReceiveLargestPossibleAPDU")) +{ + TransportTestObject test(true); + + uint32_t num_packets = CalcMaxPackets(opendnp3::DEFAULT_MAX_APDU_SIZE, MAX_TPDU_PAYLOAD); + uint32_t last_packet_length = CalcLastPacketSize(opendnp3::DEFAULT_MAX_APDU_SIZE, MAX_TPDU_PAYLOAD); + + vector packets; + string apdu = test.GeneratePacketSequence(packets, num_packets, last_packet_length); + for(string s : packets) + { + test.link.SendUp(s); + } + + REQUIRE(test.upper.BufferEqualsHex(apdu)); //check that the correct data was written +} + +TEST_CASE(SUITE("ReceiveBufferOverflow")) +{ + TransportTestObject test(true, 4); // maximum ASDU size of 4 + + REQUIRE(test.link.SendUp("40 11 22 33")); // FIN = 0, FIR = 1, SEQ = 0 + + { + auto stats = test.transport.GetStatistics().rx; + REQUIRE(stats.numTransportRx == 1); + REQUIRE(stats.numTransportBufferOverflow == 0); + } + + REQUIRE(test.link.SendUp("81 44 55")); // FIN = 0, FIR = 1, SEQ = 1 + + { + auto stats = test.transport.GetStatistics().rx; + REQUIRE(stats.numTransportRx == 2); + REQUIRE(stats.numTransportBufferOverflow == 1); + } +} + +TEST_CASE(SUITE("ReceiveNewFir")) +{ + TransportTestObject test(true); + + test.link.SendUp(test.GetData("40")); // FIR/_/0 + REQUIRE(test.upper.IsBufferEmpty()); + + test.link.SendUp("C0 AB CD"); // FIR/FIN/0 + REQUIRE("AB CD" == test.upper.GetBufferAsHexString()); + REQUIRE(test.transport.GetStatistics().rx.numTransportDiscard == 1); +} + +TEST_CASE(SUITE("StateSending")) +{ + TransportTestObject test(true); + + // this puts the layer into the Sending state + REQUIRE(test.upper.SendDown("11")); + REQUIRE("C0 11" == test.link.PopWriteAsHex()); //FIR/FIN SEQ=0 + + // Check that while we're sending, all other send requests are rejected + REQUIRE_FALSE(test.upper.SendDown("00")); + + REQUIRE_FALSE(test.transport.OnLowerLayerUp()); + + //while we are sending, we should still be able to receive data as normal + test.link.SendUp("C0 77"); + test.upper.BufferEqualsHex("77"); + + //this should put us back in the Ready state since it was a single tpdu send + test.transport.OnSendResult(true); + REQUIRE(test.upper.GetState().mSuccessCnt == 1); + + REQUIRE_FALSE(test.transport.OnSendResult(true)); +} + +TEST_CASE(SUITE("SendFailure")) +{ + TransportTestObject test(true); + + // this puts the layer into the Sending state + test.upper.SendDown("11"); + REQUIRE("C0 11" == test.link.PopWriteAsHex()); //FIR/FIN SEQ=0 + + //this should put us back in the Ready state + test.transport.OnSendResult(false); + REQUIRE(test.upper.GetState().mSuccessCnt == 0); + REQUIRE(test.upper.GetState().mFailureCnt == 1); + + test.upper.SendDown("11"); + REQUIRE("C1 11" == test.link.PopWriteAsHex()); // use next sequence number FIR/FIN SEQ=1 + test.transport.OnSendResult(true); + REQUIRE(test.upper.GetState().mSuccessCnt == 1); + REQUIRE(test.upper.GetState().mFailureCnt == 1); +} + +TEST_CASE(SUITE("SendSuccess")) +{ + TransportTestObject test(true); + + // this puts the layer into the Sending state + test.upper.SendDown("11"); + REQUIRE("C0 11" == test.link.PopWriteAsHex()); //FIR/FIN SEQ=0 + test.transport.OnSendResult(true); + + // this puts the layer into the Sending state + test.upper.SendDown("11"); + REQUIRE("C1 11" == test.link.PopWriteAsHex()); //FIR/FIN SEQ=1 + test.transport.OnSendResult(true); + REQUIRE(test.upper.GetState().mSuccessCnt == 2); +} + +//if we're in the middle of a send and the layer goes down +TEST_CASE(SUITE("ClosedWhileSending")) +{ + TransportTestObject test(true); + test.upper.SendDown("11"); //get the layer into the sending state + + test.transport.OnLowerLayerDown(); + REQUIRE_FALSE(test.upper.IsOnline()); +} + +TEST_CASE(SUITE("SendFullAPDU")) +{ + TransportTestObject test(true); + + uint32_t numPackets = CalcMaxPackets(opendnp3::DEFAULT_MAX_APDU_SIZE, MAX_TPDU_PAYLOAD); + uint32_t lastPacketLength = CalcLastPacketSize(opendnp3::DEFAULT_MAX_APDU_SIZE, MAX_TPDU_PAYLOAD); + + vector packets; + std::string apdu = test.GeneratePacketSequence(packets, numPackets, lastPacketLength); + + test.upper.SendDown(apdu); + + // 9 total packets + REQUIRE(numPackets == test.link.sends.size()); + REQUIRE(packets.size() == test.link.sends.size()); + + for (size_t i = 0; i < packets.size(); ++i) + { + REQUIRE(packets[i] == test.link.PopWriteAsHex()); + } + + test.transport.OnSendResult(true); +} + + + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestTypedCommandHeader.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestTypedCommandHeader.cpp new file mode 100644 index 0000000..07222f4 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestTypedCommandHeader.cpp @@ -0,0 +1,101 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace opendnp3; +using namespace openpal; +using namespace testlib; + +std::string WriteToHex(const CommandSet& set); + +#define SUITE(name) "TypedCommandHeaderTestSuite - " name + +TEST_CASE(SUITE("Can instantiate a CROB header")) +{ + TypedCommandHeader header(Group12Var1::Inst()); +} + +TEST_CASE(SUITE("Formats properly if enough space is available")) +{ + TypedCommandHeader header(Group41Var2::Inst()); + header.Add(AnalogOutputInt16(7), 10); + header.Add(AnalogOutputInt16(8), 11); + + StaticBuffer<100> buffer; + auto dest = buffer.GetWSlice(); + APDURequest request(dest); + auto writer = request.GetWriter(); + + REQUIRE(header.Write(writer)); + + auto hex = ToHex(request.ToRSlice().Skip(2)); + + REQUIRE(hex == "29 02 28 02 00 0A 00 07 00 00 0B 00 08 00 00"); +} + +TEST_CASE(SUITE("Does not format if insufficient space")) +{ + TypedCommandHeader header(Group41Var2::Inst()); + header.Add(AnalogOutputInt16(7), 10); + header.Add(AnalogOutputInt16(8), 11); + + StaticBuffer<14> buffer; + auto dest = buffer.GetWSlice(); + APDURequest request(dest); + auto writer = request.GetWriter(); + + REQUIRE_FALSE(header.Write(writer)); +} + +TEST_CASE(SUITE("Command set can be moved and written")) +{ + CommandSet commands; + + commands.Add({ WithIndex(AnalogOutputInt16(7), 10) }); + commands.Add({ WithIndex(AnalogOutputInt32(8), 11) }); + + CommandSet commands2(std::move(commands)); + + REQUIRE(WriteToHex(commands) == ""); + REQUIRE(WriteToHex(commands2) == "29 02 28 01 00 0A 00 07 00 00 29 01 28 01 00 0B 00 08 00 00 00 00"); +} + +std::string WriteToHex(const CommandSet& commands) +{ + StaticBuffer<100> buffer; + auto dest = buffer.GetWSlice(); + APDURequest request(dest); + auto writer = request.GetWriter(); + + REQUIRE(CommandSetOps::Write(commands, writer)); + return ToHex(request.ToRSlice().Skip(2)); +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestTypes.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestTypes.cpp new file mode 100644 index 0000000..b30b3c0 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestTypes.cpp @@ -0,0 +1,86 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +using namespace std; + +#undef max +#undef min + +template +void TestType(T min, T max, size_t numBytes) +{ + REQUIRE((sizeof(T) == numBytes)); + + T val = min; + T limit = numeric_limits::min(); + REQUIRE((val == limit)); + + val = max; + limit = numeric_limits::max(); + REQUIRE((val == limit)); +} + +#define SUITE(name) "TestTypes - " name + +TEST_CASE(SUITE(" UByte ")) +{ + TestType(0, 255, 1); +} + +TEST_CASE(SUITE(" Int16 ")) +{ + TestType(-32768, 32767, 2); +} + +TEST_CASE(SUITE(" UInt16 ")) +{ + TestType(0, 65535, 2); +} + +TEST_CASE(SUITE(" Int32 ")) +{ + TestType(0x80000000, 2147483647L, 4); +} + +TEST_CASE(SUITE(" UInt32 ")) +{ + TestType(0, 4294967295UL, 4); +} + +TEST_CASE(SUITE(" Int64")) +{ + TestType(0x8000000000000000LL, 9223372036854775807LL, 8); +} + +TEST_CASE(SUITE("Float")) +{ + REQUIRE(4 == sizeof(float)); +} + +TEST_CASE(SUITE("Double")) +{ + REQUIRE(8 == sizeof(double)); +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestUtil.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestUtil.cpp new file mode 100644 index 0000000..9e2769e --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestUtil.cpp @@ -0,0 +1,67 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +using namespace std; +using namespace testlib; + + +#define SUITE(name) "UtilSuite - " name +template +void TestHex(const std::string& hex, uint8_t* compareBytes, size_t count) +{ + HexSequence hs(hex); + + REQUIRE(hs.Size() <= N); + + REQUIRE((hs.Size() == count)); + for ( size_t i = 0; i < count; i++ ) + { + REQUIRE((hs[i] == compareBytes[i])); + } +} + +TEST_CASE(SUITE("HexToBytes2TestSmall")) +{ + uint8_t values[] = { 0xAF, 0x23 }; + TestHex<2>( "AF23", values, 2 ); +} +TEST_CASE(SUITE("HexToBytes2Test64")) +{ + uint8_t values[] = { 0x13, 0xA2, 0x00, 0x40, 0x56, 0x1D, 0x08 }; + TestHex<7>( "13A20040561D08", values, 7 ); +} + +TEST_CASE(SUITE("HexToBytes2Test64TooBig")) +{ + uint8_t values[] = { 0x13, 0xA2, 0x00, 0x40, 0x56, 0x1D, 0x08 }; + TestHex<8>( "13A20040561D08", values, 7 ); +} + +TEST_CASE(SUITE("HexToBytes2Test64Hole")) +{ + uint8_t values[] = { 0x13, 0xA2, 0x00, 0x40, 0x56, 0x1D, 0x08 }; + TestHex<8>( "13A200 40561 D08", values, 7 ); +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/TestWriteConversions.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/TestWriteConversions.cpp new file mode 100644 index 0000000..5eda971 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/TestWriteConversions.cpp @@ -0,0 +1,58 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +using namespace opendnp3; + +#define SUITE(name) "WriteConversionTestSuite - " name + +TEST_CASE(SUITE("Group30Var2ConvertsWithinRange")) +{ + Analog a(12); + auto gv = ConvertGroup30Var2::Apply(a); + + REQUIRE(gv.value == 12); + REQUIRE(gv.flags == ToUnderlying(AnalogQuality::ONLINE)); +} + +TEST_CASE(SUITE("Group30Var2ConvertsOverrange")) +{ + Analog a(32768); + auto gv = ConvertGroup30Var2::Apply(a); + + REQUIRE(gv.value == 32767); + REQUIRE(gv.flags == (ToUnderlying(AnalogQuality::ONLINE) | ToUnderlying(AnalogQuality::OVERRANGE))); +} + +TEST_CASE(SUITE("Group30Var2ConvertsUnderrange")) +{ + Analog a(-32769); + auto gv = ConvertGroup30Var2::Apply(a); + + REQUIRE(gv.value == -32768); + REQUIRE(gv.flags == (ToUnderlying(AnalogQuality::ONLINE) | ToUnderlying(AnalogQuality::OVERRANGE))); +} + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.cpp new file mode 100644 index 0000000..0404344 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "APDUHelpers.h" + +uint8_t APDUHelpers::fixedBuffer[SIZE]; + +opendnp3::APDURequest APDUHelpers::Request(opendnp3::FunctionCode code, uint32_t size) +{ + assert(size <= SIZE); + openpal::WSlice buffer(fixedBuffer, size); + opendnp3::APDURequest request(buffer); + request.SetFunction(code); + request.SetControl(opendnp3::AppControlField(true, true, false, false, 0)); + return request; +} + +opendnp3::APDUResponse APDUHelpers::Response(uint32_t size) +{ + assert(size <= SIZE); + openpal::WSlice buffer(fixedBuffer, size); + opendnp3::APDUResponse response(buffer); + response.SetFunction(opendnp3::FunctionCode::RESPONSE); + response.SetControl(opendnp3::AppControlField(true, true, false, false, 0)); + response.SetIIN(opendnp3::IINField::Empty()); + return response; +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.h new file mode 100644 index 0000000..a545551 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/APDUHelpers.h @@ -0,0 +1,43 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __APDU_HELPERS_H_ +#define __APDU_HELPERS_H_ + +#include +#include +#include + +#include + +class APDUHelpers : private openpal::StaticOnly +{ +private: + static const uint32_t SIZE = 2048; + static uint8_t fixedBuffer[2048]; + +public: + + static opendnp3::APDURequest Request(opendnp3::FunctionCode code, uint32_t size = SIZE); + + static opendnp3::APDUResponse Response(uint32_t size = SIZE); +}; + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.cpp new file mode 100644 index 0000000..e967993 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.cpp @@ -0,0 +1,74 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "BufferSegment.h" + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ + +BufferSegment::BufferSegment(uint32_t segmentSize_, const std::string& hex) : + segmentSize(segmentSize_), + hs(hex), + remainder(hs.ToRSlice()) +{ + assert(segmentSize > 0); +} + +void BufferSegment::Reset() +{ + remainder = hs.ToRSlice(); +} + +bool BufferSegment::HasValue() const +{ + return remainder.Size() > 0; +} + +openpal::RSlice BufferSegment::GetSegment() +{ + auto size = std::min(segmentSize, remainder.Size()); + auto chunk = remainder.Take(size); + return chunk; +} + +bool BufferSegment::Advance() +{ + auto size = std::min(segmentSize, remainder.Size()); + remainder.Advance(size); + return remainder.IsNotEmpty(); +} + +} + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.h new file mode 100644 index 0000000..73edd26 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/BufferSegment.h @@ -0,0 +1,55 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __BUFFER_SEGMENT_H_ +#define __BUFFER_SEGMENT_H_ + +#include +#include + +#include + +namespace opendnp3 +{ + +class BufferSegment : public ITransportSegment +{ +public: + + BufferSegment(uint32_t segmentSize, const std::string& hex); + + virtual bool HasValue() const override final; + + virtual openpal::RSlice GetSegment() override final; + + virtual bool Advance() override final; + + void Reset(); + +private: + uint32_t segmentSize; + testlib::HexSequence hs; + openpal::RSlice remainder; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.cpp new file mode 100644 index 0000000..45b2db9 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.cpp @@ -0,0 +1,75 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "DNPHelpers.h" + +#include + +#include +#include + +#include + +#include +#include + +using namespace testlib; + +namespace opendnp3 +{ + +std::string RepairCRC(const std::string& arData) +{ + HexSequence hs(arData); + + //validate the size of the data + REQUIRE(hs.Size() >= 10); + REQUIRE(hs.Size() <= 292); + + //first determine how much user data is present + uint32_t full_blocks = (hs.Size() - 10) / 18; + uint32_t partial_size = (hs.Size() - 10) % 18; + + //can't have a partial size < 3 since even 1 byte requires 2 CRC bytes + if(partial_size > 0) + { + REQUIRE(partial_size >= 3); + } + + //repair the header crc + CRC::AddCrc(hs, 8); + + uint8_t* ptr = hs + 10; + + // repair the full blocks + for(size_t i = 0; i < full_blocks; i++) + { + CRC::AddCrc(ptr, 16); + ptr += 18; + } + + //repair the partial block + if (partial_size > 0) CRC::AddCrc(ptr, partial_size - 2); + + return testlib::ToHex(hs.ToRSlice(), true); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.h new file mode 100644 index 0000000..42bdb64 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DNPHelpers.h @@ -0,0 +1,39 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __DNP_HELPERS_H_ +#define __DNP_HELPERS_H_ + +#include + + +namespace opendnp3 +{ + +class LinkFrame; + +std::string RepairCRC(const std::string& arData); + +std::string ToHex(LinkFrame& frame); + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DatabaseTestObject.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DatabaseTestObject.h new file mode 100644 index 0000000..03c631e --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/DatabaseTestObject.h @@ -0,0 +1,100 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __DATABASE_TEST_OBJECT_H_ +#define __DATABASE_TEST_OBJECT_H_ + +#include + +#include +#include + +namespace opendnp3 +{ + +class MockEventBuffer final : public IEventReceiver +{ +public: + + void Update(const Event& evt) override + { + binaryEvents.push_back(evt); + } + + void Update(const Event& evt) override + { + doubleBinaryEvents.push_back(evt); + } + + void Update(const Event& evt) override + { + analogEvents.push_back(evt); + } + + void Update(const Event& evt) override + { + counterEvents.push_back(evt); + } + + void Update(const Event& evt) override + { + frozenCounterEvents.push_back(evt); + } + + void Update(const Event& evt) override + { + binaryOutputStatusEvents.push_back(evt); + } + + void Update(const Event& evt) override + { + analogOutputStatusEvents.push_back(evt); + } + + std::deque> binaryEvents; + std::deque> doubleBinaryEvents; + std::deque> analogEvents; + std::deque> counterEvents; + std::deque> frozenCounterEvents; + std::deque> binaryOutputStatusEvents; + std::deque> analogOutputStatusEvents; + std::deque> securityStatEvents; +}; + +class DatabaseTestObject +{ +public: + + DatabaseTestObject(const DatabaseSizes& dbSizes, IndexMode mode = IndexMode::Contiguous, StaticTypeBitField allowedClass0 = StaticTypeBitField::AllTypes()) : + buffer(), + db(dbSizes, buffer, mode, allowedClass0) + { + + } + + + MockEventBuffer buffer; + Database db; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/FanoutDataObserver.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/FanoutDataObserver.h new file mode 100644 index 0000000..f74df71 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/FanoutDataObserver.h @@ -0,0 +1,91 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __FANOUT_DATA_OBSERVER_H_ +#define __FANOUT_DATA_OBSERVER_H_ + +#include + +#include + +namespace opendnp3 +{ + +class FanoutDataObserver : public IMeasurementLoader +{ +public: + + void AddObserver(IMeasurementLoader* apObserver) + { + mObservers.push_back(apObserver); + } + + void Start() + { + for (auto pObs : mObservers) openpal::Transaction::Start(pObs); + } + + void End() + { + for (auto pObs : mObservers) openpal::Transaction::End(pObs); + } + + void Update(const Binary& arPoint, uint16_t aIndex) override final + { + for(auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + + void Update(const DoubleBitBinary& arPoint, uint16_t aIndex) override final + { + for (auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + + void Update(const Analog& arPoint, uint16_t aIndex) override final + { + for(auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + + void Update(const Counter& arPoint, uint16_t aIndex) override final + { + for(auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + + void Update(const FrozenCounter& arPoint, uint16_t aIndex) override final + { + for(auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + + void Update(const BinaryOutputStatus& arPoint, uint16_t aIndex) override final + { + for(auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + void Update(const AnalogOutputStatus& arPoint, uint16_t aIndex) override final + { + for(auto pObs : mObservers) pObs->Update(arPoint, aIndex); + } + +private: + std::vector mObservers; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.cpp new file mode 100644 index 0000000..d84ab46 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.cpp @@ -0,0 +1,106 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkHex.h" + +#include +#include + +#include +#include + +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ +std::string LinkHex::Ack(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatAck(ouput, master, isRxBuffFull, dest, src, nullptr)); +} + +std::string LinkHex::Nack(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatNack(ouput, master, isRxBuffFull, dest, src, nullptr)); +} + +std::string LinkHex::LinkStatus(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatLinkStatus(ouput, master, isRxBuffFull, dest, src, nullptr)); +} + +std::string LinkHex::NotSupported(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatNotSupported(ouput, master, isRxBuffFull, dest, src, nullptr)); +} + +std::string LinkHex::TestLinkStatus(bool master, bool fcb, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatTestLinkStatus(ouput, master, fcb, dest, src, nullptr)); +} + +std::string LinkHex::ResetLinkStates(bool master, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatResetLinkStates(ouput, master, dest, src, nullptr)); +} + +std::string LinkHex::RequestLinkStatus(bool master, uint16_t dest, uint16_t src) +{ + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatRequestLinkStatus(ouput, master, dest, src, nullptr)); +} + +std::string LinkHex::ConfirmedUserData(bool master, bool fcb, uint16_t dest, uint16_t src, const std::string& userDataHex) +{ + HexSequence hs(userDataHex); + auto data = hs.ToRSlice(); + + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatConfirmedUserData(ouput, master, fcb, dest, src, data, data.Size(), nullptr)); +} + +std::string LinkHex::UnconfirmedUserData(bool master, uint16_t dest, uint16_t src, const std::string& userDataHex) +{ + HexSequence hs(userDataHex); + auto data = hs.ToRSlice(); + + StaticBuffer<292> buffer; + auto ouput = buffer.GetWSlice(); + return ToHex(LinkFrame::FormatUnconfirmedUserData(ouput, master, dest, src, data, data.Size(), nullptr)); +} + +} + + + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.h new file mode 100644 index 0000000..40f7e90 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkHex.h @@ -0,0 +1,63 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef OPENDNP3_LINK_HEX_H +#define OPENDNP3_LINK_HEX_H + +#include "opendnp3/gen/FunctionCode.h" +#include "opendnp3/gen/LinkFunction.h" + +#include +#include + +#include + +namespace opendnp3 +{ + +class LinkHex : private openpal::StaticOnly +{ + +public: + + //////////////////////////////////////////////// + // Functions for formatting outgoing Sec to Pri frames + //////////////////////////////////////////////// + + static std::string Ack(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src); + static std::string Nack(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src); + static std::string LinkStatus(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src); + static std::string NotSupported(bool master, bool isRxBuffFull, uint16_t dest, uint16_t src); + + //////////////////////////////////////////////// + // Functions for formatting outgoing Pri to Sec frames + //////////////////////////////////////////////// + + static std::string TestLinkStatus(bool master, bool fcb, uint16_t dest, uint16_t src); + static std::string ResetLinkStates(bool master, uint16_t dest, uint16_t src); + static std::string RequestLinkStatus(bool master, uint16_t dest, uint16_t src); + static std::string ConfirmedUserData(bool master, bool fcb, uint16_t dest, uint16_t src, const std::string& userDataHex); + static std::string UnconfirmedUserData(bool master, uint16_t dest, uint16_t src, const std::string& userDataHex); +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.cpp new file mode 100644 index 0000000..5f29dd2 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.cpp @@ -0,0 +1,83 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "LinkLayerTest.h" + +#include + +using namespace testlib; +using namespace openpal; + +namespace opendnp3 +{ + +LinkLayerTest::LinkLayerTest(LinkConfig config) : + log(), + exe(std::make_shared()), + listener(std::make_shared()), + upper(std::make_shared()), + link(log.logger, exe, upper, listener, config), + numTotalWrites(0) +{ + upper->SetLinkLayer(link); + link.SetRouter(*this); +} + +bool LinkLayerTest::OnFrame(LinkFunction func, bool isMaster, bool fcb, bool fcvdfc, uint16_t dest, uint16_t source, const openpal::RSlice& userdata) +{ + LinkHeaderFields fields(func, isMaster, fcb, fcvdfc, dest, source); + return link.OnFrame(fields, userdata); +} + +std::string LinkLayerTest::PopLastWriteAsHex() +{ + if (writeQueue.empty()) + { + return ""; + } + + while (writeQueue.size() > 1) + { + writeQueue.pop_front(); + } + + auto ret = writeQueue.front(); + writeQueue.pop_front(); + return ret; +} + +uint32_t LinkLayerTest::NumTotalWrites() +{ + return numTotalWrites; +} + +void LinkLayerTest::BeginTransmit(const openpal::RSlice& buffer, ILinkSession&) +{ + ++numTotalWrites; + this->writeQueue.push_back(ToHex(buffer)); +} + +LinkConfig LinkLayerTest::DefaultConfig() +{ + return LinkConfig(true, false); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.h new file mode 100644 index 0000000..852001c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkLayerTest.h @@ -0,0 +1,73 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __LINK_LAYER_TEST_H_ +#define __LINK_LAYER_TEST_H_ + +#include "MockTransportLayer.h" + +#include + +#include "testlib/MockExecutor.h" +#include "testlib/MockLogHandler.h" + +#include +#include +#include + +#include + +namespace opendnp3 +{ + +class LinkLayerTest : public ILinkTx +{ +public: + + LinkLayerTest(LinkConfig config = DefaultConfig()); + + bool OnFrame(LinkFunction func, bool isMaster, bool fcb, bool fcvdfc, uint16_t dest, uint16_t source, const openpal::RSlice& userdata = openpal::RSlice::Empty()); + + //ILinkTx interface + virtual void BeginTransmit(const openpal::RSlice& buffer, ILinkSession& context) override final; + + static LinkConfig DefaultConfig(); + + testlib::MockLogHandler log; + std::shared_ptr exe; + std::shared_ptr listener; + std::shared_ptr upper; + + LinkLayer link; + + std::string PopLastWriteAsHex(); + uint32_t NumTotalWrites(); + +private: + + uint32_t numTotalWrites; + + std::deque writeQueue; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkReceiverTest.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkReceiverTest.h new file mode 100644 index 0000000..cc1de85 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/LinkReceiverTest.h @@ -0,0 +1,72 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __LINK_PARSER_TEST_H_ +#define __LINK_PARSER_TEST_H_ + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace opendnp3 +{ + +class LinkParserTest +{ +public: + LinkParserTest(bool aImmediate = false) : + log(), + sink(), + parser(log.logger) + {} + + void WriteData(const openpal::RSlice& input) + { + auto buff = parser.WriteBuff(); + assert(input.Size() <= buff.Size()); + input.CopyTo(buff); + parser.OnRead(input.Size(), sink); + } + + void WriteData(const std::string& hex) + { + testlib::HexSequence hs(hex); + auto buff = parser.WriteBuff(); + assert(hs.Size() <= buff.Size()); + memcpy(buff, hs, hs.Size()); + parser.OnRead(hs.Size(), sink); + } + + testlib::MockLogHandler log; + MockFrameSink sink; + LinkLayerParser parser; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.cpp new file mode 100644 index 0000000..a633d4f --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.cpp @@ -0,0 +1,57 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MasterTestObject.h" + +#include + +#include + +using namespace testlib; + +namespace opendnp3 +{ + +MasterParams NoStartupTasks() +{ + MasterParams params; + params.disableUnsolOnStartup = false; + params.startupIntegrityClassMask = 0; + params.unsolClassMask = 0; + return params; +} + +MasterTestObject::MasterTestObject(const MasterParams& params, ITaskLock& lock) : + log(), + exe(std::make_shared()), + meas(std::make_shared()), + lower(std::make_shared()), + application(std::make_shared()), + context(std::make_shared(log.logger, exe, lower, meas, application, params, lock)) +{} + +void MasterTestObject::SendToMaster(const std::string& hex) +{ + HexSequence hs(hex); + context->OnReceive(hs.ToRSlice()); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.h new file mode 100644 index 0000000..a72e65b --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MasterTestObject.h @@ -0,0 +1,59 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MASTER_TEST_OBJECT_H_ +#define __MASTER_TEST_OBJECT_H_ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace opendnp3 +{ + +MasterParams NoStartupTasks(); + +class MasterTestObject +{ +public: + + MasterTestObject(const MasterParams& params, ITaskLock& lock = NullTaskLock::Instance()); + + void SendToMaster(const std::string& hex); + + testlib::MockLogHandler log; + std::shared_ptr exe; + std::shared_ptr meas; + std::shared_ptr lower; + std::shared_ptr application; + std::shared_ptr context; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MeasurementComparisons.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MeasurementComparisons.h new file mode 100644 index 0000000..a0890ab --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MeasurementComparisons.h @@ -0,0 +1,64 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MEASUREMENT_COMPARISONS_H_ +#define __MEASUREMENT_COMPARISONS_H_ + +#include +#include + +#include + +template +bool Equals(const opendnp3::TypedMeasurement& lhs, const opendnp3::TypedMeasurement& rhs) +{ + return + (lhs.flags.value == rhs.flags.value) && + (lhs.value == rhs.value) && + (lhs.time == rhs.time); +} + +template +bool operator==(const opendnp3::TypedMeasurement& lhs, const opendnp3::TypedMeasurement& rhs) +{ + return Equals(lhs, rhs); +} + +template +bool operator!=(const opendnp3::TypedMeasurement& lhs, const opendnp3::TypedMeasurement& rhs) +{ + return !Equals(lhs, rhs); +} + +template +bool operator==(const opendnp3::Indexed& lhs, const opendnp3::Indexed& rhs) +{ + return (lhs.value == rhs.value) && (lhs.index == rhs.index); +} + +template +bool operator==(const opendnp3::Event& lhs, const opendnp3::Event& rhs) +{ + return (lhs.clazz == rhs.clazz) && (lhs.value == rhs.value) && (lhs.index == rhs.index); +} + + + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockAPDUHeaderHandler.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockAPDUHeaderHandler.h new file mode 100644 index 0000000..2c46617 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockAPDUHeaderHandler.h @@ -0,0 +1,245 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_APDU_HEADER_HANDLER_H_ +#define __MOCK_APDU_HEADER_HANDLER_H_ + +#include + +#include + +namespace opendnp3 +{ + +class MockApduHeaderHandler : public IAPDUHandler +{ +public: + + virtual bool IsAllowed(uint32_t headerCount, GroupVariation gv, QualifierCode qc) override final + { + return true; + } + + virtual void OnHeaderResult(const HeaderRecord& record, const IINField& result) override final + { + records.push_back(record); + } + + virtual IINField ProcessHeader(const CountHeader& header, const ICollection& values) override final + { + return ProcessAny(header, values, authStatusRequests); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, iinBits); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, staticBinaries); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, staticDoubleBinaries); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, staticControlStatii); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, staticCounters); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, staticFrozenCounters); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, eventAnalogs); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, staticSetpointStatii); + } + + virtual IINField ProcessHeader(const RangeHeader& header, const ICollection>& values) override final + { + return ProcessAny(header, values, rangedOctets); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, eventBinaries); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, eventDoubleBinaries); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, eventCounters); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, eventFrozenCounters); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, eventAnalogs); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, indexPrefixedOctets); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, binaryCommandEvents); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& values) override final + { + return this->ProcessAny(header, values, analogCommandEvents); + } + + /// --- controls ---- + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final + { + return this->ProcessAny(header, meas, crobRequests); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final + { + return this->ProcessAny(header, meas, aoInt16Requests); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final + { + return this->ProcessAny(header, meas, aoInt32Requests); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final + { + return this->ProcessAny(header, meas, aoFloat32Requests); + } + + virtual IINField ProcessHeader(const PrefixHeader& header, const ICollection>& meas) override final + { + return this->ProcessAny(header, meas, aoDouble64Requests); + } + + virtual IINField ProcessHeader(const opendnp3::FreeFormatHeader& header, const Group120Var1& value, const openpal::RSlice& object) override final + { + authChallenges.push_back(value); + return IINField::Empty(); + } + + virtual IINField ProcessHeader(const opendnp3::FreeFormatHeader& header, const Group120Var2& value, const openpal::RSlice& object) override final + { + authReplys.push_back(value); + return IINField::Empty(); + } + + virtual IINField ProcessHeader(const opendnp3::FreeFormatHeader& header, const Group120Var5& value, const openpal::RSlice& object) override final + { + authKeyStatusResponses.push_back(value); + return IINField::Empty(); + } + + virtual IINField ProcessHeader(const opendnp3::FreeFormatHeader& header, const Group120Var6& value, const openpal::RSlice& object) override final + { + authChanges.push_back(value); + return IINField::Empty(); + } + + std::vector records; + + std::vector authChallenges; + std::vector authReplys; + std::vector authStatusRequests; + std::vector authKeyStatusResponses; + std::vector authChanges; + + std::vector> iinBits; + + std::vector> eventBinaries; + std::vector> staticBinaries; + + std::vector> eventDoubleBinaries; + std::vector> staticDoubleBinaries; + + std::vector> staticControlStatii; + + std::vector> eventCounters; + std::vector> staticCounters; + + std::vector> eventFrozenCounters; + std::vector> staticFrozenCounters; + + std::vector> eventAnalogs; + std::vector> staticAnalogs; + + std::vector> staticSetpointStatii; + + std::vector> crobRequests; + + std::vector> aoInt16Requests; + std::vector> aoInt32Requests; + std::vector> aoFloat32Requests; + std::vector> aoDouble64Requests; + + std::vector> indexPrefixedOctets; + std::vector> rangedOctets; + + std::vector> binaryCommandEvents; + + std::vector> analogCommandEvents; + +private: + + template + IINField ProcessAny(const HeaderRecord& record, const ICollection& meas, std::vector& items) + { + auto add = [&items](const T & v) + { + items.push_back(v); + }; + meas.ForeachItem(add); + return IINField::Empty(); + } +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockLinkLayer.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockLinkLayer.h new file mode 100644 index 0000000..1bc7a09 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockLinkLayer.h @@ -0,0 +1,75 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_LINK_LAYER_H_ +#define __MOCK_LINK_LAYER_H_ + +#include + +#include +#include + +#include +#include + +namespace opendnp3 +{ + +class MockLinkLayer : public ILinkLayer, public HasUpperLayer +{ + +public: + + virtual bool Send(ITransportSegment& segments) override final + { + while (segments.HasValue()) + { + sends.push_back(testlib::ToHex(segments.GetSegment())); + segments.Advance(); + } + + return true; + } + + std::string PopWriteAsHex() + { + assert(!sends.empty()); + auto ret = sends.front(); + sends.erase(sends.begin()); + return ret; + } + + bool SendUp(const std::string& hex) + { + testlib::HexSequence hs(hex); + if (pUpperLayer) + { + auto buffer = hs.ToRSlice(); + return pUpperLayer->OnReceive(buffer); + } + return false; + } + + std::vector sends; +}; + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.cpp new file mode 100644 index 0000000..63ecd6a --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.cpp @@ -0,0 +1,84 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "MockTransportLayer.h" + +#include +#include + +#include + +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ + +MockTransportLayer::MockTransportLayer() : pLinkLayer(nullptr), isOnline(false) +{} + +void MockTransportLayer::SetLinkLayer(ILinkLayer& linkLayer) +{ + this->pLinkLayer = &linkLayer; +} + +bool MockTransportLayer::SendDown(ITransportSegment& segments) +{ + return pLinkLayer->Send(segments); +} + +bool MockTransportLayer::OnReceive(const openpal::RSlice& buffer) +{ + receivedQueue.push_back(ToHex(buffer)); + return true; +} + +bool MockTransportLayer::OnSendResult(bool isSuccess) +{ + if (isSuccess) + { + ++state.successCnt; + } + else + { + ++state.failureCnt; + } + + return true; +} + +bool MockTransportLayer::OnLowerLayerUp() +{ + assert(!isOnline); + isOnline = true; + ++state.numLayerUp; + return true; +} + +bool MockTransportLayer::OnLowerLayerDown() +{ + assert(isOnline); + isOnline = false; + ++state.numLayerDown; + return true; +} + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.h new file mode 100644 index 0000000..3bf92c8 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/MockTransportLayer.h @@ -0,0 +1,109 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __MOCK_LINK_LAYER_USER_H_ +#define __MOCK_LINK_LAYER_USER_H_ + +#include +#include + +#include +#include + +namespace opendnp3 +{ + +class MockTransportLayer : public IUpperLayer +{ + +public: + + struct State + { + + State() + { + Reset(); + } + + uint32_t successCnt; + uint32_t failureCnt; + uint32_t numLayerUp; + uint32_t numLayerDown; + + void Reset() + { + successCnt = failureCnt = numLayerUp = numLayerDown = 0; + } + }; + + MockTransportLayer(); + + void SetLinkLayer(ILinkLayer& linkLayer); + + bool SendDown(ITransportSegment& segments); + + bool IsOnline() const + { + return isOnline; + } + + bool CountersEqual(uint32_t success, uint32_t failure) + { + return state.successCnt == success && state.failureCnt == failure; + } + + bool StateEquals(const State& s) + { + return (state.successCnt == s.successCnt) + && (state.failureCnt == s.failureCnt) + && (state.numLayerUp == s.numLayerUp) + && (state.numLayerDown == s.numLayerDown); + } + + void Reset() + { + state.Reset(); + } + + State GetState() + { + return state; + } + + // these are the NVII delegates + virtual bool OnReceive(const openpal::RSlice& buffer) override final; + virtual bool OnSendResult(bool isSuccess) override final; + virtual bool OnLowerLayerUp() override final; + virtual bool OnLowerLayerDown() override final; + + std::deque receivedQueue; + +private: + ILinkLayer* pLinkLayer; + bool isOnline; + State state; +}; + + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.cpp new file mode 100644 index 0000000..1ba560b --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.cpp @@ -0,0 +1,93 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "OutstationTestObject.h" +#include + +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ + +OutstationTestObject::OutstationTestObject( + const OutstationConfig& config, + const DatabaseSizes& dbSizes +) : + log(), + exe(std::make_shared()), + lower(std::make_shared()), + cmdHandler(std::make_shared(CommandStatus::SUCCESS)), + application(std::make_shared()), + context(config, dbSizes, log.logger, exe, lower, cmdHandler, application) +{ + lower->SetUpperLayer(context); +} + +size_t OutstationTestObject::LowerLayerUp() +{ + context.OnLowerLayerUp(); + return exe->RunMany(); +} + +size_t OutstationTestObject::LowerLayerDown() +{ + context.OnLowerLayerDown(); + return exe->RunMany(); +} + +size_t OutstationTestObject::OnSendResult(bool isSuccess) +{ + context.OnSendResult(isSuccess); + return exe->RunMany(); +} + +size_t OutstationTestObject::SendToOutstation(const std::string& hex) +{ + HexSequence hs(hex); + context.OnReceive(hs.ToRSlice()); + return exe->RunMany(); +} + +size_t OutstationTestObject::NumPendingTimers() const +{ + return exe->NumPendingTimers(); +} + +bool OutstationTestObject::AdvanceToNextTimer() +{ + if (exe->AdvanceToNextTimer()) + { + return exe->RunMany() > 0; + } + else + { + return false; + } +} + +size_t OutstationTestObject::AdvanceTime(const openpal::TimeDuration& td) +{ + exe->AdvanceTime(td); + return exe->RunMany(); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.h new file mode 100644 index 0000000..4634177 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/OutstationTestObject.h @@ -0,0 +1,88 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __OUTSTATION_TEST_OBJECT_H_ +#define __OUTSTATION_TEST_OBJECT_H_ + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +namespace opendnp3 +{ + +class OutstationTestObject +{ + +public: + OutstationTestObject(const OutstationConfig& config, const DatabaseSizes& dbSizes = DatabaseSizes::Empty()); + + + size_t SendToOutstation(const std::string& hex); + + size_t LowerLayerUp(); + + size_t LowerLayerDown(); + + size_t OnSendResult(bool isSuccess); + + size_t NumPendingTimers() const; + + bool AdvanceToNextTimer(); + + size_t AdvanceTime(const openpal::TimeDuration& td); + + testlib::MockLogHandler log; + + void Transaction(const std::function& apply) + { + //auto& handler = context.GetUpdateHandler(); + apply(context.GetUpdateHandler()); + context.CheckForTaskStart(); + } + +private: + + const std::shared_ptr exe; + +public: + + const std::shared_ptr lower; + const std::shared_ptr cmdHandler; + const std::shared_ptr application; + OContext context; +}; + + +} + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TestHelpers.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TestHelpers.h new file mode 100644 index 0000000..ea17cbb --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TestHelpers.h @@ -0,0 +1,32 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __TEST_HELPERS_H_ +#define __TEST_HELPERS_H_ + +#define BOOST_REQUIRE_FLOAT_EQUAL_TOL(a,b,tol) BOOST_REQUIRE(FloatEqual(a,b,tol)) + +#define BOOST_REQUIRE_FLOAT_EQUAL(a,b) BOOST_REQUIRE(FloatEqual(a,b,1e-6)) + +#define BOOST_REQUIRE_NOT_EQUAL(a,b) BOOST_REQUIRE(a != b) + +#define BOOST_REQUIRE_FALSE(a) BOOST_REQUIRE(!a) + +#endif diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.cpp b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.cpp new file mode 100644 index 0000000..9a8981b --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.cpp @@ -0,0 +1,90 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include "TransportTestObject.h" + +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace openpal; +using namespace testlib; + +namespace opendnp3 +{ + +TransportTestObject::TransportTestObject(bool openOnStart, uint32_t maxRxFragmentSize) : + log(), + exe(), + transport(log.logger, maxRxFragmentSize) +{ + link.SetUpperLayer(transport); + transport.SetLinkLayer(link); + + upper.SetLowerLayer(transport); + transport.SetAppLayer(upper); + + if (openOnStart) + { + transport.OnLowerLayerUp(); + } +} + +std::string TransportTestObject::GetData(const std::string& arHdr, uint8_t aSeed, uint32_t aLength) +{ + testlib::ByteStr buff(aLength); + uint8_t val = aSeed; + for(size_t i = 0; i < aLength; ++i) + { + buff[i] = val; + ++val; + } + + ostringstream oss; + if(arHdr.size() > 0) oss << arHdr << " "; + oss << ToHex(buff, buff.Size(), true); + return oss.str(); +} + +std::string TransportTestObject::GeneratePacketSequence(vector< std::string >& arVec, uint32_t aNumPackets, uint32_t aLastPacketLength) +{ + ostringstream oss; + for(size_t i = 0; i < aNumPackets; ++i) + { + bool fir = i == 0; + bool fin = i == (aNumPackets - 1); + int seq = static_cast(i % 64); + uint32_t len = fin ? aLastPacketLength : MAX_TPDU_PAYLOAD; + uint8_t hdr = TransportTx::GetHeader(fir, fin, seq); + std::string data = this->GetData("", 0, len); //raw data with no header + oss << ((i == 0) ? "" : " ") << data; //cache the data in the string stream + arVec.push_back(ToHex(&hdr, 1, true) + " " + data); + } + + return oss.str(); +} + +} + diff --git a/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.h b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.h new file mode 100644 index 0000000..9c8a4c9 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/opendnp3/src/mocks/TransportTestObject.h @@ -0,0 +1,62 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#ifndef __TRANSPORT_TEST_OBJECT_H_ +#define __TRANSPORT_TEST_OBJECT_H_ + +#include "opendnp3/transport/TransportLayer.h" +#include "opendnp3/app/AppConstants.h" +#include "opendnp3/LogLevels.h" + +#include "MockLinkLayer.h" +#include "dnp3mocks/MockUpperLayer.h" + +#include "testlib/MockExecutor.h" +#include "testlib/MockLogHandler.h" + +#include +#include + +namespace opendnp3 +{ + +class TransportTestObject +{ +public: + TransportTestObject(bool openOnStart = false, uint32_t maxRxFragmentSize = DEFAULT_MAX_APDU_SIZE); + + // Generate a complete packet sequence inside the vector and + // return the corresponding reassembled APDU + std::string GeneratePacketSequence(std::vector&, uint32_t aNumPackets, uint32_t aLastPacketLength); + + // Get a Sequence of data w/ optional header + std::string GetData(const std::string& arHdr, uint8_t aSeed = 0, uint32_t aLength = MAX_TPDU_PAYLOAD); + + testlib::MockLogHandler log; + testlib::MockExecutor exe; + TransportLayer transport; + MockLinkLayer link; + MockUpperLayer upper; +}; + +} + +#endif + diff --git a/utils/dnp3_src/cpp/tests/openpal/src/CatchTestStart.cpp b/utils/dnp3_src/cpp/tests/openpal/src/CatchTestStart.cpp new file mode 100644 index 0000000..3da2194 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/CatchTestStart.cpp @@ -0,0 +1,22 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#define CATCH_CONFIG_MAIN +#include diff --git a/utils/dnp3_src/cpp/tests/openpal/src/LinkedListTestSuite.cpp b/utils/dnp3_src/cpp/tests/openpal/src/LinkedListTestSuite.cpp new file mode 100644 index 0000000..d16eb85 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/LinkedListTestSuite.cpp @@ -0,0 +1,241 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +using namespace openpal; + +#define SUITE(name) "LinkedListAdapter - " name + +TEST_CASE(SUITE("CorrectInitialState")) +{ + LinkedList list(3); + + REQUIRE(list.IsEmpty()); + REQUIRE(!list.IsFull()); + REQUIRE(0 == list.Size()); +} + +TEST_CASE(SUITE("AddsUntilFull")) +{ + LinkedList list(3); + + REQUIRE(list.Add(1)); + REQUIRE(list.Add(2)); + REQUIRE(list.Add(3)); + + REQUIRE(list.IsFull()); + + // adding to a full list returns a nullptr + REQUIRE_FALSE(list.Add(4)); +} + +TEST_CASE(SUITE("CanRemoveHead")) +{ + LinkedList list(3); + + auto one = list.Add(1); + list.Add(2); + list.Add(3); + + list.Remove(one); + + REQUIRE(2 == list.Size()); + + auto four = list.Add(4); + + REQUIRE(four == one); // these pointers should be the same +} + +TEST_CASE(SUITE("CanRemoveTail")) +{ + LinkedList list(3); + + list.Add(1); + list.Add(2); + auto three = list.Add(3); + + list.Remove(three); + + REQUIRE(2 == list.Size()); + + auto four = list.Add(4); + + REQUIRE(four == three); // these pointers should be the same +} + +TEST_CASE(SUITE("CanRemoveMiddle")) +{ + LinkedList list(3); + + list.Add(1); + auto two = list.Add(2); + list.Add(3); + + list.Remove(two); + + REQUIRE(2 == list.Size()); + + auto four = list.Add(4); + + REQUIRE(four == two); // these pointers should be the same +} + +TEST_CASE(SUITE("RemoveAllComplexQuery")) +{ + LinkedList list(10); + + list.Add(2); + list.Add(3); + list.Add(4); + list.Add(7); + list.Add(20); + list.Add(8); + + auto isEven = [](int num) + { + return (num % 2) == 0; + }; + auto count = list.RemoveAll(isEven); + + REQUIRE(count == 4); + REQUIRE(list.Size() == 2); + + std::vector remaining; + auto pushToVector = [&](int num) + { + remaining.push_back(num); + }; + list.Foreach(pushToVector); + + REQUIRE(remaining.size() == 2); + REQUIRE(remaining[0] == 3); + REQUIRE(remaining[1] == 7); +} + +TEST_CASE(SUITE("CanIterateOverValues")) +{ + LinkedList list(3); + + list.Add(1); + list.Add(2); + list.Add(3); + + auto iter = list.Iterate(); + + for(int i = 1; i < 4; ++i) + { + REQUIRE(iter.HasNext()); + REQUIRE(i == iter.Next()->value); + } + + REQUIRE(!iter.HasNext()); +} + +TEST_CASE(SUITE("StaticLinkedList")) +{ + LinkedList list(3); + + REQUIRE(list.Add(1)); + REQUIRE(list.Add(2)); + REQUIRE(list.Add(3)); + REQUIRE_FALSE(list.Add(4)); + + REQUIRE(list.Remove(2)); +} + +TEST_CASE(SUITE("Insert at front of list")) +{ + LinkedList list(3); + + REQUIRE(list.Add(7)); + + auto lessThan = [](int lhs, int rhs) + { + return lhs < rhs; + }; + REQUIRE(list.Insert(4, lessThan)); + + std::vector items; + + list.Foreach([&](int x) + { + items.push_back(x); + }); + REQUIRE(items.size() == 2); + REQUIRE(items[0] == 4); + REQUIRE(items[1] == 7); +} + +TEST_CASE(SUITE("Insert in center of list")) +{ + LinkedList list(10); + + REQUIRE(list.Add(2)); + REQUIRE(list.Add(7)); + + auto lessThan = [](int lhs, int rhs) + { + return lhs < rhs; + }; + REQUIRE(list.Insert(4, lessThan)); + + std::vector items; + + list.Foreach([&](int x) + { + items.push_back(x); + }); + REQUIRE(items.size() == 3); + + REQUIRE(items[0] == 2); + REQUIRE(items[1] == 4); + REQUIRE(items[2] == 7); +} + +TEST_CASE(SUITE("Insert at end of list")) +{ + LinkedList list(10); + + REQUIRE(list.Add(2)); + REQUIRE(list.Add(4)); + + auto lessThan = [](int lhs, int rhs) + { + return lhs < rhs; + }; + REQUIRE(list.Insert(7, lessThan)); + + std::vector items; + + list.Foreach([&](int x) + { + items.push_back(x); + }); + REQUIRE(items.size() == 3); + + REQUIRE(items[0] == 2); + REQUIRE(items[1] == 4); + REQUIRE(items[2] == 7); +} + diff --git a/utils/dnp3_src/cpp/tests/openpal/src/QueueTestSuite.cpp b/utils/dnp3_src/cpp/tests/openpal/src/QueueTestSuite.cpp new file mode 100644 index 0000000..5101fa9 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/QueueTestSuite.cpp @@ -0,0 +1,45 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +using namespace openpal; + +#define SUITE(name) "Queue - " name + +TEST_CASE(SUITE("CorrectInitialState")) +{ + Queue queue(3); +} + +TEST_CASE(SUITE("AddsUntilFull")) +{ + Queue queue(3); + + REQUIRE(queue.Enqueue(true)); + REQUIRE(queue.Enqueue(false)); + REQUIRE(queue.Enqueue(true)); + + REQUIRE_FALSE(queue.Enqueue(true)); +} + + diff --git a/utils/dnp3_src/cpp/tests/openpal/src/TestFloatSerialization.cpp b/utils/dnp3_src/cpp/tests/openpal/src/TestFloatSerialization.cpp new file mode 100644 index 0000000..3fd7916 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/TestFloatSerialization.cpp @@ -0,0 +1,135 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace openpal; +using namespace testlib; + +using namespace std; + +template +bool TestReadWriteFloat(T value) +{ + Buffer buffer(2 * sizeof(T)); + + for (uint32_t i = 0; i < sizeof(T); ++i) + { + auto dest = buffer.GetWSlice(); + dest.Advance(i); + if (!Format::Write(dest, value)) + { + return false; + } + + auto written = buffer.ToRSlice().Skip(i); + T readValue; + if (!(Parse::Read(written, readValue) && FloatEqual(value, readValue))) + { + return false; + } + } + + return true; +} + +template +bool TestFloatParsing(std::string hex, typename T::Type value) +{ + HexSequence hs(hex); + const uint32_t TYPE_SIZE = static_cast(sizeof(typename T::Type)); + REQUIRE((hs.Size() == TYPE_SIZE)); + + Buffer buffer(2 * TYPE_SIZE); + + for (uint32_t i = 0; i < TYPE_SIZE; ++i) + { + auto dest = buffer.GetWSlice(); + dest.Advance(i); + if (!Format::Write(dest, value)) + { + return false; + } + auto written = buffer.ToRSlice().Skip(i); + + typename T::Type val = 0; + if (!(Parse::Read(written, val) && openpal::FloatEqual(val, value))) + { + return false; + } + } + + return true; +} + +#define SUITE(name) "FloatSerializationTestSuite - " name + +TEST_CASE(SUITE("Float memory byte order is IEEE 754")) +{ + REQUIRE(openpal::FloatByteOrder::ORDER != FloatByteOrder::Value::UNSUPPORTED); +} + +TEST_CASE(SUITE("DoublePacking")) +{ + REQUIRE(TestFloatParsing("20 74 85 2F C7 2B A2 C0", -2.3258890344E3)); + REQUIRE(TestFloatParsing("00 00 00 00 64 89 67 41", 12340000.0)); + REQUIRE(TestFloatParsing("00 00 00 00 00 00 34 C0", -20.0)); + REQUIRE(TestFloatParsing("8F 81 9C 95 2D F9 64 BB", -13.879E-23)); + REQUIRE(TestFloatParsing("00 00 00 00 00 00 59 40", 100.0)); +} + +TEST_CASE(SUITE("SinglePacking")) +{ + REQUIRE(TestFloatParsing("20 4B 3C 4B", 12340000.0f)); + REQUIRE(TestFloatParsing("6D C9 27 9B", -13.879E-23f)); + REQUIRE(TestFloatParsing("00 00 A0 C1", -20.0)); +} + + +TEST_CASE(SUITE("DoubleFloat")) +{ + REQUIRE(TestReadWriteFloat(0.0)); + REQUIRE(TestReadWriteFloat(-100000)); + REQUIRE(TestReadWriteFloat(-2.3258890344E3)); + REQUIRE(TestReadWriteFloat(1E20)); + REQUIRE(TestReadWriteFloat(100.0)); +} + +TEST_CASE(SUITE("SingleFloat")) +{ + REQUIRE(TestReadWriteFloat(0.0f)); + REQUIRE(TestReadWriteFloat(-100000.0f)); + REQUIRE(TestReadWriteFloat(-2.3258890344E3f)); + REQUIRE(TestReadWriteFloat(1E20f)); + REQUIRE(TestReadWriteFloat(100.0f)); +} + diff --git a/utils/dnp3_src/cpp/tests/openpal/src/TestIntegerSerialization.cpp b/utils/dnp3_src/cpp/tests/openpal/src/TestIntegerSerialization.cpp new file mode 100644 index 0000000..c1a6630 --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/TestIntegerSerialization.cpp @@ -0,0 +1,196 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace openpal; +using namespace testlib; + +using namespace std; + +template +bool TestReadWrite(T value) +{ + Buffer buffer(2 * sizeof(T)); + + for (uint32_t i = 0; i < sizeof(T); ++i) + { + auto dest = buffer.GetWSlice(); + dest.Advance(i); + if (!Format::Write(dest, value)) + { + return false; + } + + auto written = buffer.ToRSlice().Skip(i); + T readValue; + if (!(Parse::Read(written, readValue) && value == readValue)) + { + return false; + } + } + + return true; +} + + +#define SUITE(name) "IntegerSerializationTestSuite - " name + +TEST_CASE(SUITE("UInt8")) +{ + REQUIRE(TestReadWrite(0)); + REQUIRE(TestReadWrite(123)); + REQUIRE(TestReadWrite(255)); +} + +TEST_CASE(SUITE("UInt16")) +{ + REQUIRE(TestReadWrite(0)); + REQUIRE(TestReadWrite(123)); + REQUIRE(TestReadWrite(65535)); +} + +TEST_CASE(SUITE("UInt16 read from little endian")) +{ + uint8_t arr[2] = { 0x01, 0x02 }; + + // 2*256 + 1 + REQUIRE(UInt16::Read(arr) == 513); +} + +TEST_CASE(SUITE("Int16")) +{ + REQUIRE(TestReadWrite(-32768)); + REQUIRE(TestReadWrite(0)); + REQUIRE(TestReadWrite(32767)); +} + +TEST_CASE(SUITE("Int16 read from little endian")) +{ + uint8_t arr[2] = { 0x00, 0x80 }; + + // 2*256 + 1 + REQUIRE(Int16::Read(arr) == openpal::MinValue()); +} + +TEST_CASE(SUITE("UInt32")) +{ + REQUIRE(TestReadWrite(0)); + REQUIRE(TestReadWrite(123)); + REQUIRE(TestReadWrite(4294967295UL)); +} + +TEST_CASE(SUITE("UInt32 read from little endian")) +{ + uint8_t arr[4] = { 0x01, 0x02, 0x00, 0x00 }; + + // 2*256 + 1 + REQUIRE(UInt32::Read(arr) == 513); +} + +TEST_CASE(SUITE("Int32")) +{ + REQUIRE(TestReadWrite(0x80000000)); + REQUIRE(TestReadWrite(0)); + REQUIRE(TestReadWrite(0x7fffffff)); +} + +TEST_CASE(SUITE("Int32 read from little endian")) +{ + uint8_t arr[4] = { 0x00, 0x00, 0x00, 0x80 }; + + REQUIRE(Int32::Read(arr) == openpal::MinValue()); +} + +TEST_CASE(SUITE("UInt48")) +{ + REQUIRE(TestReadWrite(UInt48Type(0))); + REQUIRE(TestReadWrite(UInt48Type(123))); + REQUIRE(TestReadWrite(UInt48Type(281474976710655ULL))); +} + +TEST_CASE(SUITE("UInt48 read from little endian")) +{ + uint8_t arr[6] = { 0x01, 0x02, 0x00, 0x00, 0x00, 0x00}; + + // 2*256 + 1 + REQUIRE(UInt48::Read(arr) == 513); +} + + +TEST_CASE(SUITE("ParseMany")) +{ + HexSequence hex("FF AB BA 01 00 00 00 CC"); + + uint8_t first = 0; + uint16_t second = 0; + uint32_t third = 0; + + { + auto input = hex.ToRSlice(); + REQUIRE(Parse::Many(input, first, second, third)); + REQUIRE(first == 255); + REQUIRE(second == 0xBAAB); + REQUIRE(third == 1); + REQUIRE(input.Size() == 1); // 1 byte remaining + } + + { + auto input = hex.ToRSlice().Skip(2); + REQUIRE_FALSE(Parse::Many(input, first, second, third)); + } +} + + +TEST_CASE(SUITE("FormatMany")) +{ + + uint8_t first = 255; + uint16_t second = 0xBAAB; + uint32_t third = 1; + + const uint32_t SIZE = 7; + + Buffer output(SIZE + 3); + + { + auto dest = output.GetWSlice(); + REQUIRE(Format::Many(dest, first, second, third)); + REQUIRE(dest.Size() == (output.Size() - SIZE)); + auto written = ToHex(output.ToRSlice().Take(SIZE)); + REQUIRE(written == "FF AB BA 01 00 00 00"); + } + + { + auto dest = output.GetWSlice(SIZE - 1); + REQUIRE_FALSE(Format::Many(dest, first, second, third)); + } +} \ No newline at end of file diff --git a/utils/dnp3_src/cpp/tests/openpal/src/TestStaticBuffer.cpp b/utils/dnp3_src/cpp/tests/openpal/src/TestStaticBuffer.cpp new file mode 100644 index 0000000..491435c --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/TestStaticBuffer.cpp @@ -0,0 +1,64 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include + +using namespace openpal; + +using namespace std; + + +#define SUITE(name) "StaticBuffer - " name + +TEST_CASE(SUITE("Static buffers can be copied")) +{ + StaticBuffer<4> buffer; + + buffer()[0] = 0xDE; + buffer()[1] = 0xAD; + buffer()[2] = 0xBE; + buffer()[3] = 0xEF; + + StaticBuffer<4> copy(buffer); + REQUIRE(copy()[0] == 0xDE); + REQUIRE(copy()[1] == 0xAD); + REQUIRE(copy()[2] == 0xBE); + REQUIRE(copy()[3] == 0xEF); +} + +TEST_CASE(SUITE("Static buffers can be assigned")) +{ + StaticBuffer<4> buffer; + + buffer()[0] = 0xDE; + buffer()[1] = 0xAD; + buffer()[2] = 0xBE; + buffer()[3] = 0xEF; + + StaticBuffer<4> copy; + copy = buffer; + REQUIRE(copy()[0] == 0xDE); + REQUIRE(copy()[1] == 0xAD); + REQUIRE(copy()[2] == 0xBE); + REQUIRE(copy()[3] == 0xEF); +} + diff --git a/utils/dnp3_src/cpp/tests/openpal/src/TestTime.cpp b/utils/dnp3_src/cpp/tests/openpal/src/TestTime.cpp new file mode 100644 index 0000000..5aaa27d --- /dev/null +++ b/utils/dnp3_src/cpp/tests/openpal/src/TestTime.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to Green Energy Corp (www.greenenergycorp.com) under one or + * more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Green Energy Corp licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This project was forked on 01/01/2013 by Automatak, LLC and modifications + * may have been made to this file. Automatak, LLC licenses these modifications + * to you under the terms of the License. + */ +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace std::chrono; +using namespace testlib; + +#define SUITE(name) "TimeoutStopWatchTests - " name + +TEST_CASE(SUITE("TimeoutCorrectlyNotExpired")) +{ + //create a timeout of 1 millisecond + Timeout to(milliseconds(1000)); + + //check that the timeout starts out unexpired + REQUIRE(to.IsExpired() == false); + REQUIRE(to.Remaining() > milliseconds(1)); +} + +TEST_CASE(SUITE("StopWatchBasicTest")) +{ + StopWatch sw; + + REQUIRE(sw.Elapsed(false) <= milliseconds(100)); +} + + + diff --git a/utils/dnp3_src/deps/asio/asio/COPYING b/utils/dnp3_src/deps/asio/asio/COPYING new file mode 100644 index 0000000..5a0dd10 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/COPYING @@ -0,0 +1,4 @@ +Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/utils/dnp3_src/deps/asio/asio/INSTALL b/utils/dnp3_src/deps/asio/asio/INSTALL new file mode 100644 index 0000000..f045678 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/INSTALL @@ -0,0 +1,5 @@ +See doc/index.html for information on: + - External dependencies + - Using asio + - Supported platforms + - How to build the tests and examples diff --git a/utils/dnp3_src/deps/asio/asio/LICENSE_1_0.txt b/utils/dnp3_src/deps/asio/asio/LICENSE_1_0.txt new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/utils/dnp3_src/deps/asio/asio/Makefile.am b/utils/dnp3_src/deps/asio/asio/Makefile.am new file mode 100644 index 0000000..0acdc02 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/Makefile.am @@ -0,0 +1,19 @@ +AUTOMAKE_OPTIONS = foreign dist-bzip2 dist-zip + +SUBDIRS = include src + +MAINTAINERCLEANFILES = \ + $(srcdir)/aclocal.m4 \ + $(srcdir)/configure \ + $(srcdir)/config.guess \ + $(srcdir)/config.sub \ + $(srcdir)/depcomp \ + $(srcdir)/install-sh \ + $(srcdir)/missing \ + $(srcdir)/mkinstalldirs \ + $(srcdir)/Makefile.in \ + asio-*.tar.gz + +EXTRA_DIST = \ + LICENSE_1_0.txt \ + doc diff --git a/utils/dnp3_src/deps/asio/asio/README b/utils/dnp3_src/deps/asio/asio/README new file mode 100644 index 0000000..590c482 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/README @@ -0,0 +1,4 @@ +asio version 1.10.8 +Released Monday, 19 September 2016. + +See doc/index.html for API documentation and a tutorial. diff --git a/utils/dnp3_src/deps/asio/asio/asio.manifest b/utils/dnp3_src/deps/asio/asio/asio.manifest new file mode 100644 index 0000000..2eedeb4 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/asio.manifest @@ -0,0 +1,4358 @@ +/ +/aclocal.m4 +/compile +/config.guess +/config.sub +/configure +/configure.ac +/COPYING +/depcomp +/doc/ +/doc/asio/ +/doc/asio/examples/ +/doc/asio/examples/cpp03_examples.html +/doc/asio/examples/cpp11_examples.html +/doc/asio/examples.html +/doc/asio/history.html +/doc/asio/index.html +/doc/asio/overview/ +/doc/asio/overview/core/ +/doc/asio/overview/core/allocation.html +/doc/asio/overview/core/async.html +/doc/asio/overview/core/basics.html +/doc/asio/overview/core/buffers.html +/doc/asio/overview/core/coroutine.html +/doc/asio/overview/core/handler_tracking.html +/doc/asio/overview/core.html +/doc/asio/overview/core/line_based.html +/doc/asio/overview/core/reactor.html +/doc/asio/overview/core/spawn.html +/doc/asio/overview/core/strands.html +/doc/asio/overview/core/streams.html +/doc/asio/overview/core/threads.html +/doc/asio/overview/cpp2011/ +/doc/asio/overview/cpp2011/array.html +/doc/asio/overview/cpp2011/atomic.html +/doc/asio/overview/cpp2011/chrono.html +/doc/asio/overview/cpp2011/futures.html +/doc/asio/overview/cpp2011.html +/doc/asio/overview/cpp2011/move_handlers.html +/doc/asio/overview/cpp2011/move_objects.html +/doc/asio/overview/cpp2011/shared_ptr.html +/doc/asio/overview/cpp2011/system_error.html +/doc/asio/overview/cpp2011/variadic.html +/doc/asio/overview.html +/doc/asio/overview/implementation.html +/doc/asio/overview/networking/ +/doc/asio/overview/networking/bsd_sockets.html +/doc/asio/overview/networking.html +/doc/asio/overview/networking/iostreams.html +/doc/asio/overview/networking/other_protocols.html +/doc/asio/overview/networking/protocols.html +/doc/asio/overview/posix/ +/doc/asio/overview/posix/fork.html +/doc/asio/overview/posix.html +/doc/asio/overview/posix/local.html +/doc/asio/overview/posix/stream_descriptor.html +/doc/asio/overview/rationale.html +/doc/asio/overview/serial_ports.html +/doc/asio/overview/signals.html +/doc/asio/overview/ssl.html +/doc/asio/overview/timers.html +/doc/asio/overview/windows/ +/doc/asio/overview/windows.html +/doc/asio/overview/windows/object_handle.html +/doc/asio/overview/windows/random_access_handle.html +/doc/asio/overview/windows/stream_handle.html +/doc/asio.png +/doc/asio/reference/ +/doc/asio/reference/AcceptHandler.html +/doc/asio/reference/add_service.html +/doc/asio/reference/asio_handler_allocate.html +/doc/asio/reference/asio_handler_deallocate.html +/doc/asio/reference/asio_handler_invoke/ +/doc/asio/reference/asio_handler_invoke.html +/doc/asio/reference/asio_handler_invoke/overload1.html +/doc/asio/reference/asio_handler_invoke/overload2.html +/doc/asio/reference/asio_handler_is_continuation.html +/doc/asio/reference/async_connect/ +/doc/asio/reference/async_connect.html +/doc/asio/reference/async_connect/overload1.html +/doc/asio/reference/async_connect/overload2.html +/doc/asio/reference/async_connect/overload3.html +/doc/asio/reference/async_connect/overload4.html +/doc/asio/reference/asynchronous_operations.html +/doc/asio/reference/AsyncRandomAccessReadDevice.html +/doc/asio/reference/AsyncRandomAccessWriteDevice.html +/doc/asio/reference/async_read/ +/doc/asio/reference/async_read_at/ +/doc/asio/reference/async_read_at.html +/doc/asio/reference/async_read_at/overload1.html +/doc/asio/reference/async_read_at/overload2.html +/doc/asio/reference/async_read_at/overload3.html +/doc/asio/reference/async_read_at/overload4.html +/doc/asio/reference/async_read.html +/doc/asio/reference/async_read/overload1.html +/doc/asio/reference/async_read/overload2.html +/doc/asio/reference/async_read/overload3.html +/doc/asio/reference/async_read/overload4.html +/doc/asio/reference/AsyncReadStream.html +/doc/asio/reference/async_read_until/ +/doc/asio/reference/async_read_until.html +/doc/asio/reference/async_read_until/overload1.html +/doc/asio/reference/async_read_until/overload2.html +/doc/asio/reference/async_read_until/overload3.html +/doc/asio/reference/async_read_until/overload4.html +/doc/asio/reference/async_result/ +/doc/asio/reference/async_result/async_result.html +/doc/asio/reference/async_result/get.html +/doc/asio/reference/async_result.html +/doc/asio/reference/async_result/type.html +/doc/asio/reference/async_write/ +/doc/asio/reference/async_write_at/ +/doc/asio/reference/async_write_at.html +/doc/asio/reference/async_write_at/overload1.html +/doc/asio/reference/async_write_at/overload2.html +/doc/asio/reference/async_write_at/overload3.html +/doc/asio/reference/async_write_at/overload4.html +/doc/asio/reference/async_write.html +/doc/asio/reference/async_write/overload1.html +/doc/asio/reference/async_write/overload2.html +/doc/asio/reference/async_write/overload3.html +/doc/asio/reference/async_write/overload4.html +/doc/asio/reference/AsyncWriteStream.html +/doc/asio/reference/basic_datagram_socket/ +/doc/asio/reference/basic_datagram_socket/assign/ +/doc/asio/reference/basic_datagram_socket/assign.html +/doc/asio/reference/basic_datagram_socket/assign/overload1.html +/doc/asio/reference/basic_datagram_socket/assign/overload2.html +/doc/asio/reference/basic_datagram_socket/async_connect.html +/doc/asio/reference/basic_datagram_socket/async_receive/ +/doc/asio/reference/basic_datagram_socket/async_receive_from/ +/doc/asio/reference/basic_datagram_socket/async_receive_from.html +/doc/asio/reference/basic_datagram_socket/async_receive_from/overload1.html +/doc/asio/reference/basic_datagram_socket/async_receive_from/overload2.html +/doc/asio/reference/basic_datagram_socket/async_receive.html +/doc/asio/reference/basic_datagram_socket/async_receive/overload1.html +/doc/asio/reference/basic_datagram_socket/async_receive/overload2.html +/doc/asio/reference/basic_datagram_socket/async_send/ +/doc/asio/reference/basic_datagram_socket/async_send.html +/doc/asio/reference/basic_datagram_socket/async_send/overload1.html +/doc/asio/reference/basic_datagram_socket/async_send/overload2.html +/doc/asio/reference/basic_datagram_socket/async_send_to/ +/doc/asio/reference/basic_datagram_socket/async_send_to.html +/doc/asio/reference/basic_datagram_socket/async_send_to/overload1.html +/doc/asio/reference/basic_datagram_socket/async_send_to/overload2.html +/doc/asio/reference/basic_datagram_socket/at_mark/ +/doc/asio/reference/basic_datagram_socket/at_mark.html +/doc/asio/reference/basic_datagram_socket/at_mark/overload1.html +/doc/asio/reference/basic_datagram_socket/at_mark/overload2.html +/doc/asio/reference/basic_datagram_socket/available/ +/doc/asio/reference/basic_datagram_socket/available.html +/doc/asio/reference/basic_datagram_socket/available/overload1.html +/doc/asio/reference/basic_datagram_socket/available/overload2.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/ +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/overload1.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/overload2.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/overload3.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/overload4.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/overload5.html +/doc/asio/reference/basic_datagram_socket/basic_datagram_socket/overload6.html +/doc/asio/reference/basic_datagram_socket/bind/ +/doc/asio/reference/basic_datagram_socket/bind.html +/doc/asio/reference/basic_datagram_socket/bind/overload1.html +/doc/asio/reference/basic_datagram_socket/bind/overload2.html +/doc/asio/reference/basic_datagram_socket/broadcast.html +/doc/asio/reference/basic_datagram_socket/bytes_readable.html +/doc/asio/reference/basic_datagram_socket/cancel/ +/doc/asio/reference/basic_datagram_socket/cancel.html +/doc/asio/reference/basic_datagram_socket/cancel/overload1.html +/doc/asio/reference/basic_datagram_socket/cancel/overload2.html +/doc/asio/reference/basic_datagram_socket/close/ +/doc/asio/reference/basic_datagram_socket/close.html +/doc/asio/reference/basic_datagram_socket/close/overload1.html +/doc/asio/reference/basic_datagram_socket/close/overload2.html +/doc/asio/reference/basic_datagram_socket/connect/ +/doc/asio/reference/basic_datagram_socket/connect.html +/doc/asio/reference/basic_datagram_socket/connect/overload1.html +/doc/asio/reference/basic_datagram_socket/connect/overload2.html +/doc/asio/reference/basic_datagram_socket/debug.html +/doc/asio/reference/basic_datagram_socket/do_not_route.html +/doc/asio/reference/basic_datagram_socket/enable_connection_aborted.html +/doc/asio/reference/basic_datagram_socket/endpoint_type.html +/doc/asio/reference/basic_datagram_socket/get_implementation/ +/doc/asio/reference/basic_datagram_socket/get_implementation.html +/doc/asio/reference/basic_datagram_socket/get_implementation/overload1.html +/doc/asio/reference/basic_datagram_socket/get_implementation/overload2.html +/doc/asio/reference/basic_datagram_socket/get_io_service.html +/doc/asio/reference/basic_datagram_socket/get_option/ +/doc/asio/reference/basic_datagram_socket/get_option.html +/doc/asio/reference/basic_datagram_socket/get_option/overload1.html +/doc/asio/reference/basic_datagram_socket/get_option/overload2.html +/doc/asio/reference/basic_datagram_socket/get_service/ +/doc/asio/reference/basic_datagram_socket/get_service.html +/doc/asio/reference/basic_datagram_socket/get_service/overload1.html +/doc/asio/reference/basic_datagram_socket/get_service/overload2.html +/doc/asio/reference/basic_datagram_socket.html +/doc/asio/reference/basic_datagram_socket/implementation.html +/doc/asio/reference/basic_datagram_socket/implementation_type.html +/doc/asio/reference/basic_datagram_socket/io_control/ +/doc/asio/reference/basic_datagram_socket/io_control.html +/doc/asio/reference/basic_datagram_socket/io_control/overload1.html +/doc/asio/reference/basic_datagram_socket/io_control/overload2.html +/doc/asio/reference/basic_datagram_socket/is_open.html +/doc/asio/reference/basic_datagram_socket/keep_alive.html +/doc/asio/reference/basic_datagram_socket/linger.html +/doc/asio/reference/basic_datagram_socket/local_endpoint/ +/doc/asio/reference/basic_datagram_socket/local_endpoint.html +/doc/asio/reference/basic_datagram_socket/local_endpoint/overload1.html +/doc/asio/reference/basic_datagram_socket/local_endpoint/overload2.html +/doc/asio/reference/basic_datagram_socket/lowest_layer/ +/doc/asio/reference/basic_datagram_socket/lowest_layer.html +/doc/asio/reference/basic_datagram_socket/lowest_layer/overload1.html +/doc/asio/reference/basic_datagram_socket/lowest_layer/overload2.html +/doc/asio/reference/basic_datagram_socket/lowest_layer_type.html +/doc/asio/reference/basic_datagram_socket/max_connections.html +/doc/asio/reference/basic_datagram_socket/message_do_not_route.html +/doc/asio/reference/basic_datagram_socket/message_end_of_record.html +/doc/asio/reference/basic_datagram_socket/message_flags.html +/doc/asio/reference/basic_datagram_socket/message_out_of_band.html +/doc/asio/reference/basic_datagram_socket/message_peek.html +/doc/asio/reference/basic_datagram_socket/native_handle.html +/doc/asio/reference/basic_datagram_socket/native_handle_type.html +/doc/asio/reference/basic_datagram_socket/native.html +/doc/asio/reference/basic_datagram_socket/native_non_blocking/ +/doc/asio/reference/basic_datagram_socket/native_non_blocking.html +/doc/asio/reference/basic_datagram_socket/native_non_blocking/overload1.html +/doc/asio/reference/basic_datagram_socket/native_non_blocking/overload2.html +/doc/asio/reference/basic_datagram_socket/native_non_blocking/overload3.html +/doc/asio/reference/basic_datagram_socket/native_type.html +/doc/asio/reference/basic_datagram_socket/non_blocking/ +/doc/asio/reference/basic_datagram_socket/non_blocking.html +/doc/asio/reference/basic_datagram_socket/non_blocking_io.html +/doc/asio/reference/basic_datagram_socket/non_blocking/overload1.html +/doc/asio/reference/basic_datagram_socket/non_blocking/overload2.html +/doc/asio/reference/basic_datagram_socket/non_blocking/overload3.html +/doc/asio/reference/basic_datagram_socket/open/ +/doc/asio/reference/basic_datagram_socket/open.html +/doc/asio/reference/basic_datagram_socket/open/overload1.html +/doc/asio/reference/basic_datagram_socket/open/overload2.html +/doc/asio/reference/basic_datagram_socket/operator_eq_/ +/doc/asio/reference/basic_datagram_socket/operator_eq_.html +/doc/asio/reference/basic_datagram_socket/operator_eq_/overload1.html +/doc/asio/reference/basic_datagram_socket/operator_eq_/overload2.html +/doc/asio/reference/basic_datagram_socket/protocol_type.html +/doc/asio/reference/basic_datagram_socket/receive/ +/doc/asio/reference/basic_datagram_socket/receive_buffer_size.html +/doc/asio/reference/basic_datagram_socket/receive_from/ +/doc/asio/reference/basic_datagram_socket/receive_from.html +/doc/asio/reference/basic_datagram_socket/receive_from/overload1.html +/doc/asio/reference/basic_datagram_socket/receive_from/overload2.html +/doc/asio/reference/basic_datagram_socket/receive_from/overload3.html +/doc/asio/reference/basic_datagram_socket/receive.html +/doc/asio/reference/basic_datagram_socket/receive_low_watermark.html +/doc/asio/reference/basic_datagram_socket/receive/overload1.html +/doc/asio/reference/basic_datagram_socket/receive/overload2.html +/doc/asio/reference/basic_datagram_socket/receive/overload3.html +/doc/asio/reference/basic_datagram_socket/remote_endpoint/ +/doc/asio/reference/basic_datagram_socket/remote_endpoint.html +/doc/asio/reference/basic_datagram_socket/remote_endpoint/overload1.html +/doc/asio/reference/basic_datagram_socket/remote_endpoint/overload2.html +/doc/asio/reference/basic_datagram_socket/reuse_address.html +/doc/asio/reference/basic_datagram_socket/send/ +/doc/asio/reference/basic_datagram_socket/send_buffer_size.html +/doc/asio/reference/basic_datagram_socket/send.html +/doc/asio/reference/basic_datagram_socket/send_low_watermark.html +/doc/asio/reference/basic_datagram_socket/send/overload1.html +/doc/asio/reference/basic_datagram_socket/send/overload2.html +/doc/asio/reference/basic_datagram_socket/send/overload3.html +/doc/asio/reference/basic_datagram_socket/send_to/ +/doc/asio/reference/basic_datagram_socket/send_to.html +/doc/asio/reference/basic_datagram_socket/send_to/overload1.html +/doc/asio/reference/basic_datagram_socket/send_to/overload2.html +/doc/asio/reference/basic_datagram_socket/send_to/overload3.html +/doc/asio/reference/basic_datagram_socket/service.html +/doc/asio/reference/basic_datagram_socket/service_type.html +/doc/asio/reference/basic_datagram_socket/set_option/ +/doc/asio/reference/basic_datagram_socket/set_option.html +/doc/asio/reference/basic_datagram_socket/set_option/overload1.html +/doc/asio/reference/basic_datagram_socket/set_option/overload2.html +/doc/asio/reference/basic_datagram_socket/shutdown/ +/doc/asio/reference/basic_datagram_socket/shutdown.html +/doc/asio/reference/basic_datagram_socket/shutdown/overload1.html +/doc/asio/reference/basic_datagram_socket/shutdown/overload2.html +/doc/asio/reference/basic_datagram_socket/shutdown_type.html +/doc/asio/reference/basic_deadline_timer/ +/doc/asio/reference/basic_deadline_timer/async_wait.html +/doc/asio/reference/basic_deadline_timer/basic_deadline_timer/ +/doc/asio/reference/basic_deadline_timer/basic_deadline_timer.html +/doc/asio/reference/basic_deadline_timer/basic_deadline_timer/overload1.html +/doc/asio/reference/basic_deadline_timer/basic_deadline_timer/overload2.html +/doc/asio/reference/basic_deadline_timer/basic_deadline_timer/overload3.html +/doc/asio/reference/basic_deadline_timer/cancel/ +/doc/asio/reference/basic_deadline_timer/cancel.html +/doc/asio/reference/basic_deadline_timer/cancel_one/ +/doc/asio/reference/basic_deadline_timer/cancel_one.html +/doc/asio/reference/basic_deadline_timer/cancel_one/overload1.html +/doc/asio/reference/basic_deadline_timer/cancel_one/overload2.html +/doc/asio/reference/basic_deadline_timer/cancel/overload1.html +/doc/asio/reference/basic_deadline_timer/cancel/overload2.html +/doc/asio/reference/basic_deadline_timer/duration_type.html +/doc/asio/reference/basic_deadline_timer/expires_at/ +/doc/asio/reference/basic_deadline_timer/expires_at.html +/doc/asio/reference/basic_deadline_timer/expires_at/overload1.html +/doc/asio/reference/basic_deadline_timer/expires_at/overload2.html +/doc/asio/reference/basic_deadline_timer/expires_at/overload3.html +/doc/asio/reference/basic_deadline_timer/expires_from_now/ +/doc/asio/reference/basic_deadline_timer/expires_from_now.html +/doc/asio/reference/basic_deadline_timer/expires_from_now/overload1.html +/doc/asio/reference/basic_deadline_timer/expires_from_now/overload2.html +/doc/asio/reference/basic_deadline_timer/expires_from_now/overload3.html +/doc/asio/reference/basic_deadline_timer/get_implementation/ +/doc/asio/reference/basic_deadline_timer/get_implementation.html +/doc/asio/reference/basic_deadline_timer/get_implementation/overload1.html +/doc/asio/reference/basic_deadline_timer/get_implementation/overload2.html +/doc/asio/reference/basic_deadline_timer/get_io_service.html +/doc/asio/reference/basic_deadline_timer/get_service/ +/doc/asio/reference/basic_deadline_timer/get_service.html +/doc/asio/reference/basic_deadline_timer/get_service/overload1.html +/doc/asio/reference/basic_deadline_timer/get_service/overload2.html +/doc/asio/reference/basic_deadline_timer.html +/doc/asio/reference/basic_deadline_timer/implementation.html +/doc/asio/reference/basic_deadline_timer/implementation_type.html +/doc/asio/reference/basic_deadline_timer/service.html +/doc/asio/reference/basic_deadline_timer/service_type.html +/doc/asio/reference/basic_deadline_timer/time_type.html +/doc/asio/reference/basic_deadline_timer/traits_type.html +/doc/asio/reference/basic_deadline_timer/wait/ +/doc/asio/reference/basic_deadline_timer/wait.html +/doc/asio/reference/basic_deadline_timer/wait/overload1.html +/doc/asio/reference/basic_deadline_timer/wait/overload2.html +/doc/asio/reference/basic_io_object/ +/doc/asio/reference/basic_io_object/basic_io_object/ +/doc/asio/reference/basic_io_object/_basic_io_object.html +/doc/asio/reference/basic_io_object/basic_io_object.html +/doc/asio/reference/basic_io_object/basic_io_object/overload1.html +/doc/asio/reference/basic_io_object/basic_io_object/overload2.html +/doc/asio/reference/basic_io_object/get_implementation/ +/doc/asio/reference/basic_io_object/get_implementation.html +/doc/asio/reference/basic_io_object/get_implementation/overload1.html +/doc/asio/reference/basic_io_object/get_implementation/overload2.html +/doc/asio/reference/basic_io_object/get_io_service.html +/doc/asio/reference/basic_io_object/get_service/ +/doc/asio/reference/basic_io_object/get_service.html +/doc/asio/reference/basic_io_object/get_service/overload1.html +/doc/asio/reference/basic_io_object/get_service/overload2.html +/doc/asio/reference/basic_io_object.html +/doc/asio/reference/basic_io_object/implementation.html +/doc/asio/reference/basic_io_object/implementation_type.html +/doc/asio/reference/basic_io_object/operator_eq_.html +/doc/asio/reference/basic_io_object/service.html +/doc/asio/reference/basic_io_object/service_type.html +/doc/asio/reference/basic_raw_socket/ +/doc/asio/reference/basic_raw_socket/assign/ +/doc/asio/reference/basic_raw_socket/assign.html +/doc/asio/reference/basic_raw_socket/assign/overload1.html +/doc/asio/reference/basic_raw_socket/assign/overload2.html +/doc/asio/reference/basic_raw_socket/async_connect.html +/doc/asio/reference/basic_raw_socket/async_receive/ +/doc/asio/reference/basic_raw_socket/async_receive_from/ +/doc/asio/reference/basic_raw_socket/async_receive_from.html +/doc/asio/reference/basic_raw_socket/async_receive_from/overload1.html +/doc/asio/reference/basic_raw_socket/async_receive_from/overload2.html +/doc/asio/reference/basic_raw_socket/async_receive.html +/doc/asio/reference/basic_raw_socket/async_receive/overload1.html +/doc/asio/reference/basic_raw_socket/async_receive/overload2.html +/doc/asio/reference/basic_raw_socket/async_send/ +/doc/asio/reference/basic_raw_socket/async_send.html +/doc/asio/reference/basic_raw_socket/async_send/overload1.html +/doc/asio/reference/basic_raw_socket/async_send/overload2.html +/doc/asio/reference/basic_raw_socket/async_send_to/ +/doc/asio/reference/basic_raw_socket/async_send_to.html +/doc/asio/reference/basic_raw_socket/async_send_to/overload1.html +/doc/asio/reference/basic_raw_socket/async_send_to/overload2.html +/doc/asio/reference/basic_raw_socket/at_mark/ +/doc/asio/reference/basic_raw_socket/at_mark.html +/doc/asio/reference/basic_raw_socket/at_mark/overload1.html +/doc/asio/reference/basic_raw_socket/at_mark/overload2.html +/doc/asio/reference/basic_raw_socket/available/ +/doc/asio/reference/basic_raw_socket/available.html +/doc/asio/reference/basic_raw_socket/available/overload1.html +/doc/asio/reference/basic_raw_socket/available/overload2.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/ +/doc/asio/reference/basic_raw_socket/basic_raw_socket.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/overload1.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/overload2.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/overload3.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/overload4.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/overload5.html +/doc/asio/reference/basic_raw_socket/basic_raw_socket/overload6.html +/doc/asio/reference/basic_raw_socket/bind/ +/doc/asio/reference/basic_raw_socket/bind.html +/doc/asio/reference/basic_raw_socket/bind/overload1.html +/doc/asio/reference/basic_raw_socket/bind/overload2.html +/doc/asio/reference/basic_raw_socket/broadcast.html +/doc/asio/reference/basic_raw_socket/bytes_readable.html +/doc/asio/reference/basic_raw_socket/cancel/ +/doc/asio/reference/basic_raw_socket/cancel.html +/doc/asio/reference/basic_raw_socket/cancel/overload1.html +/doc/asio/reference/basic_raw_socket/cancel/overload2.html +/doc/asio/reference/basic_raw_socket/close/ +/doc/asio/reference/basic_raw_socket/close.html +/doc/asio/reference/basic_raw_socket/close/overload1.html +/doc/asio/reference/basic_raw_socket/close/overload2.html +/doc/asio/reference/basic_raw_socket/connect/ +/doc/asio/reference/basic_raw_socket/connect.html +/doc/asio/reference/basic_raw_socket/connect/overload1.html +/doc/asio/reference/basic_raw_socket/connect/overload2.html +/doc/asio/reference/basic_raw_socket/debug.html +/doc/asio/reference/basic_raw_socket/do_not_route.html +/doc/asio/reference/basic_raw_socket/enable_connection_aborted.html +/doc/asio/reference/basic_raw_socket/endpoint_type.html +/doc/asio/reference/basic_raw_socket/get_implementation/ +/doc/asio/reference/basic_raw_socket/get_implementation.html +/doc/asio/reference/basic_raw_socket/get_implementation/overload1.html +/doc/asio/reference/basic_raw_socket/get_implementation/overload2.html +/doc/asio/reference/basic_raw_socket/get_io_service.html +/doc/asio/reference/basic_raw_socket/get_option/ +/doc/asio/reference/basic_raw_socket/get_option.html +/doc/asio/reference/basic_raw_socket/get_option/overload1.html +/doc/asio/reference/basic_raw_socket/get_option/overload2.html +/doc/asio/reference/basic_raw_socket/get_service/ +/doc/asio/reference/basic_raw_socket/get_service.html +/doc/asio/reference/basic_raw_socket/get_service/overload1.html +/doc/asio/reference/basic_raw_socket/get_service/overload2.html +/doc/asio/reference/basic_raw_socket.html +/doc/asio/reference/basic_raw_socket/implementation.html +/doc/asio/reference/basic_raw_socket/implementation_type.html +/doc/asio/reference/basic_raw_socket/io_control/ +/doc/asio/reference/basic_raw_socket/io_control.html +/doc/asio/reference/basic_raw_socket/io_control/overload1.html +/doc/asio/reference/basic_raw_socket/io_control/overload2.html +/doc/asio/reference/basic_raw_socket/is_open.html +/doc/asio/reference/basic_raw_socket/keep_alive.html +/doc/asio/reference/basic_raw_socket/linger.html +/doc/asio/reference/basic_raw_socket/local_endpoint/ +/doc/asio/reference/basic_raw_socket/local_endpoint.html +/doc/asio/reference/basic_raw_socket/local_endpoint/overload1.html +/doc/asio/reference/basic_raw_socket/local_endpoint/overload2.html +/doc/asio/reference/basic_raw_socket/lowest_layer/ +/doc/asio/reference/basic_raw_socket/lowest_layer.html +/doc/asio/reference/basic_raw_socket/lowest_layer/overload1.html +/doc/asio/reference/basic_raw_socket/lowest_layer/overload2.html +/doc/asio/reference/basic_raw_socket/lowest_layer_type.html +/doc/asio/reference/basic_raw_socket/max_connections.html +/doc/asio/reference/basic_raw_socket/message_do_not_route.html +/doc/asio/reference/basic_raw_socket/message_end_of_record.html +/doc/asio/reference/basic_raw_socket/message_flags.html +/doc/asio/reference/basic_raw_socket/message_out_of_band.html +/doc/asio/reference/basic_raw_socket/message_peek.html +/doc/asio/reference/basic_raw_socket/native_handle.html +/doc/asio/reference/basic_raw_socket/native_handle_type.html +/doc/asio/reference/basic_raw_socket/native.html +/doc/asio/reference/basic_raw_socket/native_non_blocking/ +/doc/asio/reference/basic_raw_socket/native_non_blocking.html +/doc/asio/reference/basic_raw_socket/native_non_blocking/overload1.html +/doc/asio/reference/basic_raw_socket/native_non_blocking/overload2.html +/doc/asio/reference/basic_raw_socket/native_non_blocking/overload3.html +/doc/asio/reference/basic_raw_socket/native_type.html +/doc/asio/reference/basic_raw_socket/non_blocking/ +/doc/asio/reference/basic_raw_socket/non_blocking.html +/doc/asio/reference/basic_raw_socket/non_blocking_io.html +/doc/asio/reference/basic_raw_socket/non_blocking/overload1.html +/doc/asio/reference/basic_raw_socket/non_blocking/overload2.html +/doc/asio/reference/basic_raw_socket/non_blocking/overload3.html +/doc/asio/reference/basic_raw_socket/open/ +/doc/asio/reference/basic_raw_socket/open.html +/doc/asio/reference/basic_raw_socket/open/overload1.html +/doc/asio/reference/basic_raw_socket/open/overload2.html +/doc/asio/reference/basic_raw_socket/operator_eq_/ +/doc/asio/reference/basic_raw_socket/operator_eq_.html +/doc/asio/reference/basic_raw_socket/operator_eq_/overload1.html +/doc/asio/reference/basic_raw_socket/operator_eq_/overload2.html +/doc/asio/reference/basic_raw_socket/protocol_type.html +/doc/asio/reference/basic_raw_socket/receive/ +/doc/asio/reference/basic_raw_socket/receive_buffer_size.html +/doc/asio/reference/basic_raw_socket/receive_from/ +/doc/asio/reference/basic_raw_socket/receive_from.html +/doc/asio/reference/basic_raw_socket/receive_from/overload1.html +/doc/asio/reference/basic_raw_socket/receive_from/overload2.html +/doc/asio/reference/basic_raw_socket/receive_from/overload3.html +/doc/asio/reference/basic_raw_socket/receive.html +/doc/asio/reference/basic_raw_socket/receive_low_watermark.html +/doc/asio/reference/basic_raw_socket/receive/overload1.html +/doc/asio/reference/basic_raw_socket/receive/overload2.html +/doc/asio/reference/basic_raw_socket/receive/overload3.html +/doc/asio/reference/basic_raw_socket/remote_endpoint/ +/doc/asio/reference/basic_raw_socket/remote_endpoint.html +/doc/asio/reference/basic_raw_socket/remote_endpoint/overload1.html +/doc/asio/reference/basic_raw_socket/remote_endpoint/overload2.html +/doc/asio/reference/basic_raw_socket/reuse_address.html +/doc/asio/reference/basic_raw_socket/send/ +/doc/asio/reference/basic_raw_socket/send_buffer_size.html +/doc/asio/reference/basic_raw_socket/send.html +/doc/asio/reference/basic_raw_socket/send_low_watermark.html +/doc/asio/reference/basic_raw_socket/send/overload1.html +/doc/asio/reference/basic_raw_socket/send/overload2.html +/doc/asio/reference/basic_raw_socket/send/overload3.html +/doc/asio/reference/basic_raw_socket/send_to/ +/doc/asio/reference/basic_raw_socket/send_to.html +/doc/asio/reference/basic_raw_socket/send_to/overload1.html +/doc/asio/reference/basic_raw_socket/send_to/overload2.html +/doc/asio/reference/basic_raw_socket/send_to/overload3.html +/doc/asio/reference/basic_raw_socket/service.html +/doc/asio/reference/basic_raw_socket/service_type.html +/doc/asio/reference/basic_raw_socket/set_option/ +/doc/asio/reference/basic_raw_socket/set_option.html +/doc/asio/reference/basic_raw_socket/set_option/overload1.html +/doc/asio/reference/basic_raw_socket/set_option/overload2.html +/doc/asio/reference/basic_raw_socket/shutdown/ +/doc/asio/reference/basic_raw_socket/shutdown.html +/doc/asio/reference/basic_raw_socket/shutdown/overload1.html +/doc/asio/reference/basic_raw_socket/shutdown/overload2.html +/doc/asio/reference/basic_raw_socket/shutdown_type.html +/doc/asio/reference/basic_seq_packet_socket/ +/doc/asio/reference/basic_seq_packet_socket/assign/ +/doc/asio/reference/basic_seq_packet_socket/assign.html +/doc/asio/reference/basic_seq_packet_socket/assign/overload1.html +/doc/asio/reference/basic_seq_packet_socket/assign/overload2.html +/doc/asio/reference/basic_seq_packet_socket/async_connect.html +/doc/asio/reference/basic_seq_packet_socket/async_receive/ +/doc/asio/reference/basic_seq_packet_socket/async_receive.html +/doc/asio/reference/basic_seq_packet_socket/async_receive/overload1.html +/doc/asio/reference/basic_seq_packet_socket/async_receive/overload2.html +/doc/asio/reference/basic_seq_packet_socket/async_send.html +/doc/asio/reference/basic_seq_packet_socket/at_mark/ +/doc/asio/reference/basic_seq_packet_socket/at_mark.html +/doc/asio/reference/basic_seq_packet_socket/at_mark/overload1.html +/doc/asio/reference/basic_seq_packet_socket/at_mark/overload2.html +/doc/asio/reference/basic_seq_packet_socket/available/ +/doc/asio/reference/basic_seq_packet_socket/available.html +/doc/asio/reference/basic_seq_packet_socket/available/overload1.html +/doc/asio/reference/basic_seq_packet_socket/available/overload2.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/ +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload1.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload2.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload3.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload4.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload5.html +/doc/asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload6.html +/doc/asio/reference/basic_seq_packet_socket/bind/ +/doc/asio/reference/basic_seq_packet_socket/bind.html +/doc/asio/reference/basic_seq_packet_socket/bind/overload1.html +/doc/asio/reference/basic_seq_packet_socket/bind/overload2.html +/doc/asio/reference/basic_seq_packet_socket/broadcast.html +/doc/asio/reference/basic_seq_packet_socket/bytes_readable.html +/doc/asio/reference/basic_seq_packet_socket/cancel/ +/doc/asio/reference/basic_seq_packet_socket/cancel.html +/doc/asio/reference/basic_seq_packet_socket/cancel/overload1.html +/doc/asio/reference/basic_seq_packet_socket/cancel/overload2.html +/doc/asio/reference/basic_seq_packet_socket/close/ +/doc/asio/reference/basic_seq_packet_socket/close.html +/doc/asio/reference/basic_seq_packet_socket/close/overload1.html +/doc/asio/reference/basic_seq_packet_socket/close/overload2.html +/doc/asio/reference/basic_seq_packet_socket/connect/ +/doc/asio/reference/basic_seq_packet_socket/connect.html +/doc/asio/reference/basic_seq_packet_socket/connect/overload1.html +/doc/asio/reference/basic_seq_packet_socket/connect/overload2.html +/doc/asio/reference/basic_seq_packet_socket/debug.html +/doc/asio/reference/basic_seq_packet_socket/do_not_route.html +/doc/asio/reference/basic_seq_packet_socket/enable_connection_aborted.html +/doc/asio/reference/basic_seq_packet_socket/endpoint_type.html +/doc/asio/reference/basic_seq_packet_socket/get_implementation/ +/doc/asio/reference/basic_seq_packet_socket/get_implementation.html +/doc/asio/reference/basic_seq_packet_socket/get_implementation/overload1.html +/doc/asio/reference/basic_seq_packet_socket/get_implementation/overload2.html +/doc/asio/reference/basic_seq_packet_socket/get_io_service.html +/doc/asio/reference/basic_seq_packet_socket/get_option/ +/doc/asio/reference/basic_seq_packet_socket/get_option.html +/doc/asio/reference/basic_seq_packet_socket/get_option/overload1.html +/doc/asio/reference/basic_seq_packet_socket/get_option/overload2.html +/doc/asio/reference/basic_seq_packet_socket/get_service/ +/doc/asio/reference/basic_seq_packet_socket/get_service.html +/doc/asio/reference/basic_seq_packet_socket/get_service/overload1.html +/doc/asio/reference/basic_seq_packet_socket/get_service/overload2.html +/doc/asio/reference/basic_seq_packet_socket.html +/doc/asio/reference/basic_seq_packet_socket/implementation.html +/doc/asio/reference/basic_seq_packet_socket/implementation_type.html +/doc/asio/reference/basic_seq_packet_socket/io_control/ +/doc/asio/reference/basic_seq_packet_socket/io_control.html +/doc/asio/reference/basic_seq_packet_socket/io_control/overload1.html +/doc/asio/reference/basic_seq_packet_socket/io_control/overload2.html +/doc/asio/reference/basic_seq_packet_socket/is_open.html +/doc/asio/reference/basic_seq_packet_socket/keep_alive.html +/doc/asio/reference/basic_seq_packet_socket/linger.html +/doc/asio/reference/basic_seq_packet_socket/local_endpoint/ +/doc/asio/reference/basic_seq_packet_socket/local_endpoint.html +/doc/asio/reference/basic_seq_packet_socket/local_endpoint/overload1.html +/doc/asio/reference/basic_seq_packet_socket/local_endpoint/overload2.html +/doc/asio/reference/basic_seq_packet_socket/lowest_layer/ +/doc/asio/reference/basic_seq_packet_socket/lowest_layer.html +/doc/asio/reference/basic_seq_packet_socket/lowest_layer/overload1.html +/doc/asio/reference/basic_seq_packet_socket/lowest_layer/overload2.html +/doc/asio/reference/basic_seq_packet_socket/lowest_layer_type.html +/doc/asio/reference/basic_seq_packet_socket/max_connections.html +/doc/asio/reference/basic_seq_packet_socket/message_do_not_route.html +/doc/asio/reference/basic_seq_packet_socket/message_end_of_record.html +/doc/asio/reference/basic_seq_packet_socket/message_flags.html +/doc/asio/reference/basic_seq_packet_socket/message_out_of_band.html +/doc/asio/reference/basic_seq_packet_socket/message_peek.html +/doc/asio/reference/basic_seq_packet_socket/native_handle.html +/doc/asio/reference/basic_seq_packet_socket/native_handle_type.html +/doc/asio/reference/basic_seq_packet_socket/native.html +/doc/asio/reference/basic_seq_packet_socket/native_non_blocking/ +/doc/asio/reference/basic_seq_packet_socket/native_non_blocking.html +/doc/asio/reference/basic_seq_packet_socket/native_non_blocking/overload1.html +/doc/asio/reference/basic_seq_packet_socket/native_non_blocking/overload2.html +/doc/asio/reference/basic_seq_packet_socket/native_non_blocking/overload3.html +/doc/asio/reference/basic_seq_packet_socket/native_type.html +/doc/asio/reference/basic_seq_packet_socket/non_blocking/ +/doc/asio/reference/basic_seq_packet_socket/non_blocking.html +/doc/asio/reference/basic_seq_packet_socket/non_blocking_io.html +/doc/asio/reference/basic_seq_packet_socket/non_blocking/overload1.html +/doc/asio/reference/basic_seq_packet_socket/non_blocking/overload2.html +/doc/asio/reference/basic_seq_packet_socket/non_blocking/overload3.html +/doc/asio/reference/basic_seq_packet_socket/open/ +/doc/asio/reference/basic_seq_packet_socket/open.html +/doc/asio/reference/basic_seq_packet_socket/open/overload1.html +/doc/asio/reference/basic_seq_packet_socket/open/overload2.html +/doc/asio/reference/basic_seq_packet_socket/operator_eq_/ +/doc/asio/reference/basic_seq_packet_socket/operator_eq_.html +/doc/asio/reference/basic_seq_packet_socket/operator_eq_/overload1.html +/doc/asio/reference/basic_seq_packet_socket/operator_eq_/overload2.html +/doc/asio/reference/basic_seq_packet_socket/protocol_type.html +/doc/asio/reference/basic_seq_packet_socket/receive/ +/doc/asio/reference/basic_seq_packet_socket/receive_buffer_size.html +/doc/asio/reference/basic_seq_packet_socket/receive.html +/doc/asio/reference/basic_seq_packet_socket/receive_low_watermark.html +/doc/asio/reference/basic_seq_packet_socket/receive/overload1.html +/doc/asio/reference/basic_seq_packet_socket/receive/overload2.html +/doc/asio/reference/basic_seq_packet_socket/receive/overload3.html +/doc/asio/reference/basic_seq_packet_socket/remote_endpoint/ +/doc/asio/reference/basic_seq_packet_socket/remote_endpoint.html +/doc/asio/reference/basic_seq_packet_socket/remote_endpoint/overload1.html +/doc/asio/reference/basic_seq_packet_socket/remote_endpoint/overload2.html +/doc/asio/reference/basic_seq_packet_socket/reuse_address.html +/doc/asio/reference/basic_seq_packet_socket/send/ +/doc/asio/reference/basic_seq_packet_socket/send_buffer_size.html +/doc/asio/reference/basic_seq_packet_socket/send.html +/doc/asio/reference/basic_seq_packet_socket/send_low_watermark.html +/doc/asio/reference/basic_seq_packet_socket/send/overload1.html +/doc/asio/reference/basic_seq_packet_socket/send/overload2.html +/doc/asio/reference/basic_seq_packet_socket/service.html +/doc/asio/reference/basic_seq_packet_socket/service_type.html +/doc/asio/reference/basic_seq_packet_socket/set_option/ +/doc/asio/reference/basic_seq_packet_socket/set_option.html +/doc/asio/reference/basic_seq_packet_socket/set_option/overload1.html +/doc/asio/reference/basic_seq_packet_socket/set_option/overload2.html +/doc/asio/reference/basic_seq_packet_socket/shutdown/ +/doc/asio/reference/basic_seq_packet_socket/shutdown.html +/doc/asio/reference/basic_seq_packet_socket/shutdown/overload1.html +/doc/asio/reference/basic_seq_packet_socket/shutdown/overload2.html +/doc/asio/reference/basic_seq_packet_socket/shutdown_type.html +/doc/asio/reference/basic_serial_port/ +/doc/asio/reference/basic_serial_port/assign/ +/doc/asio/reference/basic_serial_port/assign.html +/doc/asio/reference/basic_serial_port/assign/overload1.html +/doc/asio/reference/basic_serial_port/assign/overload2.html +/doc/asio/reference/basic_serial_port/async_read_some.html +/doc/asio/reference/basic_serial_port/async_write_some.html +/doc/asio/reference/basic_serial_port/basic_serial_port/ +/doc/asio/reference/basic_serial_port/basic_serial_port.html +/doc/asio/reference/basic_serial_port/basic_serial_port/overload1.html +/doc/asio/reference/basic_serial_port/basic_serial_port/overload2.html +/doc/asio/reference/basic_serial_port/basic_serial_port/overload3.html +/doc/asio/reference/basic_serial_port/basic_serial_port/overload4.html +/doc/asio/reference/basic_serial_port/basic_serial_port/overload5.html +/doc/asio/reference/basic_serial_port/cancel/ +/doc/asio/reference/basic_serial_port/cancel.html +/doc/asio/reference/basic_serial_port/cancel/overload1.html +/doc/asio/reference/basic_serial_port/cancel/overload2.html +/doc/asio/reference/basic_serial_port/close/ +/doc/asio/reference/basic_serial_port/close.html +/doc/asio/reference/basic_serial_port/close/overload1.html +/doc/asio/reference/basic_serial_port/close/overload2.html +/doc/asio/reference/basic_serial_port/get_implementation/ +/doc/asio/reference/basic_serial_port/get_implementation.html +/doc/asio/reference/basic_serial_port/get_implementation/overload1.html +/doc/asio/reference/basic_serial_port/get_implementation/overload2.html +/doc/asio/reference/basic_serial_port/get_io_service.html +/doc/asio/reference/basic_serial_port/get_option/ +/doc/asio/reference/basic_serial_port/get_option.html +/doc/asio/reference/basic_serial_port/get_option/overload1.html +/doc/asio/reference/basic_serial_port/get_option/overload2.html +/doc/asio/reference/basic_serial_port/get_service/ +/doc/asio/reference/basic_serial_port/get_service.html +/doc/asio/reference/basic_serial_port/get_service/overload1.html +/doc/asio/reference/basic_serial_port/get_service/overload2.html +/doc/asio/reference/basic_serial_port.html +/doc/asio/reference/basic_serial_port/implementation.html +/doc/asio/reference/basic_serial_port/implementation_type.html +/doc/asio/reference/basic_serial_port/is_open.html +/doc/asio/reference/basic_serial_port/lowest_layer/ +/doc/asio/reference/basic_serial_port/lowest_layer.html +/doc/asio/reference/basic_serial_port/lowest_layer/overload1.html +/doc/asio/reference/basic_serial_port/lowest_layer/overload2.html +/doc/asio/reference/basic_serial_port/lowest_layer_type.html +/doc/asio/reference/basic_serial_port/native_handle.html +/doc/asio/reference/basic_serial_port/native_handle_type.html +/doc/asio/reference/basic_serial_port/native.html +/doc/asio/reference/basic_serial_port/native_type.html +/doc/asio/reference/basic_serial_port/open/ +/doc/asio/reference/basic_serial_port/open.html +/doc/asio/reference/basic_serial_port/open/overload1.html +/doc/asio/reference/basic_serial_port/open/overload2.html +/doc/asio/reference/basic_serial_port/operator_eq_.html +/doc/asio/reference/basic_serial_port/read_some/ +/doc/asio/reference/basic_serial_port/read_some.html +/doc/asio/reference/basic_serial_port/read_some/overload1.html +/doc/asio/reference/basic_serial_port/read_some/overload2.html +/doc/asio/reference/basic_serial_port/send_break/ +/doc/asio/reference/basic_serial_port/send_break.html +/doc/asio/reference/basic_serial_port/send_break/overload1.html +/doc/asio/reference/basic_serial_port/send_break/overload2.html +/doc/asio/reference/basic_serial_port/service.html +/doc/asio/reference/basic_serial_port/service_type.html +/doc/asio/reference/basic_serial_port/set_option/ +/doc/asio/reference/basic_serial_port/set_option.html +/doc/asio/reference/basic_serial_port/set_option/overload1.html +/doc/asio/reference/basic_serial_port/set_option/overload2.html +/doc/asio/reference/basic_serial_port/write_some/ +/doc/asio/reference/basic_serial_port/write_some.html +/doc/asio/reference/basic_serial_port/write_some/overload1.html +/doc/asio/reference/basic_serial_port/write_some/overload2.html +/doc/asio/reference/basic_signal_set/ +/doc/asio/reference/basic_signal_set/add/ +/doc/asio/reference/basic_signal_set/add.html +/doc/asio/reference/basic_signal_set/add/overload1.html +/doc/asio/reference/basic_signal_set/add/overload2.html +/doc/asio/reference/basic_signal_set/async_wait.html +/doc/asio/reference/basic_signal_set/basic_signal_set/ +/doc/asio/reference/basic_signal_set/basic_signal_set.html +/doc/asio/reference/basic_signal_set/basic_signal_set/overload1.html +/doc/asio/reference/basic_signal_set/basic_signal_set/overload2.html +/doc/asio/reference/basic_signal_set/basic_signal_set/overload3.html +/doc/asio/reference/basic_signal_set/basic_signal_set/overload4.html +/doc/asio/reference/basic_signal_set/cancel/ +/doc/asio/reference/basic_signal_set/cancel.html +/doc/asio/reference/basic_signal_set/cancel/overload1.html +/doc/asio/reference/basic_signal_set/cancel/overload2.html +/doc/asio/reference/basic_signal_set/clear/ +/doc/asio/reference/basic_signal_set/clear.html +/doc/asio/reference/basic_signal_set/clear/overload1.html +/doc/asio/reference/basic_signal_set/clear/overload2.html +/doc/asio/reference/basic_signal_set/get_implementation/ +/doc/asio/reference/basic_signal_set/get_implementation.html +/doc/asio/reference/basic_signal_set/get_implementation/overload1.html +/doc/asio/reference/basic_signal_set/get_implementation/overload2.html +/doc/asio/reference/basic_signal_set/get_io_service.html +/doc/asio/reference/basic_signal_set/get_service/ +/doc/asio/reference/basic_signal_set/get_service.html +/doc/asio/reference/basic_signal_set/get_service/overload1.html +/doc/asio/reference/basic_signal_set/get_service/overload2.html +/doc/asio/reference/basic_signal_set.html +/doc/asio/reference/basic_signal_set/implementation.html +/doc/asio/reference/basic_signal_set/implementation_type.html +/doc/asio/reference/basic_signal_set/remove/ +/doc/asio/reference/basic_signal_set/remove.html +/doc/asio/reference/basic_signal_set/remove/overload1.html +/doc/asio/reference/basic_signal_set/remove/overload2.html +/doc/asio/reference/basic_signal_set/service.html +/doc/asio/reference/basic_signal_set/service_type.html +/doc/asio/reference/basic_socket/ +/doc/asio/reference/basic_socket_acceptor/ +/doc/asio/reference/basic_socket_acceptor/accept/ +/doc/asio/reference/basic_socket_acceptor/accept.html +/doc/asio/reference/basic_socket_acceptor/accept/overload1.html +/doc/asio/reference/basic_socket_acceptor/accept/overload2.html +/doc/asio/reference/basic_socket_acceptor/accept/overload3.html +/doc/asio/reference/basic_socket_acceptor/accept/overload4.html +/doc/asio/reference/basic_socket_acceptor/assign/ +/doc/asio/reference/basic_socket_acceptor/assign.html +/doc/asio/reference/basic_socket_acceptor/assign/overload1.html +/doc/asio/reference/basic_socket_acceptor/assign/overload2.html +/doc/asio/reference/basic_socket_acceptor/async_accept/ +/doc/asio/reference/basic_socket_acceptor/async_accept.html +/doc/asio/reference/basic_socket_acceptor/async_accept/overload1.html +/doc/asio/reference/basic_socket_acceptor/async_accept/overload2.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/ +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload1.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload2.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload3.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload4.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload5.html +/doc/asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload6.html +/doc/asio/reference/basic_socket_acceptor/bind/ +/doc/asio/reference/basic_socket_acceptor/bind.html +/doc/asio/reference/basic_socket_acceptor/bind/overload1.html +/doc/asio/reference/basic_socket_acceptor/bind/overload2.html +/doc/asio/reference/basic_socket_acceptor/broadcast.html +/doc/asio/reference/basic_socket_acceptor/bytes_readable.html +/doc/asio/reference/basic_socket_acceptor/cancel/ +/doc/asio/reference/basic_socket_acceptor/cancel.html +/doc/asio/reference/basic_socket_acceptor/cancel/overload1.html +/doc/asio/reference/basic_socket_acceptor/cancel/overload2.html +/doc/asio/reference/basic_socket_acceptor/close/ +/doc/asio/reference/basic_socket_acceptor/close.html +/doc/asio/reference/basic_socket_acceptor/close/overload1.html +/doc/asio/reference/basic_socket_acceptor/close/overload2.html +/doc/asio/reference/basic_socket_acceptor/debug.html +/doc/asio/reference/basic_socket_acceptor/do_not_route.html +/doc/asio/reference/basic_socket_acceptor/enable_connection_aborted.html +/doc/asio/reference/basic_socket_acceptor/endpoint_type.html +/doc/asio/reference/basic_socket_acceptor/get_implementation/ +/doc/asio/reference/basic_socket_acceptor/get_implementation.html +/doc/asio/reference/basic_socket_acceptor/get_implementation/overload1.html +/doc/asio/reference/basic_socket_acceptor/get_implementation/overload2.html +/doc/asio/reference/basic_socket_acceptor/get_io_service.html +/doc/asio/reference/basic_socket_acceptor/get_option/ +/doc/asio/reference/basic_socket_acceptor/get_option.html +/doc/asio/reference/basic_socket_acceptor/get_option/overload1.html +/doc/asio/reference/basic_socket_acceptor/get_option/overload2.html +/doc/asio/reference/basic_socket_acceptor/get_service/ +/doc/asio/reference/basic_socket_acceptor/get_service.html +/doc/asio/reference/basic_socket_acceptor/get_service/overload1.html +/doc/asio/reference/basic_socket_acceptor/get_service/overload2.html +/doc/asio/reference/basic_socket_acceptor.html +/doc/asio/reference/basic_socket_acceptor/implementation.html +/doc/asio/reference/basic_socket_acceptor/implementation_type.html +/doc/asio/reference/basic_socket_acceptor/io_control/ +/doc/asio/reference/basic_socket_acceptor/io_control.html +/doc/asio/reference/basic_socket_acceptor/io_control/overload1.html +/doc/asio/reference/basic_socket_acceptor/io_control/overload2.html +/doc/asio/reference/basic_socket_acceptor/is_open.html +/doc/asio/reference/basic_socket_acceptor/keep_alive.html +/doc/asio/reference/basic_socket_acceptor/linger.html +/doc/asio/reference/basic_socket_acceptor/listen/ +/doc/asio/reference/basic_socket_acceptor/listen.html +/doc/asio/reference/basic_socket_acceptor/listen/overload1.html +/doc/asio/reference/basic_socket_acceptor/listen/overload2.html +/doc/asio/reference/basic_socket_acceptor/local_endpoint/ +/doc/asio/reference/basic_socket_acceptor/local_endpoint.html +/doc/asio/reference/basic_socket_acceptor/local_endpoint/overload1.html +/doc/asio/reference/basic_socket_acceptor/local_endpoint/overload2.html +/doc/asio/reference/basic_socket_acceptor/max_connections.html +/doc/asio/reference/basic_socket_acceptor/message_do_not_route.html +/doc/asio/reference/basic_socket_acceptor/message_end_of_record.html +/doc/asio/reference/basic_socket_acceptor/message_flags.html +/doc/asio/reference/basic_socket_acceptor/message_out_of_band.html +/doc/asio/reference/basic_socket_acceptor/message_peek.html +/doc/asio/reference/basic_socket_acceptor/native_handle.html +/doc/asio/reference/basic_socket_acceptor/native_handle_type.html +/doc/asio/reference/basic_socket_acceptor/native.html +/doc/asio/reference/basic_socket_acceptor/native_non_blocking/ +/doc/asio/reference/basic_socket_acceptor/native_non_blocking.html +/doc/asio/reference/basic_socket_acceptor/native_non_blocking/overload1.html +/doc/asio/reference/basic_socket_acceptor/native_non_blocking/overload2.html +/doc/asio/reference/basic_socket_acceptor/native_non_blocking/overload3.html +/doc/asio/reference/basic_socket_acceptor/native_type.html +/doc/asio/reference/basic_socket_acceptor/non_blocking/ +/doc/asio/reference/basic_socket_acceptor/non_blocking.html +/doc/asio/reference/basic_socket_acceptor/non_blocking_io.html +/doc/asio/reference/basic_socket_acceptor/non_blocking/overload1.html +/doc/asio/reference/basic_socket_acceptor/non_blocking/overload2.html +/doc/asio/reference/basic_socket_acceptor/non_blocking/overload3.html +/doc/asio/reference/basic_socket_acceptor/open/ +/doc/asio/reference/basic_socket_acceptor/open.html +/doc/asio/reference/basic_socket_acceptor/open/overload1.html +/doc/asio/reference/basic_socket_acceptor/open/overload2.html +/doc/asio/reference/basic_socket_acceptor/operator_eq_/ +/doc/asio/reference/basic_socket_acceptor/operator_eq_.html +/doc/asio/reference/basic_socket_acceptor/operator_eq_/overload1.html +/doc/asio/reference/basic_socket_acceptor/operator_eq_/overload2.html +/doc/asio/reference/basic_socket_acceptor/protocol_type.html +/doc/asio/reference/basic_socket_acceptor/receive_buffer_size.html +/doc/asio/reference/basic_socket_acceptor/receive_low_watermark.html +/doc/asio/reference/basic_socket_acceptor/reuse_address.html +/doc/asio/reference/basic_socket_acceptor/send_buffer_size.html +/doc/asio/reference/basic_socket_acceptor/send_low_watermark.html +/doc/asio/reference/basic_socket_acceptor/service.html +/doc/asio/reference/basic_socket_acceptor/service_type.html +/doc/asio/reference/basic_socket_acceptor/set_option/ +/doc/asio/reference/basic_socket_acceptor/set_option.html +/doc/asio/reference/basic_socket_acceptor/set_option/overload1.html +/doc/asio/reference/basic_socket_acceptor/set_option/overload2.html +/doc/asio/reference/basic_socket_acceptor/shutdown_type.html +/doc/asio/reference/basic_socket/assign/ +/doc/asio/reference/basic_socket/assign.html +/doc/asio/reference/basic_socket/assign/overload1.html +/doc/asio/reference/basic_socket/assign/overload2.html +/doc/asio/reference/basic_socket/async_connect.html +/doc/asio/reference/basic_socket/at_mark/ +/doc/asio/reference/basic_socket/at_mark.html +/doc/asio/reference/basic_socket/at_mark/overload1.html +/doc/asio/reference/basic_socket/at_mark/overload2.html +/doc/asio/reference/basic_socket/available/ +/doc/asio/reference/basic_socket/available.html +/doc/asio/reference/basic_socket/available/overload1.html +/doc/asio/reference/basic_socket/available/overload2.html +/doc/asio/reference/basic_socket/basic_socket/ +/doc/asio/reference/basic_socket/_basic_socket.html +/doc/asio/reference/basic_socket/basic_socket.html +/doc/asio/reference/basic_socket/basic_socket/overload1.html +/doc/asio/reference/basic_socket/basic_socket/overload2.html +/doc/asio/reference/basic_socket/basic_socket/overload3.html +/doc/asio/reference/basic_socket/basic_socket/overload4.html +/doc/asio/reference/basic_socket/basic_socket/overload5.html +/doc/asio/reference/basic_socket/basic_socket/overload6.html +/doc/asio/reference/basic_socket/bind/ +/doc/asio/reference/basic_socket/bind.html +/doc/asio/reference/basic_socket/bind/overload1.html +/doc/asio/reference/basic_socket/bind/overload2.html +/doc/asio/reference/basic_socket/broadcast.html +/doc/asio/reference/basic_socket/bytes_readable.html +/doc/asio/reference/basic_socket/cancel/ +/doc/asio/reference/basic_socket/cancel.html +/doc/asio/reference/basic_socket/cancel/overload1.html +/doc/asio/reference/basic_socket/cancel/overload2.html +/doc/asio/reference/basic_socket/close/ +/doc/asio/reference/basic_socket/close.html +/doc/asio/reference/basic_socket/close/overload1.html +/doc/asio/reference/basic_socket/close/overload2.html +/doc/asio/reference/basic_socket/connect/ +/doc/asio/reference/basic_socket/connect.html +/doc/asio/reference/basic_socket/connect/overload1.html +/doc/asio/reference/basic_socket/connect/overload2.html +/doc/asio/reference/basic_socket/debug.html +/doc/asio/reference/basic_socket/do_not_route.html +/doc/asio/reference/basic_socket/enable_connection_aborted.html +/doc/asio/reference/basic_socket/endpoint_type.html +/doc/asio/reference/basic_socket/get_implementation/ +/doc/asio/reference/basic_socket/get_implementation.html +/doc/asio/reference/basic_socket/get_implementation/overload1.html +/doc/asio/reference/basic_socket/get_implementation/overload2.html +/doc/asio/reference/basic_socket/get_io_service.html +/doc/asio/reference/basic_socket/get_option/ +/doc/asio/reference/basic_socket/get_option.html +/doc/asio/reference/basic_socket/get_option/overload1.html +/doc/asio/reference/basic_socket/get_option/overload2.html +/doc/asio/reference/basic_socket/get_service/ +/doc/asio/reference/basic_socket/get_service.html +/doc/asio/reference/basic_socket/get_service/overload1.html +/doc/asio/reference/basic_socket/get_service/overload2.html +/doc/asio/reference/basic_socket.html +/doc/asio/reference/basic_socket/implementation.html +/doc/asio/reference/basic_socket/implementation_type.html +/doc/asio/reference/basic_socket/io_control/ +/doc/asio/reference/basic_socket/io_control.html +/doc/asio/reference/basic_socket/io_control/overload1.html +/doc/asio/reference/basic_socket/io_control/overload2.html +/doc/asio/reference/basic_socket_iostream/ +/doc/asio/reference/basic_socket_iostream/basic_socket_iostream/ +/doc/asio/reference/basic_socket_iostream/basic_socket_iostream.html +/doc/asio/reference/basic_socket_iostream/basic_socket_iostream/overload1.html +/doc/asio/reference/basic_socket_iostream/basic_socket_iostream/overload2.html +/doc/asio/reference/basic_socket_iostream/close.html +/doc/asio/reference/basic_socket_iostream/connect.html +/doc/asio/reference/basic_socket_iostream/duration_type.html +/doc/asio/reference/basic_socket_iostream/endpoint_type.html +/doc/asio/reference/basic_socket_iostream/error.html +/doc/asio/reference/basic_socket_iostream/expires_at/ +/doc/asio/reference/basic_socket_iostream/expires_at.html +/doc/asio/reference/basic_socket_iostream/expires_at/overload1.html +/doc/asio/reference/basic_socket_iostream/expires_at/overload2.html +/doc/asio/reference/basic_socket_iostream/expires_from_now/ +/doc/asio/reference/basic_socket_iostream/expires_from_now.html +/doc/asio/reference/basic_socket_iostream/expires_from_now/overload1.html +/doc/asio/reference/basic_socket_iostream/expires_from_now/overload2.html +/doc/asio/reference/basic_socket_iostream.html +/doc/asio/reference/basic_socket_iostream/rdbuf.html +/doc/asio/reference/basic_socket_iostream/time_type.html +/doc/asio/reference/basic_socket/is_open.html +/doc/asio/reference/basic_socket/keep_alive.html +/doc/asio/reference/basic_socket/linger.html +/doc/asio/reference/basic_socket/local_endpoint/ +/doc/asio/reference/basic_socket/local_endpoint.html +/doc/asio/reference/basic_socket/local_endpoint/overload1.html +/doc/asio/reference/basic_socket/local_endpoint/overload2.html +/doc/asio/reference/basic_socket/lowest_layer/ +/doc/asio/reference/basic_socket/lowest_layer.html +/doc/asio/reference/basic_socket/lowest_layer/overload1.html +/doc/asio/reference/basic_socket/lowest_layer/overload2.html +/doc/asio/reference/basic_socket/lowest_layer_type.html +/doc/asio/reference/basic_socket/max_connections.html +/doc/asio/reference/basic_socket/message_do_not_route.html +/doc/asio/reference/basic_socket/message_end_of_record.html +/doc/asio/reference/basic_socket/message_flags.html +/doc/asio/reference/basic_socket/message_out_of_band.html +/doc/asio/reference/basic_socket/message_peek.html +/doc/asio/reference/basic_socket/native_handle.html +/doc/asio/reference/basic_socket/native_handle_type.html +/doc/asio/reference/basic_socket/native.html +/doc/asio/reference/basic_socket/native_non_blocking/ +/doc/asio/reference/basic_socket/native_non_blocking.html +/doc/asio/reference/basic_socket/native_non_blocking/overload1.html +/doc/asio/reference/basic_socket/native_non_blocking/overload2.html +/doc/asio/reference/basic_socket/native_non_blocking/overload3.html +/doc/asio/reference/basic_socket/native_type.html +/doc/asio/reference/basic_socket/non_blocking/ +/doc/asio/reference/basic_socket/non_blocking.html +/doc/asio/reference/basic_socket/non_blocking_io.html +/doc/asio/reference/basic_socket/non_blocking/overload1.html +/doc/asio/reference/basic_socket/non_blocking/overload2.html +/doc/asio/reference/basic_socket/non_blocking/overload3.html +/doc/asio/reference/basic_socket/open/ +/doc/asio/reference/basic_socket/open.html +/doc/asio/reference/basic_socket/open/overload1.html +/doc/asio/reference/basic_socket/open/overload2.html +/doc/asio/reference/basic_socket/operator_eq_/ +/doc/asio/reference/basic_socket/operator_eq_.html +/doc/asio/reference/basic_socket/operator_eq_/overload1.html +/doc/asio/reference/basic_socket/operator_eq_/overload2.html +/doc/asio/reference/basic_socket/protocol_type.html +/doc/asio/reference/basic_socket/receive_buffer_size.html +/doc/asio/reference/basic_socket/receive_low_watermark.html +/doc/asio/reference/basic_socket/remote_endpoint/ +/doc/asio/reference/basic_socket/remote_endpoint.html +/doc/asio/reference/basic_socket/remote_endpoint/overload1.html +/doc/asio/reference/basic_socket/remote_endpoint/overload2.html +/doc/asio/reference/basic_socket/reuse_address.html +/doc/asio/reference/basic_socket/send_buffer_size.html +/doc/asio/reference/basic_socket/send_low_watermark.html +/doc/asio/reference/basic_socket/service.html +/doc/asio/reference/basic_socket/service_type.html +/doc/asio/reference/basic_socket/set_option/ +/doc/asio/reference/basic_socket/set_option.html +/doc/asio/reference/basic_socket/set_option/overload1.html +/doc/asio/reference/basic_socket/set_option/overload2.html +/doc/asio/reference/basic_socket/shutdown/ +/doc/asio/reference/basic_socket/shutdown.html +/doc/asio/reference/basic_socket/shutdown/overload1.html +/doc/asio/reference/basic_socket/shutdown/overload2.html +/doc/asio/reference/basic_socket/shutdown_type.html +/doc/asio/reference/basic_socket_streambuf/ +/doc/asio/reference/basic_socket_streambuf/assign/ +/doc/asio/reference/basic_socket_streambuf/assign.html +/doc/asio/reference/basic_socket_streambuf/assign/overload1.html +/doc/asio/reference/basic_socket_streambuf/assign/overload2.html +/doc/asio/reference/basic_socket_streambuf/async_connect.html +/doc/asio/reference/basic_socket_streambuf/at_mark/ +/doc/asio/reference/basic_socket_streambuf/at_mark.html +/doc/asio/reference/basic_socket_streambuf/at_mark/overload1.html +/doc/asio/reference/basic_socket_streambuf/at_mark/overload2.html +/doc/asio/reference/basic_socket_streambuf/available/ +/doc/asio/reference/basic_socket_streambuf/available.html +/doc/asio/reference/basic_socket_streambuf/available/overload1.html +/doc/asio/reference/basic_socket_streambuf/available/overload2.html +/doc/asio/reference/basic_socket_streambuf/_basic_socket_streambuf.html +/doc/asio/reference/basic_socket_streambuf/basic_socket_streambuf.html +/doc/asio/reference/basic_socket_streambuf/bind/ +/doc/asio/reference/basic_socket_streambuf/bind.html +/doc/asio/reference/basic_socket_streambuf/bind/overload1.html +/doc/asio/reference/basic_socket_streambuf/bind/overload2.html +/doc/asio/reference/basic_socket_streambuf/broadcast.html +/doc/asio/reference/basic_socket_streambuf/bytes_readable.html +/doc/asio/reference/basic_socket_streambuf/cancel/ +/doc/asio/reference/basic_socket_streambuf/cancel.html +/doc/asio/reference/basic_socket_streambuf/cancel/overload1.html +/doc/asio/reference/basic_socket_streambuf/cancel/overload2.html +/doc/asio/reference/basic_socket_streambuf/close/ +/doc/asio/reference/basic_socket_streambuf/close.html +/doc/asio/reference/basic_socket_streambuf/close/overload1.html +/doc/asio/reference/basic_socket_streambuf/close/overload2.html +/doc/asio/reference/basic_socket_streambuf/connect/ +/doc/asio/reference/basic_socket_streambuf/connect.html +/doc/asio/reference/basic_socket_streambuf/connect/overload1.html +/doc/asio/reference/basic_socket_streambuf/connect/overload2.html +/doc/asio/reference/basic_socket_streambuf/connect/overload3.html +/doc/asio/reference/basic_socket_streambuf/debug.html +/doc/asio/reference/basic_socket_streambuf/do_not_route.html +/doc/asio/reference/basic_socket_streambuf/duration_type.html +/doc/asio/reference/basic_socket_streambuf/enable_connection_aborted.html +/doc/asio/reference/basic_socket_streambuf/endpoint_type.html +/doc/asio/reference/basic_socket_streambuf/error.html +/doc/asio/reference/basic_socket_streambuf/expires_at/ +/doc/asio/reference/basic_socket_streambuf/expires_at.html +/doc/asio/reference/basic_socket_streambuf/expires_at/overload1.html +/doc/asio/reference/basic_socket_streambuf/expires_at/overload2.html +/doc/asio/reference/basic_socket_streambuf/expires_from_now/ +/doc/asio/reference/basic_socket_streambuf/expires_from_now.html +/doc/asio/reference/basic_socket_streambuf/expires_from_now/overload1.html +/doc/asio/reference/basic_socket_streambuf/expires_from_now/overload2.html +/doc/asio/reference/basic_socket_streambuf/get_implementation/ +/doc/asio/reference/basic_socket_streambuf/get_implementation.html +/doc/asio/reference/basic_socket_streambuf/get_implementation/overload1.html +/doc/asio/reference/basic_socket_streambuf/get_implementation/overload2.html +/doc/asio/reference/basic_socket_streambuf/get_io_service.html +/doc/asio/reference/basic_socket_streambuf/get_option/ +/doc/asio/reference/basic_socket_streambuf/get_option.html +/doc/asio/reference/basic_socket_streambuf/get_option/overload1.html +/doc/asio/reference/basic_socket_streambuf/get_option/overload2.html +/doc/asio/reference/basic_socket_streambuf/get_service/ +/doc/asio/reference/basic_socket_streambuf/get_service.html +/doc/asio/reference/basic_socket_streambuf/get_service/overload1.html +/doc/asio/reference/basic_socket_streambuf/get_service/overload2.html +/doc/asio/reference/basic_socket_streambuf.html +/doc/asio/reference/basic_socket_streambuf/implementation.html +/doc/asio/reference/basic_socket_streambuf/implementation_type.html +/doc/asio/reference/basic_socket_streambuf/io_control/ +/doc/asio/reference/basic_socket_streambuf/io_control.html +/doc/asio/reference/basic_socket_streambuf/io_control/overload1.html +/doc/asio/reference/basic_socket_streambuf/io_control/overload2.html +/doc/asio/reference/basic_socket_streambuf/io_handler.html +/doc/asio/reference/basic_socket_streambuf/is_open.html +/doc/asio/reference/basic_socket_streambuf/keep_alive.html +/doc/asio/reference/basic_socket_streambuf/linger.html +/doc/asio/reference/basic_socket_streambuf/local_endpoint/ +/doc/asio/reference/basic_socket_streambuf/local_endpoint.html +/doc/asio/reference/basic_socket_streambuf/local_endpoint/overload1.html +/doc/asio/reference/basic_socket_streambuf/local_endpoint/overload2.html +/doc/asio/reference/basic_socket_streambuf/lowest_layer/ +/doc/asio/reference/basic_socket_streambuf/lowest_layer.html +/doc/asio/reference/basic_socket_streambuf/lowest_layer/overload1.html +/doc/asio/reference/basic_socket_streambuf/lowest_layer/overload2.html +/doc/asio/reference/basic_socket_streambuf/lowest_layer_type.html +/doc/asio/reference/basic_socket_streambuf/max_connections.html +/doc/asio/reference/basic_socket_streambuf/message_do_not_route.html +/doc/asio/reference/basic_socket_streambuf/message_end_of_record.html +/doc/asio/reference/basic_socket_streambuf/message_flags.html +/doc/asio/reference/basic_socket_streambuf/message_out_of_band.html +/doc/asio/reference/basic_socket_streambuf/message_peek.html +/doc/asio/reference/basic_socket_streambuf/native_handle.html +/doc/asio/reference/basic_socket_streambuf/native_handle_type.html +/doc/asio/reference/basic_socket_streambuf/native.html +/doc/asio/reference/basic_socket_streambuf/native_non_blocking/ +/doc/asio/reference/basic_socket_streambuf/native_non_blocking.html +/doc/asio/reference/basic_socket_streambuf/native_non_blocking/overload1.html +/doc/asio/reference/basic_socket_streambuf/native_non_blocking/overload2.html +/doc/asio/reference/basic_socket_streambuf/native_non_blocking/overload3.html +/doc/asio/reference/basic_socket_streambuf/native_type.html +/doc/asio/reference/basic_socket_streambuf/non_blocking/ +/doc/asio/reference/basic_socket_streambuf/non_blocking.html +/doc/asio/reference/basic_socket_streambuf/non_blocking_io.html +/doc/asio/reference/basic_socket_streambuf/non_blocking/overload1.html +/doc/asio/reference/basic_socket_streambuf/non_blocking/overload2.html +/doc/asio/reference/basic_socket_streambuf/non_blocking/overload3.html +/doc/asio/reference/basic_socket_streambuf/open/ +/doc/asio/reference/basic_socket_streambuf/open.html +/doc/asio/reference/basic_socket_streambuf/open/overload1.html +/doc/asio/reference/basic_socket_streambuf/open/overload2.html +/doc/asio/reference/basic_socket_streambuf/overflow.html +/doc/asio/reference/basic_socket_streambuf/protocol_type.html +/doc/asio/reference/basic_socket_streambuf/puberror.html +/doc/asio/reference/basic_socket_streambuf/receive_buffer_size.html +/doc/asio/reference/basic_socket_streambuf/receive_low_watermark.html +/doc/asio/reference/basic_socket_streambuf/remote_endpoint/ +/doc/asio/reference/basic_socket_streambuf/remote_endpoint.html +/doc/asio/reference/basic_socket_streambuf/remote_endpoint/overload1.html +/doc/asio/reference/basic_socket_streambuf/remote_endpoint/overload2.html +/doc/asio/reference/basic_socket_streambuf/reuse_address.html +/doc/asio/reference/basic_socket_streambuf/send_buffer_size.html +/doc/asio/reference/basic_socket_streambuf/send_low_watermark.html +/doc/asio/reference/basic_socket_streambuf/service.html +/doc/asio/reference/basic_socket_streambuf/service_type.html +/doc/asio/reference/basic_socket_streambuf/setbuf.html +/doc/asio/reference/basic_socket_streambuf/set_option/ +/doc/asio/reference/basic_socket_streambuf/set_option.html +/doc/asio/reference/basic_socket_streambuf/set_option/overload1.html +/doc/asio/reference/basic_socket_streambuf/set_option/overload2.html +/doc/asio/reference/basic_socket_streambuf/shutdown/ +/doc/asio/reference/basic_socket_streambuf/shutdown.html +/doc/asio/reference/basic_socket_streambuf/shutdown/overload1.html +/doc/asio/reference/basic_socket_streambuf/shutdown/overload2.html +/doc/asio/reference/basic_socket_streambuf/shutdown_type.html +/doc/asio/reference/basic_socket_streambuf/sync.html +/doc/asio/reference/basic_socket_streambuf/timer_handler.html +/doc/asio/reference/basic_socket_streambuf/time_type.html +/doc/asio/reference/basic_socket_streambuf/underflow.html +/doc/asio/reference/basic_streambuf/ +/doc/asio/reference/basic_streambuf/basic_streambuf.html +/doc/asio/reference/basic_streambuf/commit.html +/doc/asio/reference/basic_streambuf/const_buffers_type.html +/doc/asio/reference/basic_streambuf/consume.html +/doc/asio/reference/basic_streambuf/data.html +/doc/asio/reference/basic_streambuf.html +/doc/asio/reference/basic_streambuf/max_size.html +/doc/asio/reference/basic_streambuf/mutable_buffers_type.html +/doc/asio/reference/basic_streambuf/overflow.html +/doc/asio/reference/basic_streambuf/prepare.html +/doc/asio/reference/basic_streambuf/reserve.html +/doc/asio/reference/basic_streambuf/size.html +/doc/asio/reference/basic_streambuf/underflow.html +/doc/asio/reference/basic_stream_socket/ +/doc/asio/reference/basic_stream_socket/assign/ +/doc/asio/reference/basic_stream_socket/assign.html +/doc/asio/reference/basic_stream_socket/assign/overload1.html +/doc/asio/reference/basic_stream_socket/assign/overload2.html +/doc/asio/reference/basic_stream_socket/async_connect.html +/doc/asio/reference/basic_stream_socket/async_read_some.html +/doc/asio/reference/basic_stream_socket/async_receive/ +/doc/asio/reference/basic_stream_socket/async_receive.html +/doc/asio/reference/basic_stream_socket/async_receive/overload1.html +/doc/asio/reference/basic_stream_socket/async_receive/overload2.html +/doc/asio/reference/basic_stream_socket/async_send/ +/doc/asio/reference/basic_stream_socket/async_send.html +/doc/asio/reference/basic_stream_socket/async_send/overload1.html +/doc/asio/reference/basic_stream_socket/async_send/overload2.html +/doc/asio/reference/basic_stream_socket/async_write_some.html +/doc/asio/reference/basic_stream_socket/at_mark/ +/doc/asio/reference/basic_stream_socket/at_mark.html +/doc/asio/reference/basic_stream_socket/at_mark/overload1.html +/doc/asio/reference/basic_stream_socket/at_mark/overload2.html +/doc/asio/reference/basic_stream_socket/available/ +/doc/asio/reference/basic_stream_socket/available.html +/doc/asio/reference/basic_stream_socket/available/overload1.html +/doc/asio/reference/basic_stream_socket/available/overload2.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/ +/doc/asio/reference/basic_stream_socket/basic_stream_socket.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/overload1.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/overload2.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/overload3.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/overload4.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/overload5.html +/doc/asio/reference/basic_stream_socket/basic_stream_socket/overload6.html +/doc/asio/reference/basic_stream_socket/bind/ +/doc/asio/reference/basic_stream_socket/bind.html +/doc/asio/reference/basic_stream_socket/bind/overload1.html +/doc/asio/reference/basic_stream_socket/bind/overload2.html +/doc/asio/reference/basic_stream_socket/broadcast.html +/doc/asio/reference/basic_stream_socket/bytes_readable.html +/doc/asio/reference/basic_stream_socket/cancel/ +/doc/asio/reference/basic_stream_socket/cancel.html +/doc/asio/reference/basic_stream_socket/cancel/overload1.html +/doc/asio/reference/basic_stream_socket/cancel/overload2.html +/doc/asio/reference/basic_stream_socket/close/ +/doc/asio/reference/basic_stream_socket/close.html +/doc/asio/reference/basic_stream_socket/close/overload1.html +/doc/asio/reference/basic_stream_socket/close/overload2.html +/doc/asio/reference/basic_stream_socket/connect/ +/doc/asio/reference/basic_stream_socket/connect.html +/doc/asio/reference/basic_stream_socket/connect/overload1.html +/doc/asio/reference/basic_stream_socket/connect/overload2.html +/doc/asio/reference/basic_stream_socket/debug.html +/doc/asio/reference/basic_stream_socket/do_not_route.html +/doc/asio/reference/basic_stream_socket/enable_connection_aborted.html +/doc/asio/reference/basic_stream_socket/endpoint_type.html +/doc/asio/reference/basic_stream_socket/get_implementation/ +/doc/asio/reference/basic_stream_socket/get_implementation.html +/doc/asio/reference/basic_stream_socket/get_implementation/overload1.html +/doc/asio/reference/basic_stream_socket/get_implementation/overload2.html +/doc/asio/reference/basic_stream_socket/get_io_service.html +/doc/asio/reference/basic_stream_socket/get_option/ +/doc/asio/reference/basic_stream_socket/get_option.html +/doc/asio/reference/basic_stream_socket/get_option/overload1.html +/doc/asio/reference/basic_stream_socket/get_option/overload2.html +/doc/asio/reference/basic_stream_socket/get_service/ +/doc/asio/reference/basic_stream_socket/get_service.html +/doc/asio/reference/basic_stream_socket/get_service/overload1.html +/doc/asio/reference/basic_stream_socket/get_service/overload2.html +/doc/asio/reference/basic_stream_socket.html +/doc/asio/reference/basic_stream_socket/implementation.html +/doc/asio/reference/basic_stream_socket/implementation_type.html +/doc/asio/reference/basic_stream_socket/io_control/ +/doc/asio/reference/basic_stream_socket/io_control.html +/doc/asio/reference/basic_stream_socket/io_control/overload1.html +/doc/asio/reference/basic_stream_socket/io_control/overload2.html +/doc/asio/reference/basic_stream_socket/is_open.html +/doc/asio/reference/basic_stream_socket/keep_alive.html +/doc/asio/reference/basic_stream_socket/linger.html +/doc/asio/reference/basic_stream_socket/local_endpoint/ +/doc/asio/reference/basic_stream_socket/local_endpoint.html +/doc/asio/reference/basic_stream_socket/local_endpoint/overload1.html +/doc/asio/reference/basic_stream_socket/local_endpoint/overload2.html +/doc/asio/reference/basic_stream_socket/lowest_layer/ +/doc/asio/reference/basic_stream_socket/lowest_layer.html +/doc/asio/reference/basic_stream_socket/lowest_layer/overload1.html +/doc/asio/reference/basic_stream_socket/lowest_layer/overload2.html +/doc/asio/reference/basic_stream_socket/lowest_layer_type.html +/doc/asio/reference/basic_stream_socket/max_connections.html +/doc/asio/reference/basic_stream_socket/message_do_not_route.html +/doc/asio/reference/basic_stream_socket/message_end_of_record.html +/doc/asio/reference/basic_stream_socket/message_flags.html +/doc/asio/reference/basic_stream_socket/message_out_of_band.html +/doc/asio/reference/basic_stream_socket/message_peek.html +/doc/asio/reference/basic_stream_socket/native_handle.html +/doc/asio/reference/basic_stream_socket/native_handle_type.html +/doc/asio/reference/basic_stream_socket/native.html +/doc/asio/reference/basic_stream_socket/native_non_blocking/ +/doc/asio/reference/basic_stream_socket/native_non_blocking.html +/doc/asio/reference/basic_stream_socket/native_non_blocking/overload1.html +/doc/asio/reference/basic_stream_socket/native_non_blocking/overload2.html +/doc/asio/reference/basic_stream_socket/native_non_blocking/overload3.html +/doc/asio/reference/basic_stream_socket/native_type.html +/doc/asio/reference/basic_stream_socket/non_blocking/ +/doc/asio/reference/basic_stream_socket/non_blocking.html +/doc/asio/reference/basic_stream_socket/non_blocking_io.html +/doc/asio/reference/basic_stream_socket/non_blocking/overload1.html +/doc/asio/reference/basic_stream_socket/non_blocking/overload2.html +/doc/asio/reference/basic_stream_socket/non_blocking/overload3.html +/doc/asio/reference/basic_stream_socket/open/ +/doc/asio/reference/basic_stream_socket/open.html +/doc/asio/reference/basic_stream_socket/open/overload1.html +/doc/asio/reference/basic_stream_socket/open/overload2.html +/doc/asio/reference/basic_stream_socket/operator_eq_/ +/doc/asio/reference/basic_stream_socket/operator_eq_.html +/doc/asio/reference/basic_stream_socket/operator_eq_/overload1.html +/doc/asio/reference/basic_stream_socket/operator_eq_/overload2.html +/doc/asio/reference/basic_stream_socket/protocol_type.html +/doc/asio/reference/basic_stream_socket/read_some/ +/doc/asio/reference/basic_stream_socket/read_some.html +/doc/asio/reference/basic_stream_socket/read_some/overload1.html +/doc/asio/reference/basic_stream_socket/read_some/overload2.html +/doc/asio/reference/basic_stream_socket/receive/ +/doc/asio/reference/basic_stream_socket/receive_buffer_size.html +/doc/asio/reference/basic_stream_socket/receive.html +/doc/asio/reference/basic_stream_socket/receive_low_watermark.html +/doc/asio/reference/basic_stream_socket/receive/overload1.html +/doc/asio/reference/basic_stream_socket/receive/overload2.html +/doc/asio/reference/basic_stream_socket/receive/overload3.html +/doc/asio/reference/basic_stream_socket/remote_endpoint/ +/doc/asio/reference/basic_stream_socket/remote_endpoint.html +/doc/asio/reference/basic_stream_socket/remote_endpoint/overload1.html +/doc/asio/reference/basic_stream_socket/remote_endpoint/overload2.html +/doc/asio/reference/basic_stream_socket/reuse_address.html +/doc/asio/reference/basic_stream_socket/send/ +/doc/asio/reference/basic_stream_socket/send_buffer_size.html +/doc/asio/reference/basic_stream_socket/send.html +/doc/asio/reference/basic_stream_socket/send_low_watermark.html +/doc/asio/reference/basic_stream_socket/send/overload1.html +/doc/asio/reference/basic_stream_socket/send/overload2.html +/doc/asio/reference/basic_stream_socket/send/overload3.html +/doc/asio/reference/basic_stream_socket/service.html +/doc/asio/reference/basic_stream_socket/service_type.html +/doc/asio/reference/basic_stream_socket/set_option/ +/doc/asio/reference/basic_stream_socket/set_option.html +/doc/asio/reference/basic_stream_socket/set_option/overload1.html +/doc/asio/reference/basic_stream_socket/set_option/overload2.html +/doc/asio/reference/basic_stream_socket/shutdown/ +/doc/asio/reference/basic_stream_socket/shutdown.html +/doc/asio/reference/basic_stream_socket/shutdown/overload1.html +/doc/asio/reference/basic_stream_socket/shutdown/overload2.html +/doc/asio/reference/basic_stream_socket/shutdown_type.html +/doc/asio/reference/basic_stream_socket/write_some/ +/doc/asio/reference/basic_stream_socket/write_some.html +/doc/asio/reference/basic_stream_socket/write_some/overload1.html +/doc/asio/reference/basic_stream_socket/write_some/overload2.html +/doc/asio/reference/basic_waitable_timer/ +/doc/asio/reference/basic_waitable_timer/async_wait.html +/doc/asio/reference/basic_waitable_timer/basic_waitable_timer/ +/doc/asio/reference/basic_waitable_timer/basic_waitable_timer.html +/doc/asio/reference/basic_waitable_timer/basic_waitable_timer/overload1.html +/doc/asio/reference/basic_waitable_timer/basic_waitable_timer/overload2.html +/doc/asio/reference/basic_waitable_timer/basic_waitable_timer/overload3.html +/doc/asio/reference/basic_waitable_timer/cancel/ +/doc/asio/reference/basic_waitable_timer/cancel.html +/doc/asio/reference/basic_waitable_timer/cancel_one/ +/doc/asio/reference/basic_waitable_timer/cancel_one.html +/doc/asio/reference/basic_waitable_timer/cancel_one/overload1.html +/doc/asio/reference/basic_waitable_timer/cancel_one/overload2.html +/doc/asio/reference/basic_waitable_timer/cancel/overload1.html +/doc/asio/reference/basic_waitable_timer/cancel/overload2.html +/doc/asio/reference/basic_waitable_timer/clock_type.html +/doc/asio/reference/basic_waitable_timer/duration.html +/doc/asio/reference/basic_waitable_timer/expires_at/ +/doc/asio/reference/basic_waitable_timer/expires_at.html +/doc/asio/reference/basic_waitable_timer/expires_at/overload1.html +/doc/asio/reference/basic_waitable_timer/expires_at/overload2.html +/doc/asio/reference/basic_waitable_timer/expires_at/overload3.html +/doc/asio/reference/basic_waitable_timer/expires_from_now/ +/doc/asio/reference/basic_waitable_timer/expires_from_now.html +/doc/asio/reference/basic_waitable_timer/expires_from_now/overload1.html +/doc/asio/reference/basic_waitable_timer/expires_from_now/overload2.html +/doc/asio/reference/basic_waitable_timer/expires_from_now/overload3.html +/doc/asio/reference/basic_waitable_timer/get_implementation/ +/doc/asio/reference/basic_waitable_timer/get_implementation.html +/doc/asio/reference/basic_waitable_timer/get_implementation/overload1.html +/doc/asio/reference/basic_waitable_timer/get_implementation/overload2.html +/doc/asio/reference/basic_waitable_timer/get_io_service.html +/doc/asio/reference/basic_waitable_timer/get_service/ +/doc/asio/reference/basic_waitable_timer/get_service.html +/doc/asio/reference/basic_waitable_timer/get_service/overload1.html +/doc/asio/reference/basic_waitable_timer/get_service/overload2.html +/doc/asio/reference/basic_waitable_timer.html +/doc/asio/reference/basic_waitable_timer/implementation.html +/doc/asio/reference/basic_waitable_timer/implementation_type.html +/doc/asio/reference/basic_waitable_timer/service.html +/doc/asio/reference/basic_waitable_timer/service_type.html +/doc/asio/reference/basic_waitable_timer/time_point.html +/doc/asio/reference/basic_waitable_timer/traits_type.html +/doc/asio/reference/basic_waitable_timer/wait/ +/doc/asio/reference/basic_waitable_timer/wait.html +/doc/asio/reference/basic_waitable_timer/wait/overload1.html +/doc/asio/reference/basic_waitable_timer/wait/overload2.html +/doc/asio/reference/basic_yield_context/ +/doc/asio/reference/basic_yield_context/basic_yield_context.html +/doc/asio/reference/basic_yield_context/callee_type.html +/doc/asio/reference/basic_yield_context/caller_type.html +/doc/asio/reference/basic_yield_context.html +/doc/asio/reference/basic_yield_context/operator_lb__rb_.html +/doc/asio/reference/buffer/ +/doc/asio/reference/buffer_cast/ +/doc/asio/reference/buffer_cast.html +/doc/asio/reference/buffer_cast/overload1.html +/doc/asio/reference/buffer_cast/overload2.html +/doc/asio/reference/buffer_copy/ +/doc/asio/reference/buffer_copy.html +/doc/asio/reference/buffer_copy/overload10.html +/doc/asio/reference/buffer_copy/overload11.html +/doc/asio/reference/buffer_copy/overload12.html +/doc/asio/reference/buffer_copy/overload13.html +/doc/asio/reference/buffer_copy/overload14.html +/doc/asio/reference/buffer_copy/overload15.html +/doc/asio/reference/buffer_copy/overload16.html +/doc/asio/reference/buffer_copy/overload17.html +/doc/asio/reference/buffer_copy/overload18.html +/doc/asio/reference/buffer_copy/overload19.html +/doc/asio/reference/buffer_copy/overload1.html +/doc/asio/reference/buffer_copy/overload20.html +/doc/asio/reference/buffer_copy/overload21.html +/doc/asio/reference/buffer_copy/overload22.html +/doc/asio/reference/buffer_copy/overload23.html +/doc/asio/reference/buffer_copy/overload24.html +/doc/asio/reference/buffer_copy/overload25.html +/doc/asio/reference/buffer_copy/overload26.html +/doc/asio/reference/buffer_copy/overload27.html +/doc/asio/reference/buffer_copy/overload28.html +/doc/asio/reference/buffer_copy/overload29.html +/doc/asio/reference/buffer_copy/overload2.html +/doc/asio/reference/buffer_copy/overload30.html +/doc/asio/reference/buffer_copy/overload3.html +/doc/asio/reference/buffer_copy/overload4.html +/doc/asio/reference/buffer_copy/overload5.html +/doc/asio/reference/buffer_copy/overload6.html +/doc/asio/reference/buffer_copy/overload7.html +/doc/asio/reference/buffer_copy/overload8.html +/doc/asio/reference/buffer_copy/overload9.html +/doc/asio/reference/BufferedHandshakeHandler.html +/doc/asio/reference/buffered_read_stream/ +/doc/asio/reference/buffered_read_stream/async_fill.html +/doc/asio/reference/buffered_read_stream/async_read_some.html +/doc/asio/reference/buffered_read_stream/async_write_some.html +/doc/asio/reference/buffered_read_stream/buffered_read_stream/ +/doc/asio/reference/buffered_read_stream/buffered_read_stream.html +/doc/asio/reference/buffered_read_stream/buffered_read_stream/overload1.html +/doc/asio/reference/buffered_read_stream/buffered_read_stream/overload2.html +/doc/asio/reference/buffered_read_stream/close/ +/doc/asio/reference/buffered_read_stream/close.html +/doc/asio/reference/buffered_read_stream/close/overload1.html +/doc/asio/reference/buffered_read_stream/close/overload2.html +/doc/asio/reference/buffered_read_stream/default_buffer_size.html +/doc/asio/reference/buffered_read_stream/fill/ +/doc/asio/reference/buffered_read_stream/fill.html +/doc/asio/reference/buffered_read_stream/fill/overload1.html +/doc/asio/reference/buffered_read_stream/fill/overload2.html +/doc/asio/reference/buffered_read_stream/get_io_service.html +/doc/asio/reference/buffered_read_stream.html +/doc/asio/reference/buffered_read_stream/in_avail/ +/doc/asio/reference/buffered_read_stream/in_avail.html +/doc/asio/reference/buffered_read_stream/in_avail/overload1.html +/doc/asio/reference/buffered_read_stream/in_avail/overload2.html +/doc/asio/reference/buffered_read_stream/lowest_layer/ +/doc/asio/reference/buffered_read_stream/lowest_layer.html +/doc/asio/reference/buffered_read_stream/lowest_layer/overload1.html +/doc/asio/reference/buffered_read_stream/lowest_layer/overload2.html +/doc/asio/reference/buffered_read_stream/lowest_layer_type.html +/doc/asio/reference/buffered_read_stream/next_layer.html +/doc/asio/reference/buffered_read_stream/next_layer_type.html +/doc/asio/reference/buffered_read_stream/peek/ +/doc/asio/reference/buffered_read_stream/peek.html +/doc/asio/reference/buffered_read_stream/peek/overload1.html +/doc/asio/reference/buffered_read_stream/peek/overload2.html +/doc/asio/reference/buffered_read_stream/read_some/ +/doc/asio/reference/buffered_read_stream/read_some.html +/doc/asio/reference/buffered_read_stream/read_some/overload1.html +/doc/asio/reference/buffered_read_stream/read_some/overload2.html +/doc/asio/reference/buffered_read_stream/write_some/ +/doc/asio/reference/buffered_read_stream/write_some.html +/doc/asio/reference/buffered_read_stream/write_some/overload1.html +/doc/asio/reference/buffered_read_stream/write_some/overload2.html +/doc/asio/reference/buffered_stream/ +/doc/asio/reference/buffered_stream/async_fill.html +/doc/asio/reference/buffered_stream/async_flush.html +/doc/asio/reference/buffered_stream/async_read_some.html +/doc/asio/reference/buffered_stream/async_write_some.html +/doc/asio/reference/buffered_stream/buffered_stream/ +/doc/asio/reference/buffered_stream/buffered_stream.html +/doc/asio/reference/buffered_stream/buffered_stream/overload1.html +/doc/asio/reference/buffered_stream/buffered_stream/overload2.html +/doc/asio/reference/buffered_stream/close/ +/doc/asio/reference/buffered_stream/close.html +/doc/asio/reference/buffered_stream/close/overload1.html +/doc/asio/reference/buffered_stream/close/overload2.html +/doc/asio/reference/buffered_stream/fill/ +/doc/asio/reference/buffered_stream/fill.html +/doc/asio/reference/buffered_stream/fill/overload1.html +/doc/asio/reference/buffered_stream/fill/overload2.html +/doc/asio/reference/buffered_stream/flush/ +/doc/asio/reference/buffered_stream/flush.html +/doc/asio/reference/buffered_stream/flush/overload1.html +/doc/asio/reference/buffered_stream/flush/overload2.html +/doc/asio/reference/buffered_stream/get_io_service.html +/doc/asio/reference/buffered_stream.html +/doc/asio/reference/buffered_stream/in_avail/ +/doc/asio/reference/buffered_stream/in_avail.html +/doc/asio/reference/buffered_stream/in_avail/overload1.html +/doc/asio/reference/buffered_stream/in_avail/overload2.html +/doc/asio/reference/buffered_stream/lowest_layer/ +/doc/asio/reference/buffered_stream/lowest_layer.html +/doc/asio/reference/buffered_stream/lowest_layer/overload1.html +/doc/asio/reference/buffered_stream/lowest_layer/overload2.html +/doc/asio/reference/buffered_stream/lowest_layer_type.html +/doc/asio/reference/buffered_stream/next_layer.html +/doc/asio/reference/buffered_stream/next_layer_type.html +/doc/asio/reference/buffered_stream/peek/ +/doc/asio/reference/buffered_stream/peek.html +/doc/asio/reference/buffered_stream/peek/overload1.html +/doc/asio/reference/buffered_stream/peek/overload2.html +/doc/asio/reference/buffered_stream/read_some/ +/doc/asio/reference/buffered_stream/read_some.html +/doc/asio/reference/buffered_stream/read_some/overload1.html +/doc/asio/reference/buffered_stream/read_some/overload2.html +/doc/asio/reference/buffered_stream/write_some/ +/doc/asio/reference/buffered_stream/write_some.html +/doc/asio/reference/buffered_stream/write_some/overload1.html +/doc/asio/reference/buffered_stream/write_some/overload2.html +/doc/asio/reference/buffered_write_stream/ +/doc/asio/reference/buffered_write_stream/async_flush.html +/doc/asio/reference/buffered_write_stream/async_read_some.html +/doc/asio/reference/buffered_write_stream/async_write_some.html +/doc/asio/reference/buffered_write_stream/buffered_write_stream/ +/doc/asio/reference/buffered_write_stream/buffered_write_stream.html +/doc/asio/reference/buffered_write_stream/buffered_write_stream/overload1.html +/doc/asio/reference/buffered_write_stream/buffered_write_stream/overload2.html +/doc/asio/reference/buffered_write_stream/close/ +/doc/asio/reference/buffered_write_stream/close.html +/doc/asio/reference/buffered_write_stream/close/overload1.html +/doc/asio/reference/buffered_write_stream/close/overload2.html +/doc/asio/reference/buffered_write_stream/default_buffer_size.html +/doc/asio/reference/buffered_write_stream/flush/ +/doc/asio/reference/buffered_write_stream/flush.html +/doc/asio/reference/buffered_write_stream/flush/overload1.html +/doc/asio/reference/buffered_write_stream/flush/overload2.html +/doc/asio/reference/buffered_write_stream/get_io_service.html +/doc/asio/reference/buffered_write_stream.html +/doc/asio/reference/buffered_write_stream/in_avail/ +/doc/asio/reference/buffered_write_stream/in_avail.html +/doc/asio/reference/buffered_write_stream/in_avail/overload1.html +/doc/asio/reference/buffered_write_stream/in_avail/overload2.html +/doc/asio/reference/buffered_write_stream/lowest_layer/ +/doc/asio/reference/buffered_write_stream/lowest_layer.html +/doc/asio/reference/buffered_write_stream/lowest_layer/overload1.html +/doc/asio/reference/buffered_write_stream/lowest_layer/overload2.html +/doc/asio/reference/buffered_write_stream/lowest_layer_type.html +/doc/asio/reference/buffered_write_stream/next_layer.html +/doc/asio/reference/buffered_write_stream/next_layer_type.html +/doc/asio/reference/buffered_write_stream/peek/ +/doc/asio/reference/buffered_write_stream/peek.html +/doc/asio/reference/buffered_write_stream/peek/overload1.html +/doc/asio/reference/buffered_write_stream/peek/overload2.html +/doc/asio/reference/buffered_write_stream/read_some/ +/doc/asio/reference/buffered_write_stream/read_some.html +/doc/asio/reference/buffered_write_stream/read_some/overload1.html +/doc/asio/reference/buffered_write_stream/read_some/overload2.html +/doc/asio/reference/buffered_write_stream/write_some/ +/doc/asio/reference/buffered_write_stream/write_some.html +/doc/asio/reference/buffered_write_stream/write_some/overload1.html +/doc/asio/reference/buffered_write_stream/write_some/overload2.html +/doc/asio/reference/buffer.html +/doc/asio/reference/buffer/overload10.html +/doc/asio/reference/buffer/overload11.html +/doc/asio/reference/buffer/overload12.html +/doc/asio/reference/buffer/overload13.html +/doc/asio/reference/buffer/overload14.html +/doc/asio/reference/buffer/overload15.html +/doc/asio/reference/buffer/overload16.html +/doc/asio/reference/buffer/overload17.html +/doc/asio/reference/buffer/overload18.html +/doc/asio/reference/buffer/overload19.html +/doc/asio/reference/buffer/overload1.html +/doc/asio/reference/buffer/overload20.html +/doc/asio/reference/buffer/overload21.html +/doc/asio/reference/buffer/overload22.html +/doc/asio/reference/buffer/overload23.html +/doc/asio/reference/buffer/overload24.html +/doc/asio/reference/buffer/overload25.html +/doc/asio/reference/buffer/overload26.html +/doc/asio/reference/buffer/overload27.html +/doc/asio/reference/buffer/overload28.html +/doc/asio/reference/buffer/overload2.html +/doc/asio/reference/buffer/overload3.html +/doc/asio/reference/buffer/overload4.html +/doc/asio/reference/buffer/overload5.html +/doc/asio/reference/buffer/overload6.html +/doc/asio/reference/buffer/overload7.html +/doc/asio/reference/buffer/overload8.html +/doc/asio/reference/buffer/overload9.html +/doc/asio/reference/buffers_begin.html +/doc/asio/reference/buffers_end.html +/doc/asio/reference/buffers_iterator/ +/doc/asio/reference/buffers_iterator/begin.html +/doc/asio/reference/buffers_iterator/buffers_iterator.html +/doc/asio/reference/buffers_iterator/difference_type.html +/doc/asio/reference/buffers_iterator/end.html +/doc/asio/reference/buffers_iterator.html +/doc/asio/reference/buffers_iterator/iterator_category.html +/doc/asio/reference/buffers_iterator/operator_arrow_.html +/doc/asio/reference/buffers_iterator/operator_eq__eq_.html +/doc/asio/reference/buffers_iterator/operator_gt__eq_.html +/doc/asio/reference/buffers_iterator/operator_gt_.html +/doc/asio/reference/buffers_iterator/operator_lb__rb_.html +/doc/asio/reference/buffers_iterator/operator_lt__eq_.html +/doc/asio/reference/buffers_iterator/operator_lt_.html +/doc/asio/reference/buffers_iterator/operator_minus_/ +/doc/asio/reference/buffers_iterator/operator_minus__eq_.html +/doc/asio/reference/buffers_iterator/operator_minus_.html +/doc/asio/reference/buffers_iterator/operator_minus__minus_/ +/doc/asio/reference/buffers_iterator/operator_minus__minus_.html +/doc/asio/reference/buffers_iterator/operator_minus__minus_/overload1.html +/doc/asio/reference/buffers_iterator/operator_minus__minus_/overload2.html +/doc/asio/reference/buffers_iterator/operator_minus_/overload1.html +/doc/asio/reference/buffers_iterator/operator_minus_/overload2.html +/doc/asio/reference/buffers_iterator/operator_not__eq_.html +/doc/asio/reference/buffers_iterator/operator_plus_/ +/doc/asio/reference/buffers_iterator/operator_plus__eq_.html +/doc/asio/reference/buffers_iterator/operator_plus_.html +/doc/asio/reference/buffers_iterator/operator_plus_/overload1.html +/doc/asio/reference/buffers_iterator/operator_plus_/overload2.html +/doc/asio/reference/buffers_iterator/operator_plus__plus_/ +/doc/asio/reference/buffers_iterator/operator_plus__plus_.html +/doc/asio/reference/buffers_iterator/operator_plus__plus_/overload1.html +/doc/asio/reference/buffers_iterator/operator_plus__plus_/overload2.html +/doc/asio/reference/buffers_iterator/operator__star_.html +/doc/asio/reference/buffers_iterator/pointer.html +/doc/asio/reference/buffers_iterator/reference.html +/doc/asio/reference/buffers_iterator/value_type.html +/doc/asio/reference/buffer_size/ +/doc/asio/reference/buffer_size.html +/doc/asio/reference/buffer_size/overload1.html +/doc/asio/reference/buffer_size/overload2.html +/doc/asio/reference/buffer_size/overload3.html +/doc/asio/reference/buffer_size/overload4.html +/doc/asio/reference/buffer_size/overload5.html +/doc/asio/reference/CompletionHandler.html +/doc/asio/reference/ComposedConnectHandler.html +/doc/asio/reference/connect/ +/doc/asio/reference/ConnectHandler.html +/doc/asio/reference/connect.html +/doc/asio/reference/connect/overload1.html +/doc/asio/reference/connect/overload2.html +/doc/asio/reference/connect/overload3.html +/doc/asio/reference/connect/overload4.html +/doc/asio/reference/connect/overload5.html +/doc/asio/reference/connect/overload6.html +/doc/asio/reference/connect/overload7.html +/doc/asio/reference/connect/overload8.html +/doc/asio/reference/const_buffer/ +/doc/asio/reference/const_buffer/const_buffer/ +/doc/asio/reference/const_buffer/const_buffer.html +/doc/asio/reference/const_buffer/const_buffer/overload1.html +/doc/asio/reference/const_buffer/const_buffer/overload2.html +/doc/asio/reference/const_buffer/const_buffer/overload3.html +/doc/asio/reference/const_buffer.html +/doc/asio/reference/const_buffer/operator_plus_/ +/doc/asio/reference/const_buffer/operator_plus_.html +/doc/asio/reference/const_buffer/operator_plus_/overload1.html +/doc/asio/reference/const_buffer/operator_plus_/overload2.html +/doc/asio/reference/const_buffers_1/ +/doc/asio/reference/const_buffers_1/begin.html +/doc/asio/reference/const_buffers_1/const_buffers_1/ +/doc/asio/reference/const_buffers_1/const_buffers_1.html +/doc/asio/reference/const_buffers_1/const_buffers_1/overload1.html +/doc/asio/reference/const_buffers_1/const_buffers_1/overload2.html +/doc/asio/reference/const_buffers_1/const_iterator.html +/doc/asio/reference/const_buffers_1/end.html +/doc/asio/reference/const_buffers_1.html +/doc/asio/reference/const_buffers_1/operator_plus_/ +/doc/asio/reference/const_buffers_1/operator_plus_.html +/doc/asio/reference/const_buffers_1/operator_plus_/overload1.html +/doc/asio/reference/const_buffers_1/operator_plus_/overload2.html +/doc/asio/reference/const_buffers_1/value_type.html +/doc/asio/reference/ConstBufferSequence.html +/doc/asio/reference/ConvertibleToConstBuffer.html +/doc/asio/reference/ConvertibleToMutableBuffer.html +/doc/asio/reference/coroutine/ +/doc/asio/reference/coroutine/coroutine.html +/doc/asio/reference/coroutine.html +/doc/asio/reference/coroutine/is_child.html +/doc/asio/reference/coroutine/is_complete.html +/doc/asio/reference/coroutine/is_parent.html +/doc/asio/reference/datagram_socket_service/ +/doc/asio/reference/datagram_socket_service/assign.html +/doc/asio/reference/datagram_socket_service/async_connect.html +/doc/asio/reference/datagram_socket_service/async_receive_from.html +/doc/asio/reference/datagram_socket_service/async_receive.html +/doc/asio/reference/datagram_socket_service/async_send.html +/doc/asio/reference/datagram_socket_service/async_send_to.html +/doc/asio/reference/datagram_socket_service/at_mark.html +/doc/asio/reference/datagram_socket_service/available.html +/doc/asio/reference/datagram_socket_service/bind.html +/doc/asio/reference/datagram_socket_service/cancel.html +/doc/asio/reference/datagram_socket_service/close.html +/doc/asio/reference/datagram_socket_service/connect.html +/doc/asio/reference/datagram_socket_service/construct.html +/doc/asio/reference/datagram_socket_service/converting_move_construct.html +/doc/asio/reference/datagram_socket_service/datagram_socket_service.html +/doc/asio/reference/datagram_socket_service/destroy.html +/doc/asio/reference/datagram_socket_service/endpoint_type.html +/doc/asio/reference/datagram_socket_service/get_io_service.html +/doc/asio/reference/datagram_socket_service/get_option.html +/doc/asio/reference/datagram_socket_service.html +/doc/asio/reference/DatagramSocketService.html +/doc/asio/reference/datagram_socket_service/id.html +/doc/asio/reference/datagram_socket_service/implementation_type.html +/doc/asio/reference/datagram_socket_service/io_control.html +/doc/asio/reference/datagram_socket_service/is_open.html +/doc/asio/reference/datagram_socket_service/local_endpoint.html +/doc/asio/reference/datagram_socket_service/move_assign.html +/doc/asio/reference/datagram_socket_service/move_construct.html +/doc/asio/reference/datagram_socket_service/native_handle.html +/doc/asio/reference/datagram_socket_service/native_handle_type.html +/doc/asio/reference/datagram_socket_service/native.html +/doc/asio/reference/datagram_socket_service/native_non_blocking/ +/doc/asio/reference/datagram_socket_service/native_non_blocking.html +/doc/asio/reference/datagram_socket_service/native_non_blocking/overload1.html +/doc/asio/reference/datagram_socket_service/native_non_blocking/overload2.html +/doc/asio/reference/datagram_socket_service/native_type.html +/doc/asio/reference/datagram_socket_service/non_blocking/ +/doc/asio/reference/datagram_socket_service/non_blocking.html +/doc/asio/reference/datagram_socket_service/non_blocking/overload1.html +/doc/asio/reference/datagram_socket_service/non_blocking/overload2.html +/doc/asio/reference/datagram_socket_service/open.html +/doc/asio/reference/datagram_socket_service/protocol_type.html +/doc/asio/reference/datagram_socket_service/receive_from.html +/doc/asio/reference/datagram_socket_service/receive.html +/doc/asio/reference/datagram_socket_service/remote_endpoint.html +/doc/asio/reference/datagram_socket_service/send.html +/doc/asio/reference/datagram_socket_service/send_to.html +/doc/asio/reference/datagram_socket_service/set_option.html +/doc/asio/reference/datagram_socket_service/shutdown.html +/doc/asio/reference/deadline_timer.html +/doc/asio/reference/deadline_timer_service/ +/doc/asio/reference/deadline_timer_service/async_wait.html +/doc/asio/reference/deadline_timer_service/cancel.html +/doc/asio/reference/deadline_timer_service/cancel_one.html +/doc/asio/reference/deadline_timer_service/construct.html +/doc/asio/reference/deadline_timer_service/deadline_timer_service.html +/doc/asio/reference/deadline_timer_service/destroy.html +/doc/asio/reference/deadline_timer_service/duration_type.html +/doc/asio/reference/deadline_timer_service/expires_at/ +/doc/asio/reference/deadline_timer_service/expires_at.html +/doc/asio/reference/deadline_timer_service/expires_at/overload1.html +/doc/asio/reference/deadline_timer_service/expires_at/overload2.html +/doc/asio/reference/deadline_timer_service/expires_from_now/ +/doc/asio/reference/deadline_timer_service/expires_from_now.html +/doc/asio/reference/deadline_timer_service/expires_from_now/overload1.html +/doc/asio/reference/deadline_timer_service/expires_from_now/overload2.html +/doc/asio/reference/deadline_timer_service/get_io_service.html +/doc/asio/reference/deadline_timer_service.html +/doc/asio/reference/deadline_timer_service/id.html +/doc/asio/reference/deadline_timer_service/implementation_type.html +/doc/asio/reference/deadline_timer_service/time_type.html +/doc/asio/reference/deadline_timer_service/traits_type.html +/doc/asio/reference/deadline_timer_service/wait.html +/doc/asio/reference/DescriptorService.html +/doc/asio/reference/Endpoint.html +/doc/asio/reference/error__addrinfo_category.html +/doc/asio/reference/error__addrinfo_errors.html +/doc/asio/reference/error__basic_errors.html +/doc/asio/reference/error_category/ +/doc/asio/reference/error_category/_error_category.html +/doc/asio/reference/error_category.html +/doc/asio/reference/error_category/message.html +/doc/asio/reference/error_category/name.html +/doc/asio/reference/error_category/operator_eq__eq_.html +/doc/asio/reference/error_category/operator_not__eq_.html +/doc/asio/reference/error_code/ +/doc/asio/reference/error_code/category.html +/doc/asio/reference/error_code/error_code/ +/doc/asio/reference/error_code/error_code.html +/doc/asio/reference/error_code/error_code/overload1.html +/doc/asio/reference/error_code/error_code/overload2.html +/doc/asio/reference/error_code/error_code/overload3.html +/doc/asio/reference/error_code.html +/doc/asio/reference/error_code/message.html +/doc/asio/reference/error_code/operator_eq__eq_.html +/doc/asio/reference/error_code/operator_not__eq_.html +/doc/asio/reference/error_code/operator_not_.html +/doc/asio/reference/error_code/operator_unspecified_bool_type.html +/doc/asio/reference/error_code/unspecified_bool_true.html +/doc/asio/reference/error_code/unspecified_bool_type.html +/doc/asio/reference/error_code__unspecified_bool_type_t.html +/doc/asio/reference/error_code/value.html +/doc/asio/reference/error__get_addrinfo_category.html +/doc/asio/reference/error__get_misc_category.html +/doc/asio/reference/error__get_netdb_category.html +/doc/asio/reference/error__get_ssl_category.html +/doc/asio/reference/error__get_system_category.html +/doc/asio/reference/error__make_error_code/ +/doc/asio/reference/error__make_error_code.html +/doc/asio/reference/error__make_error_code/overload1.html +/doc/asio/reference/error__make_error_code/overload2.html +/doc/asio/reference/error__make_error_code/overload3.html +/doc/asio/reference/error__make_error_code/overload4.html +/doc/asio/reference/error__make_error_code/overload5.html +/doc/asio/reference/error__misc_category.html +/doc/asio/reference/error__misc_errors.html +/doc/asio/reference/error__netdb_category.html +/doc/asio/reference/error__netdb_errors.html +/doc/asio/reference/error__ssl_category.html +/doc/asio/reference/error__ssl_errors.html +/doc/asio/reference/error__system_category.html +/doc/asio/reference/generic__basic_endpoint/ +/doc/asio/reference/generic__basic_endpoint/basic_endpoint/ +/doc/asio/reference/generic__basic_endpoint/basic_endpoint.html +/doc/asio/reference/generic__basic_endpoint/basic_endpoint/overload1.html +/doc/asio/reference/generic__basic_endpoint/basic_endpoint/overload2.html +/doc/asio/reference/generic__basic_endpoint/basic_endpoint/overload3.html +/doc/asio/reference/generic__basic_endpoint/basic_endpoint/overload4.html +/doc/asio/reference/generic__basic_endpoint/capacity.html +/doc/asio/reference/generic__basic_endpoint/data/ +/doc/asio/reference/generic__basic_endpoint/data.html +/doc/asio/reference/generic__basic_endpoint/data/overload1.html +/doc/asio/reference/generic__basic_endpoint/data/overload2.html +/doc/asio/reference/generic__basic_endpoint/data_type.html +/doc/asio/reference/generic__basic_endpoint.html +/doc/asio/reference/generic__basic_endpoint/operator_eq__eq_.html +/doc/asio/reference/generic__basic_endpoint/operator_eq_.html +/doc/asio/reference/generic__basic_endpoint/operator_gt__eq_.html +/doc/asio/reference/generic__basic_endpoint/operator_gt_.html +/doc/asio/reference/generic__basic_endpoint/operator_lt__eq_.html +/doc/asio/reference/generic__basic_endpoint/operator_lt_.html +/doc/asio/reference/generic__basic_endpoint/operator_not__eq_.html +/doc/asio/reference/generic__basic_endpoint/protocol.html +/doc/asio/reference/generic__basic_endpoint/protocol_type.html +/doc/asio/reference/generic__basic_endpoint/resize.html +/doc/asio/reference/generic__basic_endpoint/size.html +/doc/asio/reference/generic__datagram_protocol/ +/doc/asio/reference/generic__datagram_protocol/datagram_protocol/ +/doc/asio/reference/generic__datagram_protocol/datagram_protocol.html +/doc/asio/reference/generic__datagram_protocol/datagram_protocol/overload1.html +/doc/asio/reference/generic__datagram_protocol/datagram_protocol/overload2.html +/doc/asio/reference/generic__datagram_protocol/endpoint.html +/doc/asio/reference/generic__datagram_protocol/family.html +/doc/asio/reference/generic__datagram_protocol.html +/doc/asio/reference/generic__datagram_protocol/operator_eq__eq_.html +/doc/asio/reference/generic__datagram_protocol/operator_not__eq_.html +/doc/asio/reference/generic__datagram_protocol/protocol.html +/doc/asio/reference/generic__datagram_protocol/socket.html +/doc/asio/reference/generic__datagram_protocol/type.html +/doc/asio/reference/generic__raw_protocol/ +/doc/asio/reference/generic__raw_protocol/endpoint.html +/doc/asio/reference/generic__raw_protocol/family.html +/doc/asio/reference/generic__raw_protocol.html +/doc/asio/reference/generic__raw_protocol/operator_eq__eq_.html +/doc/asio/reference/generic__raw_protocol/operator_not__eq_.html +/doc/asio/reference/generic__raw_protocol/protocol.html +/doc/asio/reference/generic__raw_protocol/raw_protocol/ +/doc/asio/reference/generic__raw_protocol/raw_protocol.html +/doc/asio/reference/generic__raw_protocol/raw_protocol/overload1.html +/doc/asio/reference/generic__raw_protocol/raw_protocol/overload2.html +/doc/asio/reference/generic__raw_protocol/socket.html +/doc/asio/reference/generic__raw_protocol/type.html +/doc/asio/reference/generic__seq_packet_protocol/ +/doc/asio/reference/generic__seq_packet_protocol/endpoint.html +/doc/asio/reference/generic__seq_packet_protocol/family.html +/doc/asio/reference/generic__seq_packet_protocol.html +/doc/asio/reference/generic__seq_packet_protocol/operator_eq__eq_.html +/doc/asio/reference/generic__seq_packet_protocol/operator_not__eq_.html +/doc/asio/reference/generic__seq_packet_protocol/protocol.html +/doc/asio/reference/generic__seq_packet_protocol/seq_packet_protocol/ +/doc/asio/reference/generic__seq_packet_protocol/seq_packet_protocol.html +/doc/asio/reference/generic__seq_packet_protocol/seq_packet_protocol/overload1.html +/doc/asio/reference/generic__seq_packet_protocol/seq_packet_protocol/overload2.html +/doc/asio/reference/generic__seq_packet_protocol/socket.html +/doc/asio/reference/generic__seq_packet_protocol/type.html +/doc/asio/reference/generic__stream_protocol/ +/doc/asio/reference/generic__stream_protocol/endpoint.html +/doc/asio/reference/generic__stream_protocol/family.html +/doc/asio/reference/generic__stream_protocol.html +/doc/asio/reference/generic__stream_protocol/iostream.html +/doc/asio/reference/generic__stream_protocol/operator_eq__eq_.html +/doc/asio/reference/generic__stream_protocol/operator_not__eq_.html +/doc/asio/reference/generic__stream_protocol/protocol.html +/doc/asio/reference/generic__stream_protocol/socket.html +/doc/asio/reference/generic__stream_protocol/stream_protocol/ +/doc/asio/reference/generic__stream_protocol/stream_protocol.html +/doc/asio/reference/generic__stream_protocol/stream_protocol/overload1.html +/doc/asio/reference/generic__stream_protocol/stream_protocol/overload2.html +/doc/asio/reference/generic__stream_protocol/type.html +/doc/asio/reference/GettableSerialPortOption.html +/doc/asio/reference/GettableSocketOption.html +/doc/asio/reference/Handler.html +/doc/asio/reference/handler_type/ +/doc/asio/reference/handler_type.html +/doc/asio/reference/handler_type/type.html +/doc/asio/reference/HandleService.html +/doc/asio/reference/HandshakeHandler.html +/doc/asio/reference/has_service.html +/doc/asio/reference/high_resolution_timer.html +/doc/asio/reference.html +/doc/asio/reference/InternetProtocol.html +/doc/asio/reference/invalid_service_owner/ +/doc/asio/reference/invalid_service_owner.html +/doc/asio/reference/invalid_service_owner/invalid_service_owner.html +/doc/asio/reference/IoControlCommand.html +/doc/asio/reference/IoObjectService.html +/doc/asio/reference/io_service/ +/doc/asio/reference/io_service/add_service.html +/doc/asio/reference/io_service/dispatch.html +/doc/asio/reference/io_service/fork_event.html +/doc/asio/reference/io_service/has_service.html +/doc/asio/reference/io_service.html +/doc/asio/reference/io_service__id/ +/doc/asio/reference/io_service__id.html +/doc/asio/reference/io_service__id/id.html +/doc/asio/reference/io_service/io_service/ +/doc/asio/reference/io_service/_io_service.html +/doc/asio/reference/io_service/io_service.html +/doc/asio/reference/io_service/io_service/overload1.html +/doc/asio/reference/io_service/io_service/overload2.html +/doc/asio/reference/io_service/notify_fork.html +/doc/asio/reference/io_service/poll/ +/doc/asio/reference/io_service/poll.html +/doc/asio/reference/io_service/poll_one/ +/doc/asio/reference/io_service/poll_one.html +/doc/asio/reference/io_service/poll_one/overload1.html +/doc/asio/reference/io_service/poll_one/overload2.html +/doc/asio/reference/io_service/poll/overload1.html +/doc/asio/reference/io_service/poll/overload2.html +/doc/asio/reference/io_service/post.html +/doc/asio/reference/io_service/reset.html +/doc/asio/reference/io_service/run/ +/doc/asio/reference/io_service/run.html +/doc/asio/reference/io_service/run_one/ +/doc/asio/reference/io_service/run_one.html +/doc/asio/reference/io_service/run_one/overload1.html +/doc/asio/reference/io_service/run_one/overload2.html +/doc/asio/reference/io_service/run/overload1.html +/doc/asio/reference/io_service/run/overload2.html +/doc/asio/reference/io_service__service/ +/doc/asio/reference/io_service__service/fork_service.html +/doc/asio/reference/io_service__service/get_io_service.html +/doc/asio/reference/io_service__service.html +/doc/asio/reference/io_service__service/_service.html +/doc/asio/reference/io_service__service/service.html +/doc/asio/reference/io_service__service/shutdown_service.html +/doc/asio/reference/io_service/stop.html +/doc/asio/reference/io_service/stopped.html +/doc/asio/reference/io_service__strand/ +/doc/asio/reference/io_service__strand/dispatch.html +/doc/asio/reference/io_service__strand/get_io_service.html +/doc/asio/reference/io_service__strand.html +/doc/asio/reference/io_service__strand/post.html +/doc/asio/reference/io_service__strand/running_in_this_thread.html +/doc/asio/reference/io_service__strand/_strand.html +/doc/asio/reference/io_service__strand/strand.html +/doc/asio/reference/io_service__strand/wrap.html +/doc/asio/reference/io_service/use_service.html +/doc/asio/reference/io_service__work/ +/doc/asio/reference/io_service__work/get_io_service.html +/doc/asio/reference/io_service__work.html +/doc/asio/reference/io_service__work/work/ +/doc/asio/reference/io_service__work/_work.html +/doc/asio/reference/io_service__work/work.html +/doc/asio/reference/io_service__work/work/overload1.html +/doc/asio/reference/io_service__work/work/overload2.html +/doc/asio/reference/io_service/wrap.html +/doc/asio/reference/ip__address/ +/doc/asio/reference/ip__address/address/ +/doc/asio/reference/ip__address/address.html +/doc/asio/reference/ip__address/address/overload1.html +/doc/asio/reference/ip__address/address/overload2.html +/doc/asio/reference/ip__address/address/overload3.html +/doc/asio/reference/ip__address/address/overload4.html +/doc/asio/reference/ip__address/from_string/ +/doc/asio/reference/ip__address/from_string.html +/doc/asio/reference/ip__address/from_string/overload1.html +/doc/asio/reference/ip__address/from_string/overload2.html +/doc/asio/reference/ip__address/from_string/overload3.html +/doc/asio/reference/ip__address/from_string/overload4.html +/doc/asio/reference/ip__address.html +/doc/asio/reference/ip__address/is_loopback.html +/doc/asio/reference/ip__address/is_multicast.html +/doc/asio/reference/ip__address/is_unspecified.html +/doc/asio/reference/ip__address/is_v4.html +/doc/asio/reference/ip__address/is_v6.html +/doc/asio/reference/ip__address/operator_eq_/ +/doc/asio/reference/ip__address/operator_eq__eq_.html +/doc/asio/reference/ip__address/operator_eq_.html +/doc/asio/reference/ip__address/operator_eq_/overload1.html +/doc/asio/reference/ip__address/operator_eq_/overload2.html +/doc/asio/reference/ip__address/operator_eq_/overload3.html +/doc/asio/reference/ip__address/operator_gt__eq_.html +/doc/asio/reference/ip__address/operator_gt_.html +/doc/asio/reference/ip__address/operator_lt__eq_.html +/doc/asio/reference/ip__address/operator_lt_.html +/doc/asio/reference/ip__address/operator_lt__lt_.html +/doc/asio/reference/ip__address/operator_not__eq_.html +/doc/asio/reference/ip__address/to_string/ +/doc/asio/reference/ip__address/to_string.html +/doc/asio/reference/ip__address/to_string/overload1.html +/doc/asio/reference/ip__address/to_string/overload2.html +/doc/asio/reference/ip__address/to_v4.html +/doc/asio/reference/ip__address/to_v6.html +/doc/asio/reference/ip__address_v4/ +/doc/asio/reference/ip__address_v4/address_v4/ +/doc/asio/reference/ip__address_v4/address_v4.html +/doc/asio/reference/ip__address_v4/address_v4/overload1.html +/doc/asio/reference/ip__address_v4/address_v4/overload2.html +/doc/asio/reference/ip__address_v4/address_v4/overload3.html +/doc/asio/reference/ip__address_v4/address_v4/overload4.html +/doc/asio/reference/ip__address_v4/any.html +/doc/asio/reference/ip__address_v4/broadcast/ +/doc/asio/reference/ip__address_v4/broadcast.html +/doc/asio/reference/ip__address_v4/broadcast/overload1.html +/doc/asio/reference/ip__address_v4/broadcast/overload2.html +/doc/asio/reference/ip__address_v4/bytes_type.html +/doc/asio/reference/ip__address_v4/from_string/ +/doc/asio/reference/ip__address_v4/from_string.html +/doc/asio/reference/ip__address_v4/from_string/overload1.html +/doc/asio/reference/ip__address_v4/from_string/overload2.html +/doc/asio/reference/ip__address_v4/from_string/overload3.html +/doc/asio/reference/ip__address_v4/from_string/overload4.html +/doc/asio/reference/ip__address_v4.html +/doc/asio/reference/ip__address_v4/is_class_a.html +/doc/asio/reference/ip__address_v4/is_class_b.html +/doc/asio/reference/ip__address_v4/is_class_c.html +/doc/asio/reference/ip__address_v4/is_loopback.html +/doc/asio/reference/ip__address_v4/is_multicast.html +/doc/asio/reference/ip__address_v4/is_unspecified.html +/doc/asio/reference/ip__address_v4/loopback.html +/doc/asio/reference/ip__address_v4/netmask.html +/doc/asio/reference/ip__address_v4/operator_eq__eq_.html +/doc/asio/reference/ip__address_v4/operator_eq_.html +/doc/asio/reference/ip__address_v4/operator_gt__eq_.html +/doc/asio/reference/ip__address_v4/operator_gt_.html +/doc/asio/reference/ip__address_v4/operator_lt__eq_.html +/doc/asio/reference/ip__address_v4/operator_lt_.html +/doc/asio/reference/ip__address_v4/operator_lt__lt_.html +/doc/asio/reference/ip__address_v4/operator_not__eq_.html +/doc/asio/reference/ip__address_v4/to_bytes.html +/doc/asio/reference/ip__address_v4/to_string/ +/doc/asio/reference/ip__address_v4/to_string.html +/doc/asio/reference/ip__address_v4/to_string/overload1.html +/doc/asio/reference/ip__address_v4/to_string/overload2.html +/doc/asio/reference/ip__address_v4/to_ulong.html +/doc/asio/reference/ip__address_v6/ +/doc/asio/reference/ip__address_v6/address_v6/ +/doc/asio/reference/ip__address_v6/address_v6.html +/doc/asio/reference/ip__address_v6/address_v6/overload1.html +/doc/asio/reference/ip__address_v6/address_v6/overload2.html +/doc/asio/reference/ip__address_v6/address_v6/overload3.html +/doc/asio/reference/ip__address_v6/any.html +/doc/asio/reference/ip__address_v6/bytes_type.html +/doc/asio/reference/ip__address_v6/from_string/ +/doc/asio/reference/ip__address_v6/from_string.html +/doc/asio/reference/ip__address_v6/from_string/overload1.html +/doc/asio/reference/ip__address_v6/from_string/overload2.html +/doc/asio/reference/ip__address_v6/from_string/overload3.html +/doc/asio/reference/ip__address_v6/from_string/overload4.html +/doc/asio/reference/ip__address_v6.html +/doc/asio/reference/ip__address_v6/is_link_local.html +/doc/asio/reference/ip__address_v6/is_loopback.html +/doc/asio/reference/ip__address_v6/is_multicast_global.html +/doc/asio/reference/ip__address_v6/is_multicast.html +/doc/asio/reference/ip__address_v6/is_multicast_link_local.html +/doc/asio/reference/ip__address_v6/is_multicast_node_local.html +/doc/asio/reference/ip__address_v6/is_multicast_org_local.html +/doc/asio/reference/ip__address_v6/is_multicast_site_local.html +/doc/asio/reference/ip__address_v6/is_site_local.html +/doc/asio/reference/ip__address_v6/is_unspecified.html +/doc/asio/reference/ip__address_v6/is_v4_compatible.html +/doc/asio/reference/ip__address_v6/is_v4_mapped.html +/doc/asio/reference/ip__address_v6/loopback.html +/doc/asio/reference/ip__address_v6/operator_eq__eq_.html +/doc/asio/reference/ip__address_v6/operator_eq_.html +/doc/asio/reference/ip__address_v6/operator_gt__eq_.html +/doc/asio/reference/ip__address_v6/operator_gt_.html +/doc/asio/reference/ip__address_v6/operator_lt__eq_.html +/doc/asio/reference/ip__address_v6/operator_lt_.html +/doc/asio/reference/ip__address_v6/operator_lt__lt_.html +/doc/asio/reference/ip__address_v6/operator_not__eq_.html +/doc/asio/reference/ip__address_v6/scope_id/ +/doc/asio/reference/ip__address_v6/scope_id.html +/doc/asio/reference/ip__address_v6/scope_id/overload1.html +/doc/asio/reference/ip__address_v6/scope_id/overload2.html +/doc/asio/reference/ip__address_v6/to_bytes.html +/doc/asio/reference/ip__address_v6/to_string/ +/doc/asio/reference/ip__address_v6/to_string.html +/doc/asio/reference/ip__address_v6/to_string/overload1.html +/doc/asio/reference/ip__address_v6/to_string/overload2.html +/doc/asio/reference/ip__address_v6/to_v4.html +/doc/asio/reference/ip__address_v6/v4_compatible.html +/doc/asio/reference/ip__address_v6/v4_mapped.html +/doc/asio/reference/ip__basic_endpoint/ +/doc/asio/reference/ip__basic_endpoint/address/ +/doc/asio/reference/ip__basic_endpoint/address.html +/doc/asio/reference/ip__basic_endpoint/address/overload1.html +/doc/asio/reference/ip__basic_endpoint/address/overload2.html +/doc/asio/reference/ip__basic_endpoint/basic_endpoint/ +/doc/asio/reference/ip__basic_endpoint/basic_endpoint.html +/doc/asio/reference/ip__basic_endpoint/basic_endpoint/overload1.html +/doc/asio/reference/ip__basic_endpoint/basic_endpoint/overload2.html +/doc/asio/reference/ip__basic_endpoint/basic_endpoint/overload3.html +/doc/asio/reference/ip__basic_endpoint/basic_endpoint/overload4.html +/doc/asio/reference/ip__basic_endpoint/capacity.html +/doc/asio/reference/ip__basic_endpoint/data/ +/doc/asio/reference/ip__basic_endpoint/data.html +/doc/asio/reference/ip__basic_endpoint/data/overload1.html +/doc/asio/reference/ip__basic_endpoint/data/overload2.html +/doc/asio/reference/ip__basic_endpoint/data_type.html +/doc/asio/reference/ip__basic_endpoint.html +/doc/asio/reference/ip__basic_endpoint/operator_eq__eq_.html +/doc/asio/reference/ip__basic_endpoint/operator_eq_.html +/doc/asio/reference/ip__basic_endpoint/operator_gt__eq_.html +/doc/asio/reference/ip__basic_endpoint/operator_gt_.html +/doc/asio/reference/ip__basic_endpoint/operator_lt__eq_.html +/doc/asio/reference/ip__basic_endpoint/operator_lt_.html +/doc/asio/reference/ip__basic_endpoint/operator_lt__lt_.html +/doc/asio/reference/ip__basic_endpoint/operator_not__eq_.html +/doc/asio/reference/ip__basic_endpoint/port/ +/doc/asio/reference/ip__basic_endpoint/port.html +/doc/asio/reference/ip__basic_endpoint/port/overload1.html +/doc/asio/reference/ip__basic_endpoint/port/overload2.html +/doc/asio/reference/ip__basic_endpoint/protocol.html +/doc/asio/reference/ip__basic_endpoint/protocol_type.html +/doc/asio/reference/ip__basic_endpoint/resize.html +/doc/asio/reference/ip__basic_endpoint/size.html +/doc/asio/reference/ip__basic_resolver/ +/doc/asio/reference/ip__basic_resolver/async_resolve/ +/doc/asio/reference/ip__basic_resolver/async_resolve.html +/doc/asio/reference/ip__basic_resolver/async_resolve/overload1.html +/doc/asio/reference/ip__basic_resolver/async_resolve/overload2.html +/doc/asio/reference/ip__basic_resolver/basic_resolver.html +/doc/asio/reference/ip__basic_resolver/cancel.html +/doc/asio/reference/ip__basic_resolver/endpoint_type.html +/doc/asio/reference/ip__basic_resolver_entry/ +/doc/asio/reference/ip__basic_resolver_entry/basic_resolver_entry/ +/doc/asio/reference/ip__basic_resolver_entry/basic_resolver_entry.html +/doc/asio/reference/ip__basic_resolver_entry/basic_resolver_entry/overload1.html +/doc/asio/reference/ip__basic_resolver_entry/basic_resolver_entry/overload2.html +/doc/asio/reference/ip__basic_resolver_entry/endpoint.html +/doc/asio/reference/ip__basic_resolver_entry/endpoint_type.html +/doc/asio/reference/ip__basic_resolver_entry/host_name.html +/doc/asio/reference/ip__basic_resolver_entry.html +/doc/asio/reference/ip__basic_resolver_entry/operator_endpoint_type.html +/doc/asio/reference/ip__basic_resolver_entry/protocol_type.html +/doc/asio/reference/ip__basic_resolver_entry/service_name.html +/doc/asio/reference/ip__basic_resolver/get_implementation/ +/doc/asio/reference/ip__basic_resolver/get_implementation.html +/doc/asio/reference/ip__basic_resolver/get_implementation/overload1.html +/doc/asio/reference/ip__basic_resolver/get_implementation/overload2.html +/doc/asio/reference/ip__basic_resolver/get_io_service.html +/doc/asio/reference/ip__basic_resolver/get_service/ +/doc/asio/reference/ip__basic_resolver/get_service.html +/doc/asio/reference/ip__basic_resolver/get_service/overload1.html +/doc/asio/reference/ip__basic_resolver/get_service/overload2.html +/doc/asio/reference/ip__basic_resolver.html +/doc/asio/reference/ip__basic_resolver/implementation.html +/doc/asio/reference/ip__basic_resolver/implementation_type.html +/doc/asio/reference/ip__basic_resolver_iterator/ +/doc/asio/reference/ip__basic_resolver_iterator/basic_resolver_iterator.html +/doc/asio/reference/ip__basic_resolver_iterator/create/ +/doc/asio/reference/ip__basic_resolver_iterator/create.html +/doc/asio/reference/ip__basic_resolver_iterator/create/overload1.html +/doc/asio/reference/ip__basic_resolver_iterator/create/overload2.html +/doc/asio/reference/ip__basic_resolver_iterator/create/overload3.html +/doc/asio/reference/ip__basic_resolver_iterator/difference_type.html +/doc/asio/reference/ip__basic_resolver_iterator.html +/doc/asio/reference/ip__basic_resolver/iterator.html +/doc/asio/reference/ip__basic_resolver_iterator/iterator_category.html +/doc/asio/reference/ip__basic_resolver_iterator/operator_arrow_.html +/doc/asio/reference/ip__basic_resolver_iterator/operator_eq__eq_.html +/doc/asio/reference/ip__basic_resolver_iterator/operator_not__eq_.html +/doc/asio/reference/ip__basic_resolver_iterator/operator_plus__plus_/ +/doc/asio/reference/ip__basic_resolver_iterator/operator_plus__plus_.html +/doc/asio/reference/ip__basic_resolver_iterator/operator_plus__plus_/overload1.html +/doc/asio/reference/ip__basic_resolver_iterator/operator_plus__plus_/overload2.html +/doc/asio/reference/ip__basic_resolver_iterator/operator__star_.html +/doc/asio/reference/ip__basic_resolver_iterator/pointer.html +/doc/asio/reference/ip__basic_resolver_iterator/reference.html +/doc/asio/reference/ip__basic_resolver_iterator/value_type.html +/doc/asio/reference/ip__basic_resolver/protocol_type.html +/doc/asio/reference/ip__basic_resolver_query/ +/doc/asio/reference/ip__basic_resolver_query/address_configured.html +/doc/asio/reference/ip__basic_resolver_query/all_matching.html +/doc/asio/reference/ip__basic_resolver_query/basic_resolver_query/ +/doc/asio/reference/ip__basic_resolver_query/basic_resolver_query.html +/doc/asio/reference/ip__basic_resolver_query/basic_resolver_query/overload1.html +/doc/asio/reference/ip__basic_resolver_query/basic_resolver_query/overload2.html +/doc/asio/reference/ip__basic_resolver_query/basic_resolver_query/overload3.html +/doc/asio/reference/ip__basic_resolver_query/basic_resolver_query/overload4.html +/doc/asio/reference/ip__basic_resolver_query/canonical_name.html +/doc/asio/reference/ip__basic_resolver_query/flags.html +/doc/asio/reference/ip__basic_resolver_query/hints.html +/doc/asio/reference/ip__basic_resolver_query/host_name.html +/doc/asio/reference/ip__basic_resolver_query.html +/doc/asio/reference/ip__basic_resolver/query.html +/doc/asio/reference/ip__basic_resolver_query/numeric_host.html +/doc/asio/reference/ip__basic_resolver_query/numeric_service.html +/doc/asio/reference/ip__basic_resolver_query/passive.html +/doc/asio/reference/ip__basic_resolver_query/protocol_type.html +/doc/asio/reference/ip__basic_resolver_query/service_name.html +/doc/asio/reference/ip__basic_resolver_query/v4_mapped.html +/doc/asio/reference/ip__basic_resolver/resolve/ +/doc/asio/reference/ip__basic_resolver/resolve.html +/doc/asio/reference/ip__basic_resolver/resolve/overload1.html +/doc/asio/reference/ip__basic_resolver/resolve/overload2.html +/doc/asio/reference/ip__basic_resolver/resolve/overload3.html +/doc/asio/reference/ip__basic_resolver/resolve/overload4.html +/doc/asio/reference/ip__basic_resolver/service.html +/doc/asio/reference/ip__basic_resolver/service_type.html +/doc/asio/reference/ip__host_name/ +/doc/asio/reference/ip__host_name.html +/doc/asio/reference/ip__host_name/overload1.html +/doc/asio/reference/ip__host_name/overload2.html +/doc/asio/reference/ip__icmp/ +/doc/asio/reference/ip__icmp/endpoint.html +/doc/asio/reference/ip__icmp/family.html +/doc/asio/reference/ip__icmp.html +/doc/asio/reference/ip__icmp/operator_eq__eq_.html +/doc/asio/reference/ip__icmp/operator_not__eq_.html +/doc/asio/reference/ip__icmp/protocol.html +/doc/asio/reference/ip__icmp/resolver.html +/doc/asio/reference/ip__icmp/socket.html +/doc/asio/reference/ip__icmp/type.html +/doc/asio/reference/ip__icmp/v4.html +/doc/asio/reference/ip__icmp/v6.html +/doc/asio/reference/ip__multicast__enable_loopback.html +/doc/asio/reference/ip__multicast__hops.html +/doc/asio/reference/ip__multicast__join_group.html +/doc/asio/reference/ip__multicast__leave_group.html +/doc/asio/reference/ip__multicast__outbound_interface.html +/doc/asio/reference/ip__resolver_query_base/ +/doc/asio/reference/ip__resolver_query_base/address_configured.html +/doc/asio/reference/ip__resolver_query_base/all_matching.html +/doc/asio/reference/ip__resolver_query_base/canonical_name.html +/doc/asio/reference/ip__resolver_query_base/flags.html +/doc/asio/reference/ip__resolver_query_base.html +/doc/asio/reference/ip__resolver_query_base/numeric_host.html +/doc/asio/reference/ip__resolver_query_base/numeric_service.html +/doc/asio/reference/ip__resolver_query_base/passive.html +/doc/asio/reference/ip__resolver_query_base/_resolver_query_base.html +/doc/asio/reference/ip__resolver_query_base/v4_mapped.html +/doc/asio/reference/ip__resolver_service/ +/doc/asio/reference/ip__resolver_service/async_resolve/ +/doc/asio/reference/ip__resolver_service/async_resolve.html +/doc/asio/reference/ip__resolver_service/async_resolve/overload1.html +/doc/asio/reference/ip__resolver_service/async_resolve/overload2.html +/doc/asio/reference/ip__resolver_service/cancel.html +/doc/asio/reference/ip__resolver_service/construct.html +/doc/asio/reference/ip__resolver_service/destroy.html +/doc/asio/reference/ip__resolver_service/endpoint_type.html +/doc/asio/reference/ip__resolver_service/get_io_service.html +/doc/asio/reference/ip__resolver_service.html +/doc/asio/reference/ip__resolver_service/id.html +/doc/asio/reference/ip__resolver_service/implementation_type.html +/doc/asio/reference/ip__resolver_service/iterator_type.html +/doc/asio/reference/ip__resolver_service/protocol_type.html +/doc/asio/reference/ip__resolver_service/query_type.html +/doc/asio/reference/ip__resolver_service/resolve/ +/doc/asio/reference/ip__resolver_service/resolve.html +/doc/asio/reference/ip__resolver_service/resolve/overload1.html +/doc/asio/reference/ip__resolver_service/resolve/overload2.html +/doc/asio/reference/ip__resolver_service/resolver_service.html +/doc/asio/reference/ip__tcp/ +/doc/asio/reference/ip__tcp/acceptor.html +/doc/asio/reference/ip__tcp/endpoint.html +/doc/asio/reference/ip__tcp/family.html +/doc/asio/reference/ip__tcp.html +/doc/asio/reference/ip__tcp/iostream.html +/doc/asio/reference/ip__tcp/no_delay.html +/doc/asio/reference/ip__tcp/operator_eq__eq_.html +/doc/asio/reference/ip__tcp/operator_not__eq_.html +/doc/asio/reference/ip__tcp/protocol.html +/doc/asio/reference/ip__tcp/resolver.html +/doc/asio/reference/ip__tcp/socket.html +/doc/asio/reference/ip__tcp/type.html +/doc/asio/reference/ip__tcp/v4.html +/doc/asio/reference/ip__tcp/v6.html +/doc/asio/reference/ip__udp/ +/doc/asio/reference/ip__udp/endpoint.html +/doc/asio/reference/ip__udp/family.html +/doc/asio/reference/ip__udp.html +/doc/asio/reference/ip__udp/operator_eq__eq_.html +/doc/asio/reference/ip__udp/operator_not__eq_.html +/doc/asio/reference/ip__udp/protocol.html +/doc/asio/reference/ip__udp/resolver.html +/doc/asio/reference/ip__udp/socket.html +/doc/asio/reference/ip__udp/type.html +/doc/asio/reference/ip__udp/v4.html +/doc/asio/reference/ip__udp/v6.html +/doc/asio/reference/ip__unicast__hops.html +/doc/asio/reference/ip__v6_only.html +/doc/asio/reference/is_match_condition/ +/doc/asio/reference/is_match_condition.html +/doc/asio/reference/is_match_condition/value.html +/doc/asio/reference/is_read_buffered/ +/doc/asio/reference/is_read_buffered.html +/doc/asio/reference/is_read_buffered/value.html +/doc/asio/reference/is_write_buffered/ +/doc/asio/reference/is_write_buffered.html +/doc/asio/reference/is_write_buffered/value.html +/doc/asio/reference/local__basic_endpoint/ +/doc/asio/reference/local__basic_endpoint/basic_endpoint/ +/doc/asio/reference/local__basic_endpoint/basic_endpoint.html +/doc/asio/reference/local__basic_endpoint/basic_endpoint/overload1.html +/doc/asio/reference/local__basic_endpoint/basic_endpoint/overload2.html +/doc/asio/reference/local__basic_endpoint/basic_endpoint/overload3.html +/doc/asio/reference/local__basic_endpoint/basic_endpoint/overload4.html +/doc/asio/reference/local__basic_endpoint/capacity.html +/doc/asio/reference/local__basic_endpoint/data/ +/doc/asio/reference/local__basic_endpoint/data.html +/doc/asio/reference/local__basic_endpoint/data/overload1.html +/doc/asio/reference/local__basic_endpoint/data/overload2.html +/doc/asio/reference/local__basic_endpoint/data_type.html +/doc/asio/reference/local__basic_endpoint.html +/doc/asio/reference/local__basic_endpoint/operator_eq__eq_.html +/doc/asio/reference/local__basic_endpoint/operator_eq_.html +/doc/asio/reference/local__basic_endpoint/operator_gt__eq_.html +/doc/asio/reference/local__basic_endpoint/operator_gt_.html +/doc/asio/reference/local__basic_endpoint/operator_lt__eq_.html +/doc/asio/reference/local__basic_endpoint/operator_lt_.html +/doc/asio/reference/local__basic_endpoint/operator_lt__lt_.html +/doc/asio/reference/local__basic_endpoint/operator_not__eq_.html +/doc/asio/reference/local__basic_endpoint/path/ +/doc/asio/reference/local__basic_endpoint/path.html +/doc/asio/reference/local__basic_endpoint/path/overload1.html +/doc/asio/reference/local__basic_endpoint/path/overload2.html +/doc/asio/reference/local__basic_endpoint/path/overload3.html +/doc/asio/reference/local__basic_endpoint/protocol.html +/doc/asio/reference/local__basic_endpoint/protocol_type.html +/doc/asio/reference/local__basic_endpoint/resize.html +/doc/asio/reference/local__basic_endpoint/size.html +/doc/asio/reference/local__connect_pair/ +/doc/asio/reference/local__connect_pair.html +/doc/asio/reference/local__connect_pair/overload1.html +/doc/asio/reference/local__connect_pair/overload2.html +/doc/asio/reference/local__datagram_protocol/ +/doc/asio/reference/local__datagram_protocol/endpoint.html +/doc/asio/reference/local__datagram_protocol/family.html +/doc/asio/reference/local__datagram_protocol.html +/doc/asio/reference/local__datagram_protocol/protocol.html +/doc/asio/reference/local__datagram_protocol/socket.html +/doc/asio/reference/local__datagram_protocol/type.html +/doc/asio/reference/local__stream_protocol/ +/doc/asio/reference/local__stream_protocol/acceptor.html +/doc/asio/reference/local__stream_protocol/endpoint.html +/doc/asio/reference/local__stream_protocol/family.html +/doc/asio/reference/local__stream_protocol.html +/doc/asio/reference/local__stream_protocol/iostream.html +/doc/asio/reference/local__stream_protocol/protocol.html +/doc/asio/reference/local__stream_protocol/socket.html +/doc/asio/reference/local__stream_protocol/type.html +/doc/asio/reference/mutable_buffer/ +/doc/asio/reference/mutable_buffer.html +/doc/asio/reference/mutable_buffer/mutable_buffer/ +/doc/asio/reference/mutable_buffer/mutable_buffer.html +/doc/asio/reference/mutable_buffer/mutable_buffer/overload1.html +/doc/asio/reference/mutable_buffer/mutable_buffer/overload2.html +/doc/asio/reference/mutable_buffer/operator_plus_/ +/doc/asio/reference/mutable_buffer/operator_plus_.html +/doc/asio/reference/mutable_buffer/operator_plus_/overload1.html +/doc/asio/reference/mutable_buffer/operator_plus_/overload2.html +/doc/asio/reference/mutable_buffers_1/ +/doc/asio/reference/mutable_buffers_1/begin.html +/doc/asio/reference/mutable_buffers_1/const_iterator.html +/doc/asio/reference/mutable_buffers_1/end.html +/doc/asio/reference/mutable_buffers_1.html +/doc/asio/reference/mutable_buffers_1/mutable_buffers_1/ +/doc/asio/reference/mutable_buffers_1/mutable_buffers_1.html +/doc/asio/reference/mutable_buffers_1/mutable_buffers_1/overload1.html +/doc/asio/reference/mutable_buffers_1/mutable_buffers_1/overload2.html +/doc/asio/reference/mutable_buffers_1/operator_plus_/ +/doc/asio/reference/mutable_buffers_1/operator_plus_.html +/doc/asio/reference/mutable_buffers_1/operator_plus_/overload1.html +/doc/asio/reference/mutable_buffers_1/operator_plus_/overload2.html +/doc/asio/reference/mutable_buffers_1/value_type.html +/doc/asio/reference/MutableBufferSequence.html +/doc/asio/reference/null_buffers/ +/doc/asio/reference/null_buffers/begin.html +/doc/asio/reference/null_buffers/const_iterator.html +/doc/asio/reference/null_buffers/end.html +/doc/asio/reference/null_buffers.html +/doc/asio/reference/null_buffers/value_type.html +/doc/asio/reference/ObjectHandleService.html +/doc/asio/reference/operator_lt__lt_.html +/doc/asio/reference/placeholders__bytes_transferred.html +/doc/asio/reference/placeholders__error.html +/doc/asio/reference/placeholders__iterator.html +/doc/asio/reference/placeholders__signal_number.html +/doc/asio/reference/posix__basic_descriptor/ +/doc/asio/reference/posix__basic_descriptor/assign/ +/doc/asio/reference/posix__basic_descriptor/assign.html +/doc/asio/reference/posix__basic_descriptor/assign/overload1.html +/doc/asio/reference/posix__basic_descriptor/assign/overload2.html +/doc/asio/reference/posix__basic_descriptor/basic_descriptor/ +/doc/asio/reference/posix__basic_descriptor/_basic_descriptor.html +/doc/asio/reference/posix__basic_descriptor/basic_descriptor.html +/doc/asio/reference/posix__basic_descriptor/basic_descriptor/overload1.html +/doc/asio/reference/posix__basic_descriptor/basic_descriptor/overload2.html +/doc/asio/reference/posix__basic_descriptor/basic_descriptor/overload3.html +/doc/asio/reference/posix__basic_descriptor/bytes_readable.html +/doc/asio/reference/posix__basic_descriptor/cancel/ +/doc/asio/reference/posix__basic_descriptor/cancel.html +/doc/asio/reference/posix__basic_descriptor/cancel/overload1.html +/doc/asio/reference/posix__basic_descriptor/cancel/overload2.html +/doc/asio/reference/posix__basic_descriptor/close/ +/doc/asio/reference/posix__basic_descriptor/close.html +/doc/asio/reference/posix__basic_descriptor/close/overload1.html +/doc/asio/reference/posix__basic_descriptor/close/overload2.html +/doc/asio/reference/posix__basic_descriptor/get_implementation/ +/doc/asio/reference/posix__basic_descriptor/get_implementation.html +/doc/asio/reference/posix__basic_descriptor/get_implementation/overload1.html +/doc/asio/reference/posix__basic_descriptor/get_implementation/overload2.html +/doc/asio/reference/posix__basic_descriptor/get_io_service.html +/doc/asio/reference/posix__basic_descriptor/get_service/ +/doc/asio/reference/posix__basic_descriptor/get_service.html +/doc/asio/reference/posix__basic_descriptor/get_service/overload1.html +/doc/asio/reference/posix__basic_descriptor/get_service/overload2.html +/doc/asio/reference/posix__basic_descriptor.html +/doc/asio/reference/posix__basic_descriptor/implementation.html +/doc/asio/reference/posix__basic_descriptor/implementation_type.html +/doc/asio/reference/posix__basic_descriptor/io_control/ +/doc/asio/reference/posix__basic_descriptor/io_control.html +/doc/asio/reference/posix__basic_descriptor/io_control/overload1.html +/doc/asio/reference/posix__basic_descriptor/io_control/overload2.html +/doc/asio/reference/posix__basic_descriptor/is_open.html +/doc/asio/reference/posix__basic_descriptor/lowest_layer/ +/doc/asio/reference/posix__basic_descriptor/lowest_layer.html +/doc/asio/reference/posix__basic_descriptor/lowest_layer/overload1.html +/doc/asio/reference/posix__basic_descriptor/lowest_layer/overload2.html +/doc/asio/reference/posix__basic_descriptor/lowest_layer_type.html +/doc/asio/reference/posix__basic_descriptor/native_handle.html +/doc/asio/reference/posix__basic_descriptor/native_handle_type.html +/doc/asio/reference/posix__basic_descriptor/native.html +/doc/asio/reference/posix__basic_descriptor/native_non_blocking/ +/doc/asio/reference/posix__basic_descriptor/native_non_blocking.html +/doc/asio/reference/posix__basic_descriptor/native_non_blocking/overload1.html +/doc/asio/reference/posix__basic_descriptor/native_non_blocking/overload2.html +/doc/asio/reference/posix__basic_descriptor/native_non_blocking/overload3.html +/doc/asio/reference/posix__basic_descriptor/native_type.html +/doc/asio/reference/posix__basic_descriptor/non_blocking/ +/doc/asio/reference/posix__basic_descriptor/non_blocking.html +/doc/asio/reference/posix__basic_descriptor/non_blocking_io.html +/doc/asio/reference/posix__basic_descriptor/non_blocking/overload1.html +/doc/asio/reference/posix__basic_descriptor/non_blocking/overload2.html +/doc/asio/reference/posix__basic_descriptor/non_blocking/overload3.html +/doc/asio/reference/posix__basic_descriptor/operator_eq_.html +/doc/asio/reference/posix__basic_descriptor/release.html +/doc/asio/reference/posix__basic_descriptor/service.html +/doc/asio/reference/posix__basic_descriptor/service_type.html +/doc/asio/reference/posix__basic_stream_descriptor/ +/doc/asio/reference/posix__basic_stream_descriptor/assign/ +/doc/asio/reference/posix__basic_stream_descriptor/assign.html +/doc/asio/reference/posix__basic_stream_descriptor/assign/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/assign/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/async_read_some.html +/doc/asio/reference/posix__basic_stream_descriptor/async_write_some.html +/doc/asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/ +/doc/asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor.html +/doc/asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/overload3.html +/doc/asio/reference/posix__basic_stream_descriptor/bytes_readable.html +/doc/asio/reference/posix__basic_stream_descriptor/cancel/ +/doc/asio/reference/posix__basic_stream_descriptor/cancel.html +/doc/asio/reference/posix__basic_stream_descriptor/cancel/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/cancel/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/close/ +/doc/asio/reference/posix__basic_stream_descriptor/close.html +/doc/asio/reference/posix__basic_stream_descriptor/close/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/close/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/get_implementation/ +/doc/asio/reference/posix__basic_stream_descriptor/get_implementation.html +/doc/asio/reference/posix__basic_stream_descriptor/get_implementation/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/get_implementation/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/get_io_service.html +/doc/asio/reference/posix__basic_stream_descriptor/get_service/ +/doc/asio/reference/posix__basic_stream_descriptor/get_service.html +/doc/asio/reference/posix__basic_stream_descriptor/get_service/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/get_service/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor.html +/doc/asio/reference/posix__basic_stream_descriptor/implementation.html +/doc/asio/reference/posix__basic_stream_descriptor/implementation_type.html +/doc/asio/reference/posix__basic_stream_descriptor/io_control/ +/doc/asio/reference/posix__basic_stream_descriptor/io_control.html +/doc/asio/reference/posix__basic_stream_descriptor/io_control/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/io_control/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/is_open.html +/doc/asio/reference/posix__basic_stream_descriptor/lowest_layer/ +/doc/asio/reference/posix__basic_stream_descriptor/lowest_layer.html +/doc/asio/reference/posix__basic_stream_descriptor/lowest_layer/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/lowest_layer/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/lowest_layer_type.html +/doc/asio/reference/posix__basic_stream_descriptor/native_handle.html +/doc/asio/reference/posix__basic_stream_descriptor/native_handle_type.html +/doc/asio/reference/posix__basic_stream_descriptor/native.html +/doc/asio/reference/posix__basic_stream_descriptor/native_non_blocking/ +/doc/asio/reference/posix__basic_stream_descriptor/native_non_blocking.html +/doc/asio/reference/posix__basic_stream_descriptor/native_non_blocking/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/native_non_blocking/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/native_non_blocking/overload3.html +/doc/asio/reference/posix__basic_stream_descriptor/native_type.html +/doc/asio/reference/posix__basic_stream_descriptor/non_blocking/ +/doc/asio/reference/posix__basic_stream_descriptor/non_blocking.html +/doc/asio/reference/posix__basic_stream_descriptor/non_blocking_io.html +/doc/asio/reference/posix__basic_stream_descriptor/non_blocking/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/non_blocking/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/non_blocking/overload3.html +/doc/asio/reference/posix__basic_stream_descriptor/operator_eq_.html +/doc/asio/reference/posix__basic_stream_descriptor/read_some/ +/doc/asio/reference/posix__basic_stream_descriptor/read_some.html +/doc/asio/reference/posix__basic_stream_descriptor/read_some/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/read_some/overload2.html +/doc/asio/reference/posix__basic_stream_descriptor/release.html +/doc/asio/reference/posix__basic_stream_descriptor/service.html +/doc/asio/reference/posix__basic_stream_descriptor/service_type.html +/doc/asio/reference/posix__basic_stream_descriptor/write_some/ +/doc/asio/reference/posix__basic_stream_descriptor/write_some.html +/doc/asio/reference/posix__basic_stream_descriptor/write_some/overload1.html +/doc/asio/reference/posix__basic_stream_descriptor/write_some/overload2.html +/doc/asio/reference/posix__descriptor_base/ +/doc/asio/reference/posix__descriptor_base/bytes_readable.html +/doc/asio/reference/posix__descriptor_base/_descriptor_base.html +/doc/asio/reference/posix__descriptor_base.html +/doc/asio/reference/posix__descriptor_base/non_blocking_io.html +/doc/asio/reference/posix__stream_descriptor.html +/doc/asio/reference/posix__stream_descriptor_service/ +/doc/asio/reference/posix__stream_descriptor_service/assign.html +/doc/asio/reference/posix__stream_descriptor_service/async_read_some.html +/doc/asio/reference/posix__stream_descriptor_service/async_write_some.html +/doc/asio/reference/posix__stream_descriptor_service/cancel.html +/doc/asio/reference/posix__stream_descriptor_service/close.html +/doc/asio/reference/posix__stream_descriptor_service/construct.html +/doc/asio/reference/posix__stream_descriptor_service/destroy.html +/doc/asio/reference/posix__stream_descriptor_service/get_io_service.html +/doc/asio/reference/posix__stream_descriptor_service.html +/doc/asio/reference/posix__stream_descriptor_service/id.html +/doc/asio/reference/posix__stream_descriptor_service/implementation_type.html +/doc/asio/reference/posix__stream_descriptor_service/io_control.html +/doc/asio/reference/posix__stream_descriptor_service/is_open.html +/doc/asio/reference/posix__stream_descriptor_service/move_assign.html +/doc/asio/reference/posix__stream_descriptor_service/move_construct.html +/doc/asio/reference/posix__stream_descriptor_service/native_handle.html +/doc/asio/reference/posix__stream_descriptor_service/native_handle_type.html +/doc/asio/reference/posix__stream_descriptor_service/native.html +/doc/asio/reference/posix__stream_descriptor_service/native_non_blocking/ +/doc/asio/reference/posix__stream_descriptor_service/native_non_blocking.html +/doc/asio/reference/posix__stream_descriptor_service/native_non_blocking/overload1.html +/doc/asio/reference/posix__stream_descriptor_service/native_non_blocking/overload2.html +/doc/asio/reference/posix__stream_descriptor_service/native_type.html +/doc/asio/reference/posix__stream_descriptor_service/non_blocking/ +/doc/asio/reference/posix__stream_descriptor_service/non_blocking.html +/doc/asio/reference/posix__stream_descriptor_service/non_blocking/overload1.html +/doc/asio/reference/posix__stream_descriptor_service/non_blocking/overload2.html +/doc/asio/reference/posix__stream_descriptor_service/read_some.html +/doc/asio/reference/posix__stream_descriptor_service/release.html +/doc/asio/reference/posix__stream_descriptor_service/stream_descriptor_service.html +/doc/asio/reference/posix__stream_descriptor_service/write_some.html +/doc/asio/reference/Protocol.html +/doc/asio/reference/RandomAccessHandleService.html +/doc/asio/reference/raw_socket_service/ +/doc/asio/reference/raw_socket_service/assign.html +/doc/asio/reference/raw_socket_service/async_connect.html +/doc/asio/reference/raw_socket_service/async_receive_from.html +/doc/asio/reference/raw_socket_service/async_receive.html +/doc/asio/reference/raw_socket_service/async_send.html +/doc/asio/reference/raw_socket_service/async_send_to.html +/doc/asio/reference/raw_socket_service/at_mark.html +/doc/asio/reference/raw_socket_service/available.html +/doc/asio/reference/raw_socket_service/bind.html +/doc/asio/reference/raw_socket_service/cancel.html +/doc/asio/reference/raw_socket_service/close.html +/doc/asio/reference/raw_socket_service/connect.html +/doc/asio/reference/raw_socket_service/construct.html +/doc/asio/reference/raw_socket_service/converting_move_construct.html +/doc/asio/reference/raw_socket_service/destroy.html +/doc/asio/reference/raw_socket_service/endpoint_type.html +/doc/asio/reference/raw_socket_service/get_io_service.html +/doc/asio/reference/raw_socket_service/get_option.html +/doc/asio/reference/raw_socket_service.html +/doc/asio/reference/RawSocketService.html +/doc/asio/reference/raw_socket_service/id.html +/doc/asio/reference/raw_socket_service/implementation_type.html +/doc/asio/reference/raw_socket_service/io_control.html +/doc/asio/reference/raw_socket_service/is_open.html +/doc/asio/reference/raw_socket_service/local_endpoint.html +/doc/asio/reference/raw_socket_service/move_assign.html +/doc/asio/reference/raw_socket_service/move_construct.html +/doc/asio/reference/raw_socket_service/native_handle.html +/doc/asio/reference/raw_socket_service/native_handle_type.html +/doc/asio/reference/raw_socket_service/native.html +/doc/asio/reference/raw_socket_service/native_non_blocking/ +/doc/asio/reference/raw_socket_service/native_non_blocking.html +/doc/asio/reference/raw_socket_service/native_non_blocking/overload1.html +/doc/asio/reference/raw_socket_service/native_non_blocking/overload2.html +/doc/asio/reference/raw_socket_service/native_type.html +/doc/asio/reference/raw_socket_service/non_blocking/ +/doc/asio/reference/raw_socket_service/non_blocking.html +/doc/asio/reference/raw_socket_service/non_blocking/overload1.html +/doc/asio/reference/raw_socket_service/non_blocking/overload2.html +/doc/asio/reference/raw_socket_service/open.html +/doc/asio/reference/raw_socket_service/protocol_type.html +/doc/asio/reference/raw_socket_service/raw_socket_service.html +/doc/asio/reference/raw_socket_service/receive_from.html +/doc/asio/reference/raw_socket_service/receive.html +/doc/asio/reference/raw_socket_service/remote_endpoint.html +/doc/asio/reference/raw_socket_service/send.html +/doc/asio/reference/raw_socket_service/send_to.html +/doc/asio/reference/raw_socket_service/set_option.html +/doc/asio/reference/raw_socket_service/shutdown.html +/doc/asio/reference/read/ +/doc/asio/reference/read_at/ +/doc/asio/reference/read_at.html +/doc/asio/reference/read_at/overload1.html +/doc/asio/reference/read_at/overload2.html +/doc/asio/reference/read_at/overload3.html +/doc/asio/reference/read_at/overload4.html +/doc/asio/reference/read_at/overload5.html +/doc/asio/reference/read_at/overload6.html +/doc/asio/reference/read_at/overload7.html +/doc/asio/reference/read_at/overload8.html +/doc/asio/reference/ReadHandler.html +/doc/asio/reference/read.html +/doc/asio/reference/read/overload1.html +/doc/asio/reference/read/overload2.html +/doc/asio/reference/read/overload3.html +/doc/asio/reference/read/overload4.html +/doc/asio/reference/read/overload5.html +/doc/asio/reference/read/overload6.html +/doc/asio/reference/read/overload7.html +/doc/asio/reference/read/overload8.html +/doc/asio/reference/read_until/ +/doc/asio/reference/read_until.html +/doc/asio/reference/read_until/overload1.html +/doc/asio/reference/read_until/overload2.html +/doc/asio/reference/read_until/overload3.html +/doc/asio/reference/read_until/overload4.html +/doc/asio/reference/read_until/overload5.html +/doc/asio/reference/read_until/overload6.html +/doc/asio/reference/read_until/overload7.html +/doc/asio/reference/read_until/overload8.html +/doc/asio/reference/ResolveHandler.html +/doc/asio/reference/ResolverService.html +/doc/asio/reference/seq_packet_socket_service/ +/doc/asio/reference/seq_packet_socket_service/assign.html +/doc/asio/reference/seq_packet_socket_service/async_connect.html +/doc/asio/reference/seq_packet_socket_service/async_receive.html +/doc/asio/reference/seq_packet_socket_service/async_send.html +/doc/asio/reference/seq_packet_socket_service/at_mark.html +/doc/asio/reference/seq_packet_socket_service/available.html +/doc/asio/reference/seq_packet_socket_service/bind.html +/doc/asio/reference/seq_packet_socket_service/cancel.html +/doc/asio/reference/seq_packet_socket_service/close.html +/doc/asio/reference/seq_packet_socket_service/connect.html +/doc/asio/reference/seq_packet_socket_service/construct.html +/doc/asio/reference/seq_packet_socket_service/converting_move_construct.html +/doc/asio/reference/seq_packet_socket_service/destroy.html +/doc/asio/reference/seq_packet_socket_service/endpoint_type.html +/doc/asio/reference/seq_packet_socket_service/get_io_service.html +/doc/asio/reference/seq_packet_socket_service/get_option.html +/doc/asio/reference/seq_packet_socket_service.html +/doc/asio/reference/SeqPacketSocketService.html +/doc/asio/reference/seq_packet_socket_service/id.html +/doc/asio/reference/seq_packet_socket_service/implementation_type.html +/doc/asio/reference/seq_packet_socket_service/io_control.html +/doc/asio/reference/seq_packet_socket_service/is_open.html +/doc/asio/reference/seq_packet_socket_service/local_endpoint.html +/doc/asio/reference/seq_packet_socket_service/move_assign.html +/doc/asio/reference/seq_packet_socket_service/move_construct.html +/doc/asio/reference/seq_packet_socket_service/native_handle.html +/doc/asio/reference/seq_packet_socket_service/native_handle_type.html +/doc/asio/reference/seq_packet_socket_service/native.html +/doc/asio/reference/seq_packet_socket_service/native_non_blocking/ +/doc/asio/reference/seq_packet_socket_service/native_non_blocking.html +/doc/asio/reference/seq_packet_socket_service/native_non_blocking/overload1.html +/doc/asio/reference/seq_packet_socket_service/native_non_blocking/overload2.html +/doc/asio/reference/seq_packet_socket_service/native_type.html +/doc/asio/reference/seq_packet_socket_service/non_blocking/ +/doc/asio/reference/seq_packet_socket_service/non_blocking.html +/doc/asio/reference/seq_packet_socket_service/non_blocking/overload1.html +/doc/asio/reference/seq_packet_socket_service/non_blocking/overload2.html +/doc/asio/reference/seq_packet_socket_service/open.html +/doc/asio/reference/seq_packet_socket_service/protocol_type.html +/doc/asio/reference/seq_packet_socket_service/receive.html +/doc/asio/reference/seq_packet_socket_service/remote_endpoint.html +/doc/asio/reference/seq_packet_socket_service/send.html +/doc/asio/reference/seq_packet_socket_service/seq_packet_socket_service.html +/doc/asio/reference/seq_packet_socket_service/set_option.html +/doc/asio/reference/seq_packet_socket_service/shutdown.html +/doc/asio/reference/serial_port_base/ +/doc/asio/reference/serial_port_base__baud_rate/ +/doc/asio/reference/serial_port_base__baud_rate/baud_rate.html +/doc/asio/reference/serial_port_base__baud_rate.html +/doc/asio/reference/serial_port_base__baud_rate/load.html +/doc/asio/reference/serial_port_base__baud_rate/store.html +/doc/asio/reference/serial_port_base__baud_rate/value.html +/doc/asio/reference/serial_port_base__character_size/ +/doc/asio/reference/serial_port_base__character_size/character_size.html +/doc/asio/reference/serial_port_base__character_size.html +/doc/asio/reference/serial_port_base__character_size/load.html +/doc/asio/reference/serial_port_base__character_size/store.html +/doc/asio/reference/serial_port_base__character_size/value.html +/doc/asio/reference/serial_port_base__flow_control/ +/doc/asio/reference/serial_port_base__flow_control/flow_control.html +/doc/asio/reference/serial_port_base__flow_control.html +/doc/asio/reference/serial_port_base__flow_control/load.html +/doc/asio/reference/serial_port_base__flow_control/store.html +/doc/asio/reference/serial_port_base__flow_control/type.html +/doc/asio/reference/serial_port_base__flow_control/value.html +/doc/asio/reference/serial_port_base.html +/doc/asio/reference/serial_port_base__parity/ +/doc/asio/reference/serial_port_base__parity.html +/doc/asio/reference/serial_port_base__parity/load.html +/doc/asio/reference/serial_port_base__parity/parity.html +/doc/asio/reference/serial_port_base__parity/store.html +/doc/asio/reference/serial_port_base__parity/type.html +/doc/asio/reference/serial_port_base__parity/value.html +/doc/asio/reference/serial_port_base/_serial_port_base.html +/doc/asio/reference/serial_port_base__stop_bits/ +/doc/asio/reference/serial_port_base__stop_bits.html +/doc/asio/reference/serial_port_base__stop_bits/load.html +/doc/asio/reference/serial_port_base__stop_bits/stop_bits.html +/doc/asio/reference/serial_port_base__stop_bits/store.html +/doc/asio/reference/serial_port_base__stop_bits/type.html +/doc/asio/reference/serial_port_base__stop_bits/value.html +/doc/asio/reference/serial_port.html +/doc/asio/reference/serial_port_service/ +/doc/asio/reference/serial_port_service/assign.html +/doc/asio/reference/serial_port_service/async_read_some.html +/doc/asio/reference/serial_port_service/async_write_some.html +/doc/asio/reference/serial_port_service/cancel.html +/doc/asio/reference/serial_port_service/close.html +/doc/asio/reference/serial_port_service/construct.html +/doc/asio/reference/serial_port_service/destroy.html +/doc/asio/reference/serial_port_service/get_io_service.html +/doc/asio/reference/serial_port_service/get_option.html +/doc/asio/reference/serial_port_service.html +/doc/asio/reference/SerialPortService.html +/doc/asio/reference/serial_port_service/id.html +/doc/asio/reference/serial_port_service/implementation_type.html +/doc/asio/reference/serial_port_service/is_open.html +/doc/asio/reference/serial_port_service/move_assign.html +/doc/asio/reference/serial_port_service/move_construct.html +/doc/asio/reference/serial_port_service/native_handle.html +/doc/asio/reference/serial_port_service/native_handle_type.html +/doc/asio/reference/serial_port_service/native.html +/doc/asio/reference/serial_port_service/native_type.html +/doc/asio/reference/serial_port_service/open.html +/doc/asio/reference/serial_port_service/read_some.html +/doc/asio/reference/serial_port_service/send_break.html +/doc/asio/reference/serial_port_service/serial_port_service.html +/doc/asio/reference/serial_port_service/set_option.html +/doc/asio/reference/serial_port_service/write_some.html +/doc/asio/reference/service_already_exists/ +/doc/asio/reference/service_already_exists.html +/doc/asio/reference/service_already_exists/service_already_exists.html +/doc/asio/reference/Service.html +/doc/asio/reference/SettableSerialPortOption.html +/doc/asio/reference/SettableSocketOption.html +/doc/asio/reference/ShutdownHandler.html +/doc/asio/reference/SignalHandler.html +/doc/asio/reference/signal_set.html +/doc/asio/reference/signal_set_service/ +/doc/asio/reference/signal_set_service/add.html +/doc/asio/reference/signal_set_service/async_wait.html +/doc/asio/reference/signal_set_service/cancel.html +/doc/asio/reference/signal_set_service/clear.html +/doc/asio/reference/signal_set_service/construct.html +/doc/asio/reference/signal_set_service/destroy.html +/doc/asio/reference/signal_set_service/get_io_service.html +/doc/asio/reference/signal_set_service.html +/doc/asio/reference/SignalSetService.html +/doc/asio/reference/signal_set_service/id.html +/doc/asio/reference/signal_set_service/implementation_type.html +/doc/asio/reference/signal_set_service/remove.html +/doc/asio/reference/signal_set_service/signal_set_service.html +/doc/asio/reference/socket_acceptor_service/ +/doc/asio/reference/socket_acceptor_service/accept.html +/doc/asio/reference/socket_acceptor_service/assign.html +/doc/asio/reference/socket_acceptor_service/async_accept.html +/doc/asio/reference/socket_acceptor_service/bind.html +/doc/asio/reference/socket_acceptor_service/cancel.html +/doc/asio/reference/socket_acceptor_service/close.html +/doc/asio/reference/socket_acceptor_service/construct.html +/doc/asio/reference/socket_acceptor_service/converting_move_construct.html +/doc/asio/reference/socket_acceptor_service/destroy.html +/doc/asio/reference/socket_acceptor_service/endpoint_type.html +/doc/asio/reference/socket_acceptor_service/get_io_service.html +/doc/asio/reference/socket_acceptor_service/get_option.html +/doc/asio/reference/socket_acceptor_service.html +/doc/asio/reference/SocketAcceptorService.html +/doc/asio/reference/socket_acceptor_service/id.html +/doc/asio/reference/socket_acceptor_service/implementation_type.html +/doc/asio/reference/socket_acceptor_service/io_control.html +/doc/asio/reference/socket_acceptor_service/is_open.html +/doc/asio/reference/socket_acceptor_service/listen.html +/doc/asio/reference/socket_acceptor_service/local_endpoint.html +/doc/asio/reference/socket_acceptor_service/move_assign.html +/doc/asio/reference/socket_acceptor_service/move_construct.html +/doc/asio/reference/socket_acceptor_service/native_handle.html +/doc/asio/reference/socket_acceptor_service/native_handle_type.html +/doc/asio/reference/socket_acceptor_service/native.html +/doc/asio/reference/socket_acceptor_service/native_non_blocking/ +/doc/asio/reference/socket_acceptor_service/native_non_blocking.html +/doc/asio/reference/socket_acceptor_service/native_non_blocking/overload1.html +/doc/asio/reference/socket_acceptor_service/native_non_blocking/overload2.html +/doc/asio/reference/socket_acceptor_service/native_type.html +/doc/asio/reference/socket_acceptor_service/non_blocking/ +/doc/asio/reference/socket_acceptor_service/non_blocking.html +/doc/asio/reference/socket_acceptor_service/non_blocking/overload1.html +/doc/asio/reference/socket_acceptor_service/non_blocking/overload2.html +/doc/asio/reference/socket_acceptor_service/open.html +/doc/asio/reference/socket_acceptor_service/protocol_type.html +/doc/asio/reference/socket_acceptor_service/set_option.html +/doc/asio/reference/socket_acceptor_service/socket_acceptor_service.html +/doc/asio/reference/socket_base/ +/doc/asio/reference/socket_base/broadcast.html +/doc/asio/reference/socket_base/bytes_readable.html +/doc/asio/reference/socket_base/debug.html +/doc/asio/reference/socket_base/do_not_route.html +/doc/asio/reference/socket_base/enable_connection_aborted.html +/doc/asio/reference/socket_base.html +/doc/asio/reference/socket_base/keep_alive.html +/doc/asio/reference/socket_base/linger.html +/doc/asio/reference/socket_base/max_connections.html +/doc/asio/reference/socket_base/message_do_not_route.html +/doc/asio/reference/socket_base/message_end_of_record.html +/doc/asio/reference/socket_base/message_flags.html +/doc/asio/reference/socket_base/message_out_of_band.html +/doc/asio/reference/socket_base/message_peek.html +/doc/asio/reference/socket_base/non_blocking_io.html +/doc/asio/reference/socket_base/receive_buffer_size.html +/doc/asio/reference/socket_base/receive_low_watermark.html +/doc/asio/reference/socket_base/reuse_address.html +/doc/asio/reference/socket_base/send_buffer_size.html +/doc/asio/reference/socket_base/send_low_watermark.html +/doc/asio/reference/socket_base/shutdown_type.html +/doc/asio/reference/socket_base/_socket_base.html +/doc/asio/reference/SocketService.html +/doc/asio/reference/spawn/ +/doc/asio/reference/spawn.html +/doc/asio/reference/spawn/overload1.html +/doc/asio/reference/spawn/overload2.html +/doc/asio/reference/spawn/overload3.html +/doc/asio/reference/spawn/overload4.html +/doc/asio/reference/ssl__context/ +/doc/asio/reference/ssl__context/add_certificate_authority/ +/doc/asio/reference/ssl__context/add_certificate_authority.html +/doc/asio/reference/ssl__context/add_certificate_authority/overload1.html +/doc/asio/reference/ssl__context/add_certificate_authority/overload2.html +/doc/asio/reference/ssl__context/add_verify_path/ +/doc/asio/reference/ssl__context/add_verify_path.html +/doc/asio/reference/ssl__context/add_verify_path/overload1.html +/doc/asio/reference/ssl__context/add_verify_path/overload2.html +/doc/asio/reference/ssl__context_base/ +/doc/asio/reference/ssl__context_base/_context_base.html +/doc/asio/reference/ssl__context_base/default_workarounds.html +/doc/asio/reference/ssl__context_base/file_format.html +/doc/asio/reference/ssl__context_base.html +/doc/asio/reference/ssl__context_base/method.html +/doc/asio/reference/ssl__context_base/no_compression.html +/doc/asio/reference/ssl__context_base/no_sslv2.html +/doc/asio/reference/ssl__context_base/no_sslv3.html +/doc/asio/reference/ssl__context_base/no_tlsv1_1.html +/doc/asio/reference/ssl__context_base/no_tlsv1_2.html +/doc/asio/reference/ssl__context_base/no_tlsv1.html +/doc/asio/reference/ssl__context_base/options.html +/doc/asio/reference/ssl__context_base/password_purpose.html +/doc/asio/reference/ssl__context_base/single_dh_use.html +/doc/asio/reference/ssl__context/clear_options/ +/doc/asio/reference/ssl__context/clear_options.html +/doc/asio/reference/ssl__context/clear_options/overload1.html +/doc/asio/reference/ssl__context/clear_options/overload2.html +/doc/asio/reference/ssl__context/context/ +/doc/asio/reference/ssl__context/_context.html +/doc/asio/reference/ssl__context/context.html +/doc/asio/reference/ssl__context/context/overload1.html +/doc/asio/reference/ssl__context/context/overload2.html +/doc/asio/reference/ssl__context/context/overload3.html +/doc/asio/reference/ssl__context/default_workarounds.html +/doc/asio/reference/ssl__context/file_format.html +/doc/asio/reference/ssl__context.html +/doc/asio/reference/ssl__context/impl.html +/doc/asio/reference/ssl__context/impl_type.html +/doc/asio/reference/ssl__context/load_verify_file/ +/doc/asio/reference/ssl__context/load_verify_file.html +/doc/asio/reference/ssl__context/load_verify_file/overload1.html +/doc/asio/reference/ssl__context/load_verify_file/overload2.html +/doc/asio/reference/ssl__context/method.html +/doc/asio/reference/ssl__context/native_handle.html +/doc/asio/reference/ssl__context/native_handle_type.html +/doc/asio/reference/ssl__context/no_compression.html +/doc/asio/reference/ssl__context/no_sslv2.html +/doc/asio/reference/ssl__context/no_sslv3.html +/doc/asio/reference/ssl__context/no_tlsv1_1.html +/doc/asio/reference/ssl__context/no_tlsv1_2.html +/doc/asio/reference/ssl__context/no_tlsv1.html +/doc/asio/reference/ssl__context/operator_eq_.html +/doc/asio/reference/ssl__context/options.html +/doc/asio/reference/ssl__context/password_purpose.html +/doc/asio/reference/ssl__context/set_default_verify_paths/ +/doc/asio/reference/ssl__context/set_default_verify_paths.html +/doc/asio/reference/ssl__context/set_default_verify_paths/overload1.html +/doc/asio/reference/ssl__context/set_default_verify_paths/overload2.html +/doc/asio/reference/ssl__context/set_options/ +/doc/asio/reference/ssl__context/set_options.html +/doc/asio/reference/ssl__context/set_options/overload1.html +/doc/asio/reference/ssl__context/set_options/overload2.html +/doc/asio/reference/ssl__context/set_password_callback/ +/doc/asio/reference/ssl__context/set_password_callback.html +/doc/asio/reference/ssl__context/set_password_callback/overload1.html +/doc/asio/reference/ssl__context/set_password_callback/overload2.html +/doc/asio/reference/ssl__context/set_verify_callback/ +/doc/asio/reference/ssl__context/set_verify_callback.html +/doc/asio/reference/ssl__context/set_verify_callback/overload1.html +/doc/asio/reference/ssl__context/set_verify_callback/overload2.html +/doc/asio/reference/ssl__context/set_verify_depth/ +/doc/asio/reference/ssl__context/set_verify_depth.html +/doc/asio/reference/ssl__context/set_verify_depth/overload1.html +/doc/asio/reference/ssl__context/set_verify_depth/overload2.html +/doc/asio/reference/ssl__context/set_verify_mode/ +/doc/asio/reference/ssl__context/set_verify_mode.html +/doc/asio/reference/ssl__context/set_verify_mode/overload1.html +/doc/asio/reference/ssl__context/set_verify_mode/overload2.html +/doc/asio/reference/ssl__context/single_dh_use.html +/doc/asio/reference/ssl__context/use_certificate/ +/doc/asio/reference/ssl__context/use_certificate_chain/ +/doc/asio/reference/ssl__context/use_certificate_chain_file/ +/doc/asio/reference/ssl__context/use_certificate_chain_file.html +/doc/asio/reference/ssl__context/use_certificate_chain_file/overload1.html +/doc/asio/reference/ssl__context/use_certificate_chain_file/overload2.html +/doc/asio/reference/ssl__context/use_certificate_chain.html +/doc/asio/reference/ssl__context/use_certificate_chain/overload1.html +/doc/asio/reference/ssl__context/use_certificate_chain/overload2.html +/doc/asio/reference/ssl__context/use_certificate_file/ +/doc/asio/reference/ssl__context/use_certificate_file.html +/doc/asio/reference/ssl__context/use_certificate_file/overload1.html +/doc/asio/reference/ssl__context/use_certificate_file/overload2.html +/doc/asio/reference/ssl__context/use_certificate.html +/doc/asio/reference/ssl__context/use_certificate/overload1.html +/doc/asio/reference/ssl__context/use_certificate/overload2.html +/doc/asio/reference/ssl__context/use_private_key/ +/doc/asio/reference/ssl__context/use_private_key_file/ +/doc/asio/reference/ssl__context/use_private_key_file.html +/doc/asio/reference/ssl__context/use_private_key_file/overload1.html +/doc/asio/reference/ssl__context/use_private_key_file/overload2.html +/doc/asio/reference/ssl__context/use_private_key.html +/doc/asio/reference/ssl__context/use_private_key/overload1.html +/doc/asio/reference/ssl__context/use_private_key/overload2.html +/doc/asio/reference/ssl__context/use_rsa_private_key/ +/doc/asio/reference/ssl__context/use_rsa_private_key_file/ +/doc/asio/reference/ssl__context/use_rsa_private_key_file.html +/doc/asio/reference/ssl__context/use_rsa_private_key_file/overload1.html +/doc/asio/reference/ssl__context/use_rsa_private_key_file/overload2.html +/doc/asio/reference/ssl__context/use_rsa_private_key.html +/doc/asio/reference/ssl__context/use_rsa_private_key/overload1.html +/doc/asio/reference/ssl__context/use_rsa_private_key/overload2.html +/doc/asio/reference/ssl__context/use_tmp_dh/ +/doc/asio/reference/ssl__context/use_tmp_dh_file/ +/doc/asio/reference/ssl__context/use_tmp_dh_file.html +/doc/asio/reference/ssl__context/use_tmp_dh_file/overload1.html +/doc/asio/reference/ssl__context/use_tmp_dh_file/overload2.html +/doc/asio/reference/ssl__context/use_tmp_dh.html +/doc/asio/reference/ssl__context/use_tmp_dh/overload1.html +/doc/asio/reference/ssl__context/use_tmp_dh/overload2.html +/doc/asio/reference/ssl__error__get_stream_category.html +/doc/asio/reference/ssl__error__make_error_code.html +/doc/asio/reference/ssl__error__stream_category.html +/doc/asio/reference/ssl__error__stream_errors.html +/doc/asio/reference/ssl__rfc2818_verification/ +/doc/asio/reference/ssl__rfc2818_verification.html +/doc/asio/reference/ssl__rfc2818_verification/operator_lp__rp_.html +/doc/asio/reference/ssl__rfc2818_verification/result_type.html +/doc/asio/reference/ssl__rfc2818_verification/rfc2818_verification.html +/doc/asio/reference/ssl__stream/ +/doc/asio/reference/ssl__stream/async_handshake/ +/doc/asio/reference/ssl__stream/async_handshake.html +/doc/asio/reference/ssl__stream/async_handshake/overload1.html +/doc/asio/reference/ssl__stream/async_handshake/overload2.html +/doc/asio/reference/ssl__stream/async_read_some.html +/doc/asio/reference/ssl__stream/async_shutdown.html +/doc/asio/reference/ssl__stream/async_write_some.html +/doc/asio/reference/ssl__stream_base/ +/doc/asio/reference/ssl__stream_base/handshake_type.html +/doc/asio/reference/ssl__stream_base.html +/doc/asio/reference/ssl__stream_base/_stream_base.html +/doc/asio/reference/ssl__stream/get_io_service.html +/doc/asio/reference/ssl__stream/handshake/ +/doc/asio/reference/ssl__stream/handshake.html +/doc/asio/reference/ssl__stream/handshake/overload1.html +/doc/asio/reference/ssl__stream/handshake/overload2.html +/doc/asio/reference/ssl__stream/handshake/overload3.html +/doc/asio/reference/ssl__stream/handshake/overload4.html +/doc/asio/reference/ssl__stream/handshake_type.html +/doc/asio/reference/ssl__stream.html +/doc/asio/reference/ssl__stream/impl.html +/doc/asio/reference/ssl__stream__impl_struct/ +/doc/asio/reference/ssl__stream__impl_struct.html +/doc/asio/reference/ssl__stream__impl_struct/ssl.html +/doc/asio/reference/ssl__stream/impl_type.html +/doc/asio/reference/ssl__stream/lowest_layer/ +/doc/asio/reference/ssl__stream/lowest_layer.html +/doc/asio/reference/ssl__stream/lowest_layer/overload1.html +/doc/asio/reference/ssl__stream/lowest_layer/overload2.html +/doc/asio/reference/ssl__stream/lowest_layer_type.html +/doc/asio/reference/ssl__stream/native_handle.html +/doc/asio/reference/ssl__stream/native_handle_type.html +/doc/asio/reference/ssl__stream/next_layer/ +/doc/asio/reference/ssl__stream/next_layer.html +/doc/asio/reference/ssl__stream/next_layer/overload1.html +/doc/asio/reference/ssl__stream/next_layer/overload2.html +/doc/asio/reference/ssl__stream/next_layer_type.html +/doc/asio/reference/ssl__stream/read_some/ +/doc/asio/reference/ssl__stream/read_some.html +/doc/asio/reference/ssl__stream/read_some/overload1.html +/doc/asio/reference/ssl__stream/read_some/overload2.html +/doc/asio/reference/ssl__stream/set_verify_callback/ +/doc/asio/reference/ssl__stream/set_verify_callback.html +/doc/asio/reference/ssl__stream/set_verify_callback/overload1.html +/doc/asio/reference/ssl__stream/set_verify_callback/overload2.html +/doc/asio/reference/ssl__stream/set_verify_depth/ +/doc/asio/reference/ssl__stream/set_verify_depth.html +/doc/asio/reference/ssl__stream/set_verify_depth/overload1.html +/doc/asio/reference/ssl__stream/set_verify_depth/overload2.html +/doc/asio/reference/ssl__stream/set_verify_mode/ +/doc/asio/reference/ssl__stream/set_verify_mode.html +/doc/asio/reference/ssl__stream/set_verify_mode/overload1.html +/doc/asio/reference/ssl__stream/set_verify_mode/overload2.html +/doc/asio/reference/ssl__stream/shutdown/ +/doc/asio/reference/ssl__stream/shutdown.html +/doc/asio/reference/ssl__stream/shutdown/overload1.html +/doc/asio/reference/ssl__stream/shutdown/overload2.html +/doc/asio/reference/ssl__stream/_stream.html +/doc/asio/reference/ssl__stream/stream.html +/doc/asio/reference/ssl__stream/write_some/ +/doc/asio/reference/ssl__stream/write_some.html +/doc/asio/reference/ssl__stream/write_some/overload1.html +/doc/asio/reference/ssl__stream/write_some/overload2.html +/doc/asio/reference/ssl__verify_client_once.html +/doc/asio/reference/ssl__verify_context/ +/doc/asio/reference/ssl__verify_context.html +/doc/asio/reference/ssl__verify_context/native_handle.html +/doc/asio/reference/ssl__verify_context/native_handle_type.html +/doc/asio/reference/ssl__verify_context/verify_context.html +/doc/asio/reference/ssl__verify_fail_if_no_peer_cert.html +/doc/asio/reference/ssl__verify_mode.html +/doc/asio/reference/ssl__verify_none.html +/doc/asio/reference/ssl__verify_peer.html +/doc/asio/reference/steady_timer.html +/doc/asio/reference/strand.html +/doc/asio/reference/streambuf.html +/doc/asio/reference/StreamDescriptorService.html +/doc/asio/reference/StreamHandleService.html +/doc/asio/reference/stream_socket_service/ +/doc/asio/reference/stream_socket_service/assign.html +/doc/asio/reference/stream_socket_service/async_connect.html +/doc/asio/reference/stream_socket_service/async_receive.html +/doc/asio/reference/stream_socket_service/async_send.html +/doc/asio/reference/stream_socket_service/at_mark.html +/doc/asio/reference/stream_socket_service/available.html +/doc/asio/reference/stream_socket_service/bind.html +/doc/asio/reference/stream_socket_service/cancel.html +/doc/asio/reference/stream_socket_service/close.html +/doc/asio/reference/stream_socket_service/connect.html +/doc/asio/reference/stream_socket_service/construct.html +/doc/asio/reference/stream_socket_service/converting_move_construct.html +/doc/asio/reference/stream_socket_service/destroy.html +/doc/asio/reference/stream_socket_service/endpoint_type.html +/doc/asio/reference/stream_socket_service/get_io_service.html +/doc/asio/reference/stream_socket_service/get_option.html +/doc/asio/reference/stream_socket_service.html +/doc/asio/reference/StreamSocketService.html +/doc/asio/reference/stream_socket_service/id.html +/doc/asio/reference/stream_socket_service/implementation_type.html +/doc/asio/reference/stream_socket_service/io_control.html +/doc/asio/reference/stream_socket_service/is_open.html +/doc/asio/reference/stream_socket_service/local_endpoint.html +/doc/asio/reference/stream_socket_service/move_assign.html +/doc/asio/reference/stream_socket_service/move_construct.html +/doc/asio/reference/stream_socket_service/native_handle.html +/doc/asio/reference/stream_socket_service/native_handle_type.html +/doc/asio/reference/stream_socket_service/native.html +/doc/asio/reference/stream_socket_service/native_non_blocking/ +/doc/asio/reference/stream_socket_service/native_non_blocking.html +/doc/asio/reference/stream_socket_service/native_non_blocking/overload1.html +/doc/asio/reference/stream_socket_service/native_non_blocking/overload2.html +/doc/asio/reference/stream_socket_service/native_type.html +/doc/asio/reference/stream_socket_service/non_blocking/ +/doc/asio/reference/stream_socket_service/non_blocking.html +/doc/asio/reference/stream_socket_service/non_blocking/overload1.html +/doc/asio/reference/stream_socket_service/non_blocking/overload2.html +/doc/asio/reference/stream_socket_service/open.html +/doc/asio/reference/stream_socket_service/protocol_type.html +/doc/asio/reference/stream_socket_service/receive.html +/doc/asio/reference/stream_socket_service/remote_endpoint.html +/doc/asio/reference/stream_socket_service/send.html +/doc/asio/reference/stream_socket_service/set_option.html +/doc/asio/reference/stream_socket_service/shutdown.html +/doc/asio/reference/stream_socket_service/stream_socket_service.html +/doc/asio/reference/SyncRandomAccessReadDevice.html +/doc/asio/reference/SyncRandomAccessWriteDevice.html +/doc/asio/reference/SyncReadStream.html +/doc/asio/reference/SyncWriteStream.html +/doc/asio/reference/system_category.html +/doc/asio/reference/system_error/ +/doc/asio/reference/system_error/code.html +/doc/asio/reference/system_error.html +/doc/asio/reference/system_error/operator_eq_.html +/doc/asio/reference/system_error/system_error/ +/doc/asio/reference/system_error/_system_error.html +/doc/asio/reference/system_error/system_error.html +/doc/asio/reference/system_error/system_error/overload1.html +/doc/asio/reference/system_error/system_error/overload2.html +/doc/asio/reference/system_error/system_error/overload3.html +/doc/asio/reference/system_error/what.html +/doc/asio/reference/system_timer.html +/doc/asio/reference/thread/ +/doc/asio/reference/thread.html +/doc/asio/reference/thread/join.html +/doc/asio/reference/thread/_thread.html +/doc/asio/reference/thread/thread.html +/doc/asio/reference/TimerService.html +/doc/asio/reference/TimeTraits.html +/doc/asio/reference/time_traits_lt__ptime__gt_/ +/doc/asio/reference/time_traits_lt__ptime__gt_/add.html +/doc/asio/reference/time_traits_lt__ptime__gt_/duration_type.html +/doc/asio/reference/time_traits_lt__ptime__gt_.html +/doc/asio/reference/time_traits_lt__ptime__gt_/less_than.html +/doc/asio/reference/time_traits_lt__ptime__gt_/now.html +/doc/asio/reference/time_traits_lt__ptime__gt_/subtract.html +/doc/asio/reference/time_traits_lt__ptime__gt_/time_type.html +/doc/asio/reference/time_traits_lt__ptime__gt_/to_posix_duration.html +/doc/asio/reference/transfer_all.html +/doc/asio/reference/transfer_at_least.html +/doc/asio/reference/transfer_exactly.html +/doc/asio/reference/use_future.html +/doc/asio/reference/use_future_t/ +/doc/asio/reference/use_future_t/allocator_type.html +/doc/asio/reference/use_future_t/get_allocator.html +/doc/asio/reference/use_future_t.html +/doc/asio/reference/use_future_t/operator_lb__rb_.html +/doc/asio/reference/use_future_t/use_future_t/ +/doc/asio/reference/use_future_t/use_future_t.html +/doc/asio/reference/use_future_t/use_future_t/overload1.html +/doc/asio/reference/use_future_t/use_future_t/overload2.html +/doc/asio/reference/use_service.html +/doc/asio/reference/waitable_timer_service/ +/doc/asio/reference/waitable_timer_service/async_wait.html +/doc/asio/reference/waitable_timer_service/cancel.html +/doc/asio/reference/waitable_timer_service/cancel_one.html +/doc/asio/reference/waitable_timer_service/clock_type.html +/doc/asio/reference/waitable_timer_service/construct.html +/doc/asio/reference/waitable_timer_service/destroy.html +/doc/asio/reference/waitable_timer_service/duration.html +/doc/asio/reference/waitable_timer_service/expires_at/ +/doc/asio/reference/waitable_timer_service/expires_at.html +/doc/asio/reference/waitable_timer_service/expires_at/overload1.html +/doc/asio/reference/waitable_timer_service/expires_at/overload2.html +/doc/asio/reference/waitable_timer_service/expires_from_now/ +/doc/asio/reference/waitable_timer_service/expires_from_now.html +/doc/asio/reference/waitable_timer_service/expires_from_now/overload1.html +/doc/asio/reference/waitable_timer_service/expires_from_now/overload2.html +/doc/asio/reference/waitable_timer_service/get_io_service.html +/doc/asio/reference/waitable_timer_service.html +/doc/asio/reference/WaitableTimerService.html +/doc/asio/reference/waitable_timer_service/id.html +/doc/asio/reference/waitable_timer_service/implementation_type.html +/doc/asio/reference/waitable_timer_service/time_point.html +/doc/asio/reference/waitable_timer_service/traits_type.html +/doc/asio/reference/waitable_timer_service/waitable_timer_service.html +/doc/asio/reference/waitable_timer_service/wait.html +/doc/asio/reference/WaitHandler.html +/doc/asio/reference/wait_traits/ +/doc/asio/reference/wait_traits.html +/doc/asio/reference/WaitTraits.html +/doc/asio/reference/wait_traits/to_wait_duration.html +/doc/asio/reference/windows__basic_handle/ +/doc/asio/reference/windows__basic_handle/assign/ +/doc/asio/reference/windows__basic_handle/assign.html +/doc/asio/reference/windows__basic_handle/assign/overload1.html +/doc/asio/reference/windows__basic_handle/assign/overload2.html +/doc/asio/reference/windows__basic_handle/basic_handle/ +/doc/asio/reference/windows__basic_handle/_basic_handle.html +/doc/asio/reference/windows__basic_handle/basic_handle.html +/doc/asio/reference/windows__basic_handle/basic_handle/overload1.html +/doc/asio/reference/windows__basic_handle/basic_handle/overload2.html +/doc/asio/reference/windows__basic_handle/basic_handle/overload3.html +/doc/asio/reference/windows__basic_handle/cancel/ +/doc/asio/reference/windows__basic_handle/cancel.html +/doc/asio/reference/windows__basic_handle/cancel/overload1.html +/doc/asio/reference/windows__basic_handle/cancel/overload2.html +/doc/asio/reference/windows__basic_handle/close/ +/doc/asio/reference/windows__basic_handle/close.html +/doc/asio/reference/windows__basic_handle/close/overload1.html +/doc/asio/reference/windows__basic_handle/close/overload2.html +/doc/asio/reference/windows__basic_handle/get_implementation/ +/doc/asio/reference/windows__basic_handle/get_implementation.html +/doc/asio/reference/windows__basic_handle/get_implementation/overload1.html +/doc/asio/reference/windows__basic_handle/get_implementation/overload2.html +/doc/asio/reference/windows__basic_handle/get_io_service.html +/doc/asio/reference/windows__basic_handle/get_service/ +/doc/asio/reference/windows__basic_handle/get_service.html +/doc/asio/reference/windows__basic_handle/get_service/overload1.html +/doc/asio/reference/windows__basic_handle/get_service/overload2.html +/doc/asio/reference/windows__basic_handle.html +/doc/asio/reference/windows__basic_handle/implementation.html +/doc/asio/reference/windows__basic_handle/implementation_type.html +/doc/asio/reference/windows__basic_handle/is_open.html +/doc/asio/reference/windows__basic_handle/lowest_layer/ +/doc/asio/reference/windows__basic_handle/lowest_layer.html +/doc/asio/reference/windows__basic_handle/lowest_layer/overload1.html +/doc/asio/reference/windows__basic_handle/lowest_layer/overload2.html +/doc/asio/reference/windows__basic_handle/lowest_layer_type.html +/doc/asio/reference/windows__basic_handle/native_handle.html +/doc/asio/reference/windows__basic_handle/native_handle_type.html +/doc/asio/reference/windows__basic_handle/native.html +/doc/asio/reference/windows__basic_handle/native_type.html +/doc/asio/reference/windows__basic_handle/operator_eq_.html +/doc/asio/reference/windows__basic_handle/service.html +/doc/asio/reference/windows__basic_handle/service_type.html +/doc/asio/reference/windows__basic_object_handle/ +/doc/asio/reference/windows__basic_object_handle/assign/ +/doc/asio/reference/windows__basic_object_handle/assign.html +/doc/asio/reference/windows__basic_object_handle/assign/overload1.html +/doc/asio/reference/windows__basic_object_handle/assign/overload2.html +/doc/asio/reference/windows__basic_object_handle/async_wait.html +/doc/asio/reference/windows__basic_object_handle/basic_object_handle/ +/doc/asio/reference/windows__basic_object_handle/basic_object_handle.html +/doc/asio/reference/windows__basic_object_handle/basic_object_handle/overload1.html +/doc/asio/reference/windows__basic_object_handle/basic_object_handle/overload2.html +/doc/asio/reference/windows__basic_object_handle/basic_object_handle/overload3.html +/doc/asio/reference/windows__basic_object_handle/cancel/ +/doc/asio/reference/windows__basic_object_handle/cancel.html +/doc/asio/reference/windows__basic_object_handle/cancel/overload1.html +/doc/asio/reference/windows__basic_object_handle/cancel/overload2.html +/doc/asio/reference/windows__basic_object_handle/close/ +/doc/asio/reference/windows__basic_object_handle/close.html +/doc/asio/reference/windows__basic_object_handle/close/overload1.html +/doc/asio/reference/windows__basic_object_handle/close/overload2.html +/doc/asio/reference/windows__basic_object_handle/get_implementation/ +/doc/asio/reference/windows__basic_object_handle/get_implementation.html +/doc/asio/reference/windows__basic_object_handle/get_implementation/overload1.html +/doc/asio/reference/windows__basic_object_handle/get_implementation/overload2.html +/doc/asio/reference/windows__basic_object_handle/get_io_service.html +/doc/asio/reference/windows__basic_object_handle/get_service/ +/doc/asio/reference/windows__basic_object_handle/get_service.html +/doc/asio/reference/windows__basic_object_handle/get_service/overload1.html +/doc/asio/reference/windows__basic_object_handle/get_service/overload2.html +/doc/asio/reference/windows__basic_object_handle.html +/doc/asio/reference/windows__basic_object_handle/implementation.html +/doc/asio/reference/windows__basic_object_handle/implementation_type.html +/doc/asio/reference/windows__basic_object_handle/is_open.html +/doc/asio/reference/windows__basic_object_handle/lowest_layer/ +/doc/asio/reference/windows__basic_object_handle/lowest_layer.html +/doc/asio/reference/windows__basic_object_handle/lowest_layer/overload1.html +/doc/asio/reference/windows__basic_object_handle/lowest_layer/overload2.html +/doc/asio/reference/windows__basic_object_handle/lowest_layer_type.html +/doc/asio/reference/windows__basic_object_handle/native_handle.html +/doc/asio/reference/windows__basic_object_handle/native_handle_type.html +/doc/asio/reference/windows__basic_object_handle/native.html +/doc/asio/reference/windows__basic_object_handle/native_type.html +/doc/asio/reference/windows__basic_object_handle/operator_eq_.html +/doc/asio/reference/windows__basic_object_handle/service.html +/doc/asio/reference/windows__basic_object_handle/service_type.html +/doc/asio/reference/windows__basic_object_handle/wait/ +/doc/asio/reference/windows__basic_object_handle/wait.html +/doc/asio/reference/windows__basic_object_handle/wait/overload1.html +/doc/asio/reference/windows__basic_object_handle/wait/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/ +/doc/asio/reference/windows__basic_random_access_handle/assign/ +/doc/asio/reference/windows__basic_random_access_handle/assign.html +/doc/asio/reference/windows__basic_random_access_handle/assign/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/assign/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/async_read_some_at.html +/doc/asio/reference/windows__basic_random_access_handle/async_write_some_at.html +/doc/asio/reference/windows__basic_random_access_handle/basic_random_access_handle/ +/doc/asio/reference/windows__basic_random_access_handle/basic_random_access_handle.html +/doc/asio/reference/windows__basic_random_access_handle/basic_random_access_handle/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/basic_random_access_handle/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/basic_random_access_handle/overload3.html +/doc/asio/reference/windows__basic_random_access_handle/cancel/ +/doc/asio/reference/windows__basic_random_access_handle/cancel.html +/doc/asio/reference/windows__basic_random_access_handle/cancel/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/cancel/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/close/ +/doc/asio/reference/windows__basic_random_access_handle/close.html +/doc/asio/reference/windows__basic_random_access_handle/close/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/close/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/get_implementation/ +/doc/asio/reference/windows__basic_random_access_handle/get_implementation.html +/doc/asio/reference/windows__basic_random_access_handle/get_implementation/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/get_implementation/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/get_io_service.html +/doc/asio/reference/windows__basic_random_access_handle/get_service/ +/doc/asio/reference/windows__basic_random_access_handle/get_service.html +/doc/asio/reference/windows__basic_random_access_handle/get_service/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/get_service/overload2.html +/doc/asio/reference/windows__basic_random_access_handle.html +/doc/asio/reference/windows__basic_random_access_handle/implementation.html +/doc/asio/reference/windows__basic_random_access_handle/implementation_type.html +/doc/asio/reference/windows__basic_random_access_handle/is_open.html +/doc/asio/reference/windows__basic_random_access_handle/lowest_layer/ +/doc/asio/reference/windows__basic_random_access_handle/lowest_layer.html +/doc/asio/reference/windows__basic_random_access_handle/lowest_layer/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/lowest_layer/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/lowest_layer_type.html +/doc/asio/reference/windows__basic_random_access_handle/native_handle.html +/doc/asio/reference/windows__basic_random_access_handle/native_handle_type.html +/doc/asio/reference/windows__basic_random_access_handle/native.html +/doc/asio/reference/windows__basic_random_access_handle/native_type.html +/doc/asio/reference/windows__basic_random_access_handle/operator_eq_.html +/doc/asio/reference/windows__basic_random_access_handle/read_some_at/ +/doc/asio/reference/windows__basic_random_access_handle/read_some_at.html +/doc/asio/reference/windows__basic_random_access_handle/read_some_at/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/read_some_at/overload2.html +/doc/asio/reference/windows__basic_random_access_handle/service.html +/doc/asio/reference/windows__basic_random_access_handle/service_type.html +/doc/asio/reference/windows__basic_random_access_handle/write_some_at/ +/doc/asio/reference/windows__basic_random_access_handle/write_some_at.html +/doc/asio/reference/windows__basic_random_access_handle/write_some_at/overload1.html +/doc/asio/reference/windows__basic_random_access_handle/write_some_at/overload2.html +/doc/asio/reference/windows__basic_stream_handle/ +/doc/asio/reference/windows__basic_stream_handle/assign/ +/doc/asio/reference/windows__basic_stream_handle/assign.html +/doc/asio/reference/windows__basic_stream_handle/assign/overload1.html +/doc/asio/reference/windows__basic_stream_handle/assign/overload2.html +/doc/asio/reference/windows__basic_stream_handle/async_read_some.html +/doc/asio/reference/windows__basic_stream_handle/async_write_some.html +/doc/asio/reference/windows__basic_stream_handle/basic_stream_handle/ +/doc/asio/reference/windows__basic_stream_handle/basic_stream_handle.html +/doc/asio/reference/windows__basic_stream_handle/basic_stream_handle/overload1.html +/doc/asio/reference/windows__basic_stream_handle/basic_stream_handle/overload2.html +/doc/asio/reference/windows__basic_stream_handle/basic_stream_handle/overload3.html +/doc/asio/reference/windows__basic_stream_handle/cancel/ +/doc/asio/reference/windows__basic_stream_handle/cancel.html +/doc/asio/reference/windows__basic_stream_handle/cancel/overload1.html +/doc/asio/reference/windows__basic_stream_handle/cancel/overload2.html +/doc/asio/reference/windows__basic_stream_handle/close/ +/doc/asio/reference/windows__basic_stream_handle/close.html +/doc/asio/reference/windows__basic_stream_handle/close/overload1.html +/doc/asio/reference/windows__basic_stream_handle/close/overload2.html +/doc/asio/reference/windows__basic_stream_handle/get_implementation/ +/doc/asio/reference/windows__basic_stream_handle/get_implementation.html +/doc/asio/reference/windows__basic_stream_handle/get_implementation/overload1.html +/doc/asio/reference/windows__basic_stream_handle/get_implementation/overload2.html +/doc/asio/reference/windows__basic_stream_handle/get_io_service.html +/doc/asio/reference/windows__basic_stream_handle/get_service/ +/doc/asio/reference/windows__basic_stream_handle/get_service.html +/doc/asio/reference/windows__basic_stream_handle/get_service/overload1.html +/doc/asio/reference/windows__basic_stream_handle/get_service/overload2.html +/doc/asio/reference/windows__basic_stream_handle.html +/doc/asio/reference/windows__basic_stream_handle/implementation.html +/doc/asio/reference/windows__basic_stream_handle/implementation_type.html +/doc/asio/reference/windows__basic_stream_handle/is_open.html +/doc/asio/reference/windows__basic_stream_handle/lowest_layer/ +/doc/asio/reference/windows__basic_stream_handle/lowest_layer.html +/doc/asio/reference/windows__basic_stream_handle/lowest_layer/overload1.html +/doc/asio/reference/windows__basic_stream_handle/lowest_layer/overload2.html +/doc/asio/reference/windows__basic_stream_handle/lowest_layer_type.html +/doc/asio/reference/windows__basic_stream_handle/native_handle.html +/doc/asio/reference/windows__basic_stream_handle/native_handle_type.html +/doc/asio/reference/windows__basic_stream_handle/native.html +/doc/asio/reference/windows__basic_stream_handle/native_type.html +/doc/asio/reference/windows__basic_stream_handle/operator_eq_.html +/doc/asio/reference/windows__basic_stream_handle/read_some/ +/doc/asio/reference/windows__basic_stream_handle/read_some.html +/doc/asio/reference/windows__basic_stream_handle/read_some/overload1.html +/doc/asio/reference/windows__basic_stream_handle/read_some/overload2.html +/doc/asio/reference/windows__basic_stream_handle/service.html +/doc/asio/reference/windows__basic_stream_handle/service_type.html +/doc/asio/reference/windows__basic_stream_handle/write_some/ +/doc/asio/reference/windows__basic_stream_handle/write_some.html +/doc/asio/reference/windows__basic_stream_handle/write_some/overload1.html +/doc/asio/reference/windows__basic_stream_handle/write_some/overload2.html +/doc/asio/reference/windows__object_handle.html +/doc/asio/reference/windows__object_handle_service/ +/doc/asio/reference/windows__object_handle_service/assign.html +/doc/asio/reference/windows__object_handle_service/async_wait.html +/doc/asio/reference/windows__object_handle_service/cancel.html +/doc/asio/reference/windows__object_handle_service/close.html +/doc/asio/reference/windows__object_handle_service/construct.html +/doc/asio/reference/windows__object_handle_service/destroy.html +/doc/asio/reference/windows__object_handle_service/get_io_service.html +/doc/asio/reference/windows__object_handle_service.html +/doc/asio/reference/windows__object_handle_service/id.html +/doc/asio/reference/windows__object_handle_service/implementation_type.html +/doc/asio/reference/windows__object_handle_service/is_open.html +/doc/asio/reference/windows__object_handle_service/move_assign.html +/doc/asio/reference/windows__object_handle_service/move_construct.html +/doc/asio/reference/windows__object_handle_service/native_handle.html +/doc/asio/reference/windows__object_handle_service/native_handle_type.html +/doc/asio/reference/windows__object_handle_service/object_handle_service.html +/doc/asio/reference/windows__object_handle_service/wait.html +/doc/asio/reference/windows__overlapped_ptr/ +/doc/asio/reference/windows__overlapped_ptr/complete.html +/doc/asio/reference/windows__overlapped_ptr/get/ +/doc/asio/reference/windows__overlapped_ptr/get.html +/doc/asio/reference/windows__overlapped_ptr/get/overload1.html +/doc/asio/reference/windows__overlapped_ptr/get/overload2.html +/doc/asio/reference/windows__overlapped_ptr.html +/doc/asio/reference/windows__overlapped_ptr/overlapped_ptr/ +/doc/asio/reference/windows__overlapped_ptr/_overlapped_ptr.html +/doc/asio/reference/windows__overlapped_ptr/overlapped_ptr.html +/doc/asio/reference/windows__overlapped_ptr/overlapped_ptr/overload1.html +/doc/asio/reference/windows__overlapped_ptr/overlapped_ptr/overload2.html +/doc/asio/reference/windows__overlapped_ptr/release.html +/doc/asio/reference/windows__overlapped_ptr/reset/ +/doc/asio/reference/windows__overlapped_ptr/reset.html +/doc/asio/reference/windows__overlapped_ptr/reset/overload1.html +/doc/asio/reference/windows__overlapped_ptr/reset/overload2.html +/doc/asio/reference/windows__random_access_handle.html +/doc/asio/reference/windows__random_access_handle_service/ +/doc/asio/reference/windows__random_access_handle_service/assign.html +/doc/asio/reference/windows__random_access_handle_service/async_read_some_at.html +/doc/asio/reference/windows__random_access_handle_service/async_write_some_at.html +/doc/asio/reference/windows__random_access_handle_service/cancel.html +/doc/asio/reference/windows__random_access_handle_service/close.html +/doc/asio/reference/windows__random_access_handle_service/construct.html +/doc/asio/reference/windows__random_access_handle_service/destroy.html +/doc/asio/reference/windows__random_access_handle_service/get_io_service.html +/doc/asio/reference/windows__random_access_handle_service.html +/doc/asio/reference/windows__random_access_handle_service/id.html +/doc/asio/reference/windows__random_access_handle_service/implementation_type.html +/doc/asio/reference/windows__random_access_handle_service/is_open.html +/doc/asio/reference/windows__random_access_handle_service/move_assign.html +/doc/asio/reference/windows__random_access_handle_service/move_construct.html +/doc/asio/reference/windows__random_access_handle_service/native_handle.html +/doc/asio/reference/windows__random_access_handle_service/native_handle_type.html +/doc/asio/reference/windows__random_access_handle_service/native.html +/doc/asio/reference/windows__random_access_handle_service/native_type.html +/doc/asio/reference/windows__random_access_handle_service/random_access_handle_service.html +/doc/asio/reference/windows__random_access_handle_service/read_some_at.html +/doc/asio/reference/windows__random_access_handle_service/write_some_at.html +/doc/asio/reference/windows__stream_handle.html +/doc/asio/reference/windows__stream_handle_service/ +/doc/asio/reference/windows__stream_handle_service/assign.html +/doc/asio/reference/windows__stream_handle_service/async_read_some.html +/doc/asio/reference/windows__stream_handle_service/async_write_some.html +/doc/asio/reference/windows__stream_handle_service/cancel.html +/doc/asio/reference/windows__stream_handle_service/close.html +/doc/asio/reference/windows__stream_handle_service/construct.html +/doc/asio/reference/windows__stream_handle_service/destroy.html +/doc/asio/reference/windows__stream_handle_service/get_io_service.html +/doc/asio/reference/windows__stream_handle_service.html +/doc/asio/reference/windows__stream_handle_service/id.html +/doc/asio/reference/windows__stream_handle_service/implementation_type.html +/doc/asio/reference/windows__stream_handle_service/is_open.html +/doc/asio/reference/windows__stream_handle_service/move_assign.html +/doc/asio/reference/windows__stream_handle_service/move_construct.html +/doc/asio/reference/windows__stream_handle_service/native_handle.html +/doc/asio/reference/windows__stream_handle_service/native_handle_type.html +/doc/asio/reference/windows__stream_handle_service/native.html +/doc/asio/reference/windows__stream_handle_service/native_type.html +/doc/asio/reference/windows__stream_handle_service/read_some.html +/doc/asio/reference/windows__stream_handle_service/stream_handle_service.html +/doc/asio/reference/windows__stream_handle_service/write_some.html +/doc/asio/reference/write/ +/doc/asio/reference/write_at/ +/doc/asio/reference/write_at.html +/doc/asio/reference/write_at/overload1.html +/doc/asio/reference/write_at/overload2.html +/doc/asio/reference/write_at/overload3.html +/doc/asio/reference/write_at/overload4.html +/doc/asio/reference/write_at/overload5.html +/doc/asio/reference/write_at/overload6.html +/doc/asio/reference/write_at/overload7.html +/doc/asio/reference/write_at/overload8.html +/doc/asio/reference/WriteHandler.html +/doc/asio/reference/write.html +/doc/asio/reference/write/overload1.html +/doc/asio/reference/write/overload2.html +/doc/asio/reference/write/overload3.html +/doc/asio/reference/write/overload4.html +/doc/asio/reference/write/overload5.html +/doc/asio/reference/write/overload6.html +/doc/asio/reference/write/overload7.html +/doc/asio/reference/write/overload8.html +/doc/asio/reference/yield_context.html +/doc/asio/tutorial/ +/doc/asio/tutorial/boost_bind.html +/doc/asio/tutorial.html +/doc/asio/tutorial/tutdaytime1/ +/doc/asio/tutorial/tutdaytime1.html +/doc/asio/tutorial/tutdaytime1/src.html +/doc/asio/tutorial/tutdaytime2/ +/doc/asio/tutorial/tutdaytime2.html +/doc/asio/tutorial/tutdaytime2/src.html +/doc/asio/tutorial/tutdaytime3/ +/doc/asio/tutorial/tutdaytime3.html +/doc/asio/tutorial/tutdaytime3/src.html +/doc/asio/tutorial/tutdaytime4/ +/doc/asio/tutorial/tutdaytime4.html +/doc/asio/tutorial/tutdaytime4/src.html +/doc/asio/tutorial/tutdaytime5/ +/doc/asio/tutorial/tutdaytime5.html +/doc/asio/tutorial/tutdaytime5/src.html +/doc/asio/tutorial/tutdaytime6/ +/doc/asio/tutorial/tutdaytime6.html +/doc/asio/tutorial/tutdaytime6/src.html +/doc/asio/tutorial/tutdaytime7/ +/doc/asio/tutorial/tutdaytime7.html +/doc/asio/tutorial/tutdaytime7/src.html +/doc/asio/tutorial/tuttimer1/ +/doc/asio/tutorial/tuttimer1.html +/doc/asio/tutorial/tuttimer1/src.html +/doc/asio/tutorial/tuttimer2/ +/doc/asio/tutorial/tuttimer2.html +/doc/asio/tutorial/tuttimer2/src.html +/doc/asio/tutorial/tuttimer3/ +/doc/asio/tutorial/tuttimer3.html +/doc/asio/tutorial/tuttimer3/src.html +/doc/asio/tutorial/tuttimer4/ +/doc/asio/tutorial/tuttimer4.html +/doc/asio/tutorial/tuttimer4/src.html +/doc/asio/tutorial/tuttimer5/ +/doc/asio/tutorial/tuttimer5.html +/doc/asio/tutorial/tuttimer5/src.html +/doc/asio/using.html +/doc/async_op1.png +/doc/async_op2.png +/doc/blank.png +/doc/boostbook.css +/doc/caution.png +/doc/draft.png +/doc/examples/ +/doc/examples/diffs/ +/doc/examples/diffs/allocation/ +/doc/examples/diffs/allocation/server.cpp.html +/doc/examples/diffs/buffers/ +/doc/examples/diffs/buffers/reference_counted.cpp.html +/doc/examples/diffs/chat/ +/doc/examples/diffs/chat/chat_client.cpp.html +/doc/examples/diffs/chat/chat_message.hpp.html +/doc/examples/diffs/chat/chat_server.cpp.html +/doc/examples/diffs/echo/ +/doc/examples/diffs/echo/async_tcp_echo_server.cpp.html +/doc/examples/diffs/echo/async_udp_echo_server.cpp.html +/doc/examples/diffs/echo/blocking_tcp_echo_client.cpp.html +/doc/examples/diffs/echo/blocking_tcp_echo_server.cpp.html +/doc/examples/diffs/echo/blocking_udp_echo_client.cpp.html +/doc/examples/diffs/echo/blocking_udp_echo_server.cpp.html +/doc/examples/diffs/futures/ +/doc/examples/diffs/futures/daytime_client.cpp.html +/doc/examples/diffs/http/ +/doc/examples/diffs/http/server/ +/doc/examples/diffs/http/server/connection.cpp.html +/doc/examples/diffs/http/server/connection.hpp.html +/doc/examples/diffs/http/server/connection_manager.cpp.html +/doc/examples/diffs/http/server/connection_manager.hpp.html +/doc/examples/diffs/http/server/header.hpp.html +/doc/examples/diffs/http/server/main.cpp.html +/doc/examples/diffs/http/server/mime_types.cpp.html +/doc/examples/diffs/http/server/mime_types.hpp.html +/doc/examples/diffs/http/server/reply.cpp.html +/doc/examples/diffs/http/server/reply.hpp.html +/doc/examples/diffs/http/server/request_handler.cpp.html +/doc/examples/diffs/http/server/request_handler.hpp.html +/doc/examples/diffs/http/server/request.hpp.html +/doc/examples/diffs/http/server/request_parser.cpp.html +/doc/examples/diffs/http/server/request_parser.hpp.html +/doc/examples/diffs/http/server/server.cpp.html +/doc/examples/diffs/http/server/server.hpp.html +/doc/examples/diffs/spawn/ +/doc/examples/diffs/spawn/echo_server.cpp.html +/doc/home.png +/doc/important.png +/doc/index.html +/doc/next_disabled.png +/doc/next.png +/doc/note.png +/doc/prev_disabled.png +/doc/prev.png +/doc/proactor.png +/doc/standalone_HTML.manifest +/doc/sync_op.png +/doc/tip.png +/doc/up_disabled.png +/doc/up.png +/doc/warning.png +/include/ +/include/asio/ +/include/asio/async_result.hpp +/include/asio/basic_datagram_socket.hpp +/include/asio/basic_deadline_timer.hpp +/include/asio/basic_io_object.hpp +/include/asio/basic_raw_socket.hpp +/include/asio/basic_seq_packet_socket.hpp +/include/asio/basic_serial_port.hpp +/include/asio/basic_signal_set.hpp +/include/asio/basic_socket_acceptor.hpp +/include/asio/basic_socket.hpp +/include/asio/basic_socket_iostream.hpp +/include/asio/basic_socket_streambuf.hpp +/include/asio/basic_streambuf_fwd.hpp +/include/asio/basic_streambuf.hpp +/include/asio/basic_stream_socket.hpp +/include/asio/basic_waitable_timer.hpp +/include/asio/buffered_read_stream_fwd.hpp +/include/asio/buffered_read_stream.hpp +/include/asio/buffered_stream_fwd.hpp +/include/asio/buffered_stream.hpp +/include/asio/buffered_write_stream_fwd.hpp +/include/asio/buffered_write_stream.hpp +/include/asio/buffer.hpp +/include/asio/buffers_iterator.hpp +/include/asio/completion_condition.hpp +/include/asio/connect.hpp +/include/asio/coroutine.hpp +/include/asio/datagram_socket_service.hpp +/include/asio/deadline_timer.hpp +/include/asio/deadline_timer_service.hpp +/include/asio/detail/ +/include/asio/detail/addressof.hpp +/include/asio/detail/array_fwd.hpp +/include/asio/detail/array.hpp +/include/asio/detail/assert.hpp +/include/asio/detail/atomic_count.hpp +/include/asio/detail/base_from_completion_cond.hpp +/include/asio/detail/bind_handler.hpp +/include/asio/detail/buffered_stream_storage.hpp +/include/asio/detail/buffer_resize_guard.hpp +/include/asio/detail/buffer_sequence_adapter.hpp +/include/asio/detail/call_stack.hpp +/include/asio/detail/chrono_time_traits.hpp +/include/asio/detail/completion_handler.hpp +/include/asio/detail/config.hpp +/include/asio/detail/consuming_buffers.hpp +/include/asio/detail/cstdint.hpp +/include/asio/detail/date_time_fwd.hpp +/include/asio/detail/deadline_timer_service.hpp +/include/asio/detail/dependent_type.hpp +/include/asio/detail/descriptor_ops.hpp +/include/asio/detail/descriptor_read_op.hpp +/include/asio/detail/descriptor_write_op.hpp +/include/asio/detail/dev_poll_reactor.hpp +/include/asio/detail/epoll_reactor.hpp +/include/asio/detail/eventfd_select_interrupter.hpp +/include/asio/detail/event.hpp +/include/asio/detail/fd_set_adapter.hpp +/include/asio/detail/fenced_block.hpp +/include/asio/detail/function.hpp +/include/asio/detail/gcc_arm_fenced_block.hpp +/include/asio/detail/gcc_hppa_fenced_block.hpp +/include/asio/detail/gcc_sync_fenced_block.hpp +/include/asio/detail/gcc_x86_fenced_block.hpp +/include/asio/detail/handler_alloc_helpers.hpp +/include/asio/detail/handler_cont_helpers.hpp +/include/asio/detail/handler_invoke_helpers.hpp +/include/asio/detail/handler_tracking.hpp +/include/asio/detail/handler_type_requirements.hpp +/include/asio/detail/hash_map.hpp +/include/asio/detail/impl/ +/include/asio/detail/impl/buffer_sequence_adapter.ipp +/include/asio/detail/impl/descriptor_ops.ipp +/include/asio/detail/impl/dev_poll_reactor.hpp +/include/asio/detail/impl/dev_poll_reactor.ipp +/include/asio/detail/impl/epoll_reactor.hpp +/include/asio/detail/impl/epoll_reactor.ipp +/include/asio/detail/impl/eventfd_select_interrupter.ipp +/include/asio/detail/impl/handler_tracking.ipp +/include/asio/detail/impl/kqueue_reactor.hpp +/include/asio/detail/impl/kqueue_reactor.ipp +/include/asio/detail/impl/pipe_select_interrupter.ipp +/include/asio/detail/impl/posix_event.ipp +/include/asio/detail/impl/posix_mutex.ipp +/include/asio/detail/impl/posix_thread.ipp +/include/asio/detail/impl/posix_tss_ptr.ipp +/include/asio/detail/impl/reactive_descriptor_service.ipp +/include/asio/detail/impl/reactive_serial_port_service.ipp +/include/asio/detail/impl/reactive_socket_service_base.ipp +/include/asio/detail/impl/resolver_service_base.ipp +/include/asio/detail/impl/select_reactor.hpp +/include/asio/detail/impl/select_reactor.ipp +/include/asio/detail/impl/service_registry.hpp +/include/asio/detail/impl/service_registry.ipp +/include/asio/detail/impl/signal_set_service.ipp +/include/asio/detail/impl/socket_ops.ipp +/include/asio/detail/impl/socket_select_interrupter.ipp +/include/asio/detail/impl/strand_service.hpp +/include/asio/detail/impl/strand_service.ipp +/include/asio/detail/impl/task_io_service.hpp +/include/asio/detail/impl/task_io_service.ipp +/include/asio/detail/impl/throw_error.ipp +/include/asio/detail/impl/timer_queue_ptime.ipp +/include/asio/detail/impl/timer_queue_set.ipp +/include/asio/detail/impl/win_event.ipp +/include/asio/detail/impl/win_iocp_handle_service.ipp +/include/asio/detail/impl/win_iocp_io_service.hpp +/include/asio/detail/impl/win_iocp_io_service.ipp +/include/asio/detail/impl/win_iocp_serial_port_service.ipp +/include/asio/detail/impl/win_iocp_socket_service_base.ipp +/include/asio/detail/impl/win_mutex.ipp +/include/asio/detail/impl/win_object_handle_service.ipp +/include/asio/detail/impl/winrt_ssocket_service_base.ipp +/include/asio/detail/impl/winrt_timer_scheduler.hpp +/include/asio/detail/impl/winrt_timer_scheduler.ipp +/include/asio/detail/impl/winsock_init.ipp +/include/asio/detail/impl/win_static_mutex.ipp +/include/asio/detail/impl/win_thread.ipp +/include/asio/detail/impl/win_tss_ptr.ipp +/include/asio/detail/io_control.hpp +/include/asio/detail/keyword_tss_ptr.hpp +/include/asio/detail/kqueue_reactor.hpp +/include/asio/detail/limits.hpp +/include/asio/detail/local_free_on_block_exit.hpp +/include/asio/detail/macos_fenced_block.hpp +/include/asio/detail/mutex.hpp +/include/asio/detail/noncopyable.hpp +/include/asio/detail/null_event.hpp +/include/asio/detail/null_fenced_block.hpp +/include/asio/detail/null_mutex.hpp +/include/asio/detail/null_reactor.hpp +/include/asio/detail/null_signal_blocker.hpp +/include/asio/detail/null_socket_service.hpp +/include/asio/detail/null_static_mutex.hpp +/include/asio/detail/null_thread.hpp +/include/asio/detail/null_tss_ptr.hpp +/include/asio/detail/object_pool.hpp +/include/asio/detail/old_win_sdk_compat.hpp +/include/asio/detail/operation.hpp +/include/asio/detail/op_queue.hpp +/include/asio/detail/pipe_select_interrupter.hpp +/include/asio/detail/pop_options.hpp +/include/asio/detail/posix_event.hpp +/include/asio/detail/posix_fd_set_adapter.hpp +/include/asio/detail/posix_mutex.hpp +/include/asio/detail/posix_signal_blocker.hpp +/include/asio/detail/posix_static_mutex.hpp +/include/asio/detail/posix_thread.hpp +/include/asio/detail/posix_tss_ptr.hpp +/include/asio/detail/push_options.hpp +/include/asio/detail/reactive_descriptor_service.hpp +/include/asio/detail/reactive_null_buffers_op.hpp +/include/asio/detail/reactive_serial_port_service.hpp +/include/asio/detail/reactive_socket_accept_op.hpp +/include/asio/detail/reactive_socket_connect_op.hpp +/include/asio/detail/reactive_socket_recvfrom_op.hpp +/include/asio/detail/reactive_socket_recvmsg_op.hpp +/include/asio/detail/reactive_socket_recv_op.hpp +/include/asio/detail/reactive_socket_send_op.hpp +/include/asio/detail/reactive_socket_sendto_op.hpp +/include/asio/detail/reactive_socket_service_base.hpp +/include/asio/detail/reactive_socket_service.hpp +/include/asio/detail/reactor_fwd.hpp +/include/asio/detail/reactor.hpp +/include/asio/detail/reactor_op.hpp +/include/asio/detail/reactor_op_queue.hpp +/include/asio/detail/regex_fwd.hpp +/include/asio/detail/resolve_endpoint_op.hpp +/include/asio/detail/resolve_op.hpp +/include/asio/detail/resolver_service_base.hpp +/include/asio/detail/resolver_service.hpp +/include/asio/detail/scoped_lock.hpp +/include/asio/detail/scoped_ptr.hpp +/include/asio/detail/select_interrupter.hpp +/include/asio/detail/select_reactor.hpp +/include/asio/detail/service_registry.hpp +/include/asio/detail/shared_ptr.hpp +/include/asio/detail/signal_blocker.hpp +/include/asio/detail/signal_handler.hpp +/include/asio/detail/signal_init.hpp +/include/asio/detail/signal_op.hpp +/include/asio/detail/signal_set_service.hpp +/include/asio/detail/socket_holder.hpp +/include/asio/detail/socket_ops.hpp +/include/asio/detail/socket_option.hpp +/include/asio/detail/socket_select_interrupter.hpp +/include/asio/detail/socket_types.hpp +/include/asio/detail/solaris_fenced_block.hpp +/include/asio/detail/static_mutex.hpp +/include/asio/detail/std_event.hpp +/include/asio/detail/std_mutex.hpp +/include/asio/detail/std_static_mutex.hpp +/include/asio/detail/std_thread.hpp +/include/asio/detail/strand_service.hpp +/include/asio/detail/task_io_service.hpp +/include/asio/detail/task_io_service_operation.hpp +/include/asio/detail/task_io_service_thread_info.hpp +/include/asio/detail/thread.hpp +/include/asio/detail/thread_info_base.hpp +/include/asio/detail/throw_error.hpp +/include/asio/detail/throw_exception.hpp +/include/asio/detail/timer_queue_base.hpp +/include/asio/detail/timer_queue.hpp +/include/asio/detail/timer_queue_ptime.hpp +/include/asio/detail/timer_queue_set.hpp +/include/asio/detail/timer_scheduler_fwd.hpp +/include/asio/detail/timer_scheduler.hpp +/include/asio/detail/tss_ptr.hpp +/include/asio/detail/type_traits.hpp +/include/asio/detail/variadic_templates.hpp +/include/asio/detail/wait_handler.hpp +/include/asio/detail/wait_op.hpp +/include/asio/detail/weak_ptr.hpp +/include/asio/detail/winapi_thread.hpp +/include/asio/detail/win_event.hpp +/include/asio/detail/win_fd_set_adapter.hpp +/include/asio/detail/win_fenced_block.hpp +/include/asio/detail/win_iocp_handle_read_op.hpp +/include/asio/detail/win_iocp_handle_service.hpp +/include/asio/detail/win_iocp_handle_write_op.hpp +/include/asio/detail/win_iocp_io_service.hpp +/include/asio/detail/win_iocp_null_buffers_op.hpp +/include/asio/detail/win_iocp_operation.hpp +/include/asio/detail/win_iocp_overlapped_op.hpp +/include/asio/detail/win_iocp_overlapped_ptr.hpp +/include/asio/detail/win_iocp_serial_port_service.hpp +/include/asio/detail/win_iocp_socket_accept_op.hpp +/include/asio/detail/win_iocp_socket_connect_op.hpp +/include/asio/detail/win_iocp_socket_recvfrom_op.hpp +/include/asio/detail/win_iocp_socket_recvmsg_op.hpp +/include/asio/detail/win_iocp_socket_recv_op.hpp +/include/asio/detail/win_iocp_socket_send_op.hpp +/include/asio/detail/win_iocp_socket_service_base.hpp +/include/asio/detail/win_iocp_socket_service.hpp +/include/asio/detail/win_iocp_thread_info.hpp +/include/asio/detail/win_mutex.hpp +/include/asio/detail/win_object_handle_service.hpp +/include/asio/detail/winrt_async_manager.hpp +/include/asio/detail/winrt_async_op.hpp +/include/asio/detail/winrt_resolve_op.hpp +/include/asio/detail/winrt_resolver_service.hpp +/include/asio/detail/winrt_socket_connect_op.hpp +/include/asio/detail/winrt_socket_recv_op.hpp +/include/asio/detail/winrt_socket_send_op.hpp +/include/asio/detail/winrt_ssocket_service_base.hpp +/include/asio/detail/winrt_ssocket_service.hpp +/include/asio/detail/winrt_timer_scheduler.hpp +/include/asio/detail/winrt_utils.hpp +/include/asio/detail/winsock_init.hpp +/include/asio/detail/win_static_mutex.hpp +/include/asio/detail/win_thread.hpp +/include/asio/detail/win_tss_ptr.hpp +/include/asio/detail/wrapped_handler.hpp +/include/asio/error_code.hpp +/include/asio/error.hpp +/include/asio/generic/ +/include/asio/generic/basic_endpoint.hpp +/include/asio/generic/datagram_protocol.hpp +/include/asio/generic/detail/ +/include/asio/generic/detail/endpoint.hpp +/include/asio/generic/detail/impl/ +/include/asio/generic/detail/impl/endpoint.ipp +/include/asio/generic/raw_protocol.hpp +/include/asio/generic/seq_packet_protocol.hpp +/include/asio/generic/stream_protocol.hpp +/include/asio/handler_alloc_hook.hpp +/include/asio/handler_continuation_hook.hpp +/include/asio/handler_invoke_hook.hpp +/include/asio/handler_type.hpp +/include/asio/high_resolution_timer.hpp +/include/asio.hpp +/include/asio/impl/ +/include/asio/impl/buffered_read_stream.hpp +/include/asio/impl/buffered_write_stream.hpp +/include/asio/impl/connect.hpp +/include/asio/impl/error_code.ipp +/include/asio/impl/error.ipp +/include/asio/impl/handler_alloc_hook.ipp +/include/asio/impl/io_service.hpp +/include/asio/impl/io_service.ipp +/include/asio/impl/read_at.hpp +/include/asio/impl/read.hpp +/include/asio/impl/read_until.hpp +/include/asio/impl/serial_port_base.hpp +/include/asio/impl/serial_port_base.ipp +/include/asio/impl/spawn.hpp +/include/asio/impl/src.cpp +/include/asio/impl/src.hpp +/include/asio/impl/use_future.hpp +/include/asio/impl/write_at.hpp +/include/asio/impl/write.hpp +/include/asio/io_service.hpp +/include/asio/ip/ +/include/asio/ip/address.hpp +/include/asio/ip/address_v4.hpp +/include/asio/ip/address_v6.hpp +/include/asio/ip/basic_endpoint.hpp +/include/asio/ip/basic_resolver_entry.hpp +/include/asio/ip/basic_resolver.hpp +/include/asio/ip/basic_resolver_iterator.hpp +/include/asio/ip/basic_resolver_query.hpp +/include/asio/ip/detail/ +/include/asio/ip/detail/endpoint.hpp +/include/asio/ip/detail/impl/ +/include/asio/ip/detail/impl/endpoint.ipp +/include/asio/ip/detail/socket_option.hpp +/include/asio/ip/host_name.hpp +/include/asio/ip/icmp.hpp +/include/asio/ip/impl/ +/include/asio/ip/impl/address.hpp +/include/asio/ip/impl/address.ipp +/include/asio/ip/impl/address_v4.hpp +/include/asio/ip/impl/address_v4.ipp +/include/asio/ip/impl/address_v6.hpp +/include/asio/ip/impl/address_v6.ipp +/include/asio/ip/impl/basic_endpoint.hpp +/include/asio/ip/impl/host_name.ipp +/include/asio/ip/multicast.hpp +/include/asio/ip/resolver_query_base.hpp +/include/asio/ip/resolver_service.hpp +/include/asio/ip/tcp.hpp +/include/asio/ip/udp.hpp +/include/asio/ip/unicast.hpp +/include/asio/ip/v6_only.hpp +/include/asio/is_read_buffered.hpp +/include/asio/is_write_buffered.hpp +/include/asio/local/ +/include/asio/local/basic_endpoint.hpp +/include/asio/local/connect_pair.hpp +/include/asio/local/datagram_protocol.hpp +/include/asio/local/detail/ +/include/asio/local/detail/endpoint.hpp +/include/asio/local/detail/impl/ +/include/asio/local/detail/impl/endpoint.ipp +/include/asio/local/stream_protocol.hpp +/include/asio/placeholders.hpp +/include/asio/posix/ +/include/asio/posix/basic_descriptor.hpp +/include/asio/posix/basic_stream_descriptor.hpp +/include/asio/posix/descriptor_base.hpp +/include/asio/posix/stream_descriptor.hpp +/include/asio/posix/stream_descriptor_service.hpp +/include/asio/raw_socket_service.hpp +/include/asio/read_at.hpp +/include/asio/read.hpp +/include/asio/read_until.hpp +/include/asio/seq_packet_socket_service.hpp +/include/asio/serial_port_base.hpp +/include/asio/serial_port.hpp +/include/asio/serial_port_service.hpp +/include/asio/signal_set.hpp +/include/asio/signal_set_service.hpp +/include/asio/socket_acceptor_service.hpp +/include/asio/socket_base.hpp +/include/asio/spawn.hpp +/include/asio/ssl/ +/include/asio/ssl/basic_context.hpp +/include/asio/ssl/context_base.hpp +/include/asio/ssl/context.hpp +/include/asio/ssl/context_service.hpp +/include/asio/ssl/detail/ +/include/asio/ssl/detail/buffered_handshake_op.hpp +/include/asio/ssl/detail/engine.hpp +/include/asio/ssl/detail/handshake_op.hpp +/include/asio/ssl/detail/impl/ +/include/asio/ssl/detail/impl/engine.ipp +/include/asio/ssl/detail/impl/openssl_init.ipp +/include/asio/ssl/detail/io.hpp +/include/asio/ssl/detail/openssl_init.hpp +/include/asio/ssl/detail/openssl_types.hpp +/include/asio/ssl/detail/password_callback.hpp +/include/asio/ssl/detail/read_op.hpp +/include/asio/ssl/detail/shutdown_op.hpp +/include/asio/ssl/detail/stream_core.hpp +/include/asio/ssl/detail/verify_callback.hpp +/include/asio/ssl/detail/write_op.hpp +/include/asio/ssl/error.hpp +/include/asio/ssl.hpp +/include/asio/ssl/impl/ +/include/asio/ssl/impl/context.hpp +/include/asio/ssl/impl/context.ipp +/include/asio/ssl/impl/error.ipp +/include/asio/ssl/impl/rfc2818_verification.ipp +/include/asio/ssl/impl/src.hpp +/include/asio/ssl/old/ +/include/asio/ssl/old/basic_context.hpp +/include/asio/ssl/old/context_service.hpp +/include/asio/ssl/old/detail/ +/include/asio/ssl/old/detail/openssl_context_service.hpp +/include/asio/ssl/old/detail/openssl_operation.hpp +/include/asio/ssl/old/detail/openssl_stream_service.hpp +/include/asio/ssl/old/stream.hpp +/include/asio/ssl/old/stream_service.hpp +/include/asio/ssl/rfc2818_verification.hpp +/include/asio/ssl/stream_base.hpp +/include/asio/ssl/stream.hpp +/include/asio/ssl/stream_service.hpp +/include/asio/ssl/verify_context.hpp +/include/asio/ssl/verify_mode.hpp +/include/asio/steady_timer.hpp +/include/asio/strand.hpp +/include/asio/streambuf.hpp +/include/asio/stream_socket_service.hpp +/include/asio/system_error.hpp +/include/asio/system_timer.hpp +/include/asio/thread.hpp +/include/asio/time_traits.hpp +/include/asio/unyield.hpp +/include/asio/use_future.hpp +/include/asio/version.hpp +/include/asio/waitable_timer_service.hpp +/include/asio/wait_traits.hpp +/include/asio/windows/ +/include/asio/windows/basic_handle.hpp +/include/asio/windows/basic_object_handle.hpp +/include/asio/windows/basic_random_access_handle.hpp +/include/asio/windows/basic_stream_handle.hpp +/include/asio/windows/object_handle.hpp +/include/asio/windows/object_handle_service.hpp +/include/asio/windows/overlapped_ptr.hpp +/include/asio/windows/random_access_handle.hpp +/include/asio/windows/random_access_handle_service.hpp +/include/asio/windows/stream_handle.hpp +/include/asio/windows/stream_handle_service.hpp +/include/asio/write_at.hpp +/include/asio/write.hpp +/include/asio/yield.hpp +/include/Makefile.am +/include/Makefile.in +/INSTALL +/install-sh +/LICENSE_1_0.txt +/Makefile.am +/Makefile.in +/missing +/README +/src/ +/src/asio.cpp +/src/asio_ssl.cpp +/src/examples/ +/src/examples/cpp03/ +/src/examples/cpp03/allocation/ +/src/examples/cpp03/allocation/server.cpp +/src/examples/cpp03/buffers/ +/src/examples/cpp03/buffers/reference_counted.cpp +/src/examples/cpp03/chat/ +/src/examples/cpp03/chat/chat_client.cpp +/src/examples/cpp03/chat/chat_message.hpp +/src/examples/cpp03/chat/chat_server.cpp +/src/examples/cpp03/chat/posix_chat_client.cpp +/src/examples/cpp03/echo/ +/src/examples/cpp03/echo/async_tcp_echo_server.cpp +/src/examples/cpp03/echo/async_udp_echo_server.cpp +/src/examples/cpp03/echo/blocking_tcp_echo_client.cpp +/src/examples/cpp03/echo/blocking_tcp_echo_server.cpp +/src/examples/cpp03/echo/blocking_udp_echo_client.cpp +/src/examples/cpp03/echo/blocking_udp_echo_server.cpp +/src/examples/cpp03/fork/ +/src/examples/cpp03/fork/daemon.cpp +/src/examples/cpp03/fork/process_per_connection.cpp +/src/examples/cpp03/http/ +/src/examples/cpp03/http/client/ +/src/examples/cpp03/http/client/async_client.cpp +/src/examples/cpp03/http/client/sync_client.cpp +/src/examples/cpp03/http/server/ +/src/examples/cpp03/http/server2/ +/src/examples/cpp03/http/server2/connection.cpp +/src/examples/cpp03/http/server2/connection.hpp +/src/examples/cpp03/http/server2/header.hpp +/src/examples/cpp03/http/server2/io_service_pool.cpp +/src/examples/cpp03/http/server2/io_service_pool.hpp +/src/examples/cpp03/http/server2/main.cpp +/src/examples/cpp03/http/server2/mime_types.cpp +/src/examples/cpp03/http/server2/mime_types.hpp +/src/examples/cpp03/http/server2/reply.cpp +/src/examples/cpp03/http/server2/reply.hpp +/src/examples/cpp03/http/server2/request_handler.cpp +/src/examples/cpp03/http/server2/request_handler.hpp +/src/examples/cpp03/http/server2/request.hpp +/src/examples/cpp03/http/server2/request_parser.cpp +/src/examples/cpp03/http/server2/request_parser.hpp +/src/examples/cpp03/http/server2/server.cpp +/src/examples/cpp03/http/server2/server.hpp +/src/examples/cpp03/http/server3/ +/src/examples/cpp03/http/server3/connection.cpp +/src/examples/cpp03/http/server3/connection.hpp +/src/examples/cpp03/http/server3/header.hpp +/src/examples/cpp03/http/server3/main.cpp +/src/examples/cpp03/http/server3/mime_types.cpp +/src/examples/cpp03/http/server3/mime_types.hpp +/src/examples/cpp03/http/server3/reply.cpp +/src/examples/cpp03/http/server3/reply.hpp +/src/examples/cpp03/http/server3/request_handler.cpp +/src/examples/cpp03/http/server3/request_handler.hpp +/src/examples/cpp03/http/server3/request.hpp +/src/examples/cpp03/http/server3/request_parser.cpp +/src/examples/cpp03/http/server3/request_parser.hpp +/src/examples/cpp03/http/server3/server.cpp +/src/examples/cpp03/http/server3/server.hpp +/src/examples/cpp03/http/server4/ +/src/examples/cpp03/http/server4/file_handler.cpp +/src/examples/cpp03/http/server4/file_handler.hpp +/src/examples/cpp03/http/server4/header.hpp +/src/examples/cpp03/http/server4/main.cpp +/src/examples/cpp03/http/server4/mime_types.cpp +/src/examples/cpp03/http/server4/mime_types.hpp +/src/examples/cpp03/http/server4/reply.cpp +/src/examples/cpp03/http/server4/reply.hpp +/src/examples/cpp03/http/server4/request.hpp +/src/examples/cpp03/http/server4/request_parser.cpp +/src/examples/cpp03/http/server4/request_parser.hpp +/src/examples/cpp03/http/server4/server.cpp +/src/examples/cpp03/http/server4/server.hpp +/src/examples/cpp03/http/server/connection.cpp +/src/examples/cpp03/http/server/connection.hpp +/src/examples/cpp03/http/server/connection_manager.cpp +/src/examples/cpp03/http/server/connection_manager.hpp +/src/examples/cpp03/http/server/header.hpp +/src/examples/cpp03/http/server/main.cpp +/src/examples/cpp03/http/server/mime_types.cpp +/src/examples/cpp03/http/server/mime_types.hpp +/src/examples/cpp03/http/server/reply.cpp +/src/examples/cpp03/http/server/reply.hpp +/src/examples/cpp03/http/server/request_handler.cpp +/src/examples/cpp03/http/server/request_handler.hpp +/src/examples/cpp03/http/server/request.hpp +/src/examples/cpp03/http/server/request_parser.cpp +/src/examples/cpp03/http/server/request_parser.hpp +/src/examples/cpp03/http/server/server.cpp +/src/examples/cpp03/http/server/server.hpp +/src/examples/cpp03/icmp/ +/src/examples/cpp03/icmp/icmp_header.hpp +/src/examples/cpp03/icmp/ipv4_header.hpp +/src/examples/cpp03/icmp/ping.cpp +/src/examples/cpp03/invocation/ +/src/examples/cpp03/invocation/prioritised_handlers.cpp +/src/examples/cpp03/iostreams/ +/src/examples/cpp03/iostreams/daytime_client.cpp +/src/examples/cpp03/iostreams/daytime_server.cpp +/src/examples/cpp03/iostreams/http_client.cpp +/src/examples/cpp03/local/ +/src/examples/cpp03/local/connect_pair.cpp +/src/examples/cpp03/local/iostream_client.cpp +/src/examples/cpp03/local/stream_client.cpp +/src/examples/cpp03/local/stream_server.cpp +/src/examples/cpp03/Makefile.am +/src/examples/cpp03/Makefile.in +/src/examples/cpp03/multicast/ +/src/examples/cpp03/multicast/receiver.cpp +/src/examples/cpp03/multicast/sender.cpp +/src/examples/cpp03/nonblocking/ +/src/examples/cpp03/nonblocking/third_party_lib.cpp +/src/examples/cpp03/porthopper/ +/src/examples/cpp03/porthopper/client.cpp +/src/examples/cpp03/porthopper/protocol.hpp +/src/examples/cpp03/porthopper/server.cpp +/src/examples/cpp03/serialization/ +/src/examples/cpp03/serialization/client.cpp +/src/examples/cpp03/serialization/connection.hpp +/src/examples/cpp03/serialization/server.cpp +/src/examples/cpp03/serialization/stock.hpp +/src/examples/cpp03/services/ +/src/examples/cpp03/services/basic_logger.hpp +/src/examples/cpp03/services/daytime_client.cpp +/src/examples/cpp03/services/logger.hpp +/src/examples/cpp03/services/logger_service.cpp +/src/examples/cpp03/services/logger_service.hpp +/src/examples/cpp03/services/stream_socket_service.hpp +/src/examples/cpp03/socks4/ +/src/examples/cpp03/socks4/socks4.hpp +/src/examples/cpp03/socks4/sync_client.cpp +/src/examples/cpp03/spawn/ +/src/examples/cpp03/spawn/echo_server.cpp +/src/examples/cpp03/ssl/ +/src/examples/cpp03/ssl/ca.pem +/src/examples/cpp03/ssl/client.cpp +/src/examples/cpp03/ssl/dh2048.pem +/src/examples/cpp03/ssl/README +/src/examples/cpp03/ssl/server.cpp +/src/examples/cpp03/ssl/server.pem +/src/examples/cpp03/timeouts/ +/src/examples/cpp03/timeouts/async_tcp_client.cpp +/src/examples/cpp03/timeouts/blocking_tcp_client.cpp +/src/examples/cpp03/timeouts/blocking_udp_client.cpp +/src/examples/cpp03/timeouts/server.cpp +/src/examples/cpp03/timers/ +/src/examples/cpp03/timers/tick_count_timer.cpp +/src/examples/cpp03/timers/time_t_timer.cpp +/src/examples/cpp03/tutorial/ +/src/examples/cpp03/tutorial/daytime1/ +/src/examples/cpp03/tutorial/daytime1/client.cpp +/src/examples/cpp03/tutorial/daytime2/ +/src/examples/cpp03/tutorial/daytime2/server.cpp +/src/examples/cpp03/tutorial/daytime3/ +/src/examples/cpp03/tutorial/daytime3/server.cpp +/src/examples/cpp03/tutorial/daytime4/ +/src/examples/cpp03/tutorial/daytime4/client.cpp +/src/examples/cpp03/tutorial/daytime5/ +/src/examples/cpp03/tutorial/daytime5/server.cpp +/src/examples/cpp03/tutorial/daytime6/ +/src/examples/cpp03/tutorial/daytime6/server.cpp +/src/examples/cpp03/tutorial/daytime7/ +/src/examples/cpp03/tutorial/daytime7/server.cpp +/src/examples/cpp03/tutorial/timer1/ +/src/examples/cpp03/tutorial/timer1/timer.cpp +/src/examples/cpp03/tutorial/timer2/ +/src/examples/cpp03/tutorial/timer2/timer.cpp +/src/examples/cpp03/tutorial/timer3/ +/src/examples/cpp03/tutorial/timer3/timer.cpp +/src/examples/cpp03/tutorial/timer4/ +/src/examples/cpp03/tutorial/timer4/timer.cpp +/src/examples/cpp03/tutorial/timer5/ +/src/examples/cpp03/tutorial/timer5/timer.cpp +/src/examples/cpp03/windows/ +/src/examples/cpp03/windows/transmit_file.cpp +/src/examples/cpp11/ +/src/examples/cpp11/allocation/ +/src/examples/cpp11/allocation/server.cpp +/src/examples/cpp11/buffers/ +/src/examples/cpp11/buffers/reference_counted.cpp +/src/examples/cpp11/chat/ +/src/examples/cpp11/chat/chat_client.cpp +/src/examples/cpp11/chat/chat_message.hpp +/src/examples/cpp11/chat/chat_server.cpp +/src/examples/cpp11/echo/ +/src/examples/cpp11/echo/async_tcp_echo_server.cpp +/src/examples/cpp11/echo/async_udp_echo_server.cpp +/src/examples/cpp11/echo/blocking_tcp_echo_client.cpp +/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp +/src/examples/cpp11/echo/blocking_udp_echo_client.cpp +/src/examples/cpp11/echo/blocking_udp_echo_server.cpp +/src/examples/cpp11/futures/ +/src/examples/cpp11/futures/daytime_client.cpp +/src/examples/cpp11/http/ +/src/examples/cpp11/http/server/ +/src/examples/cpp11/http/server/connection.cpp +/src/examples/cpp11/http/server/connection.hpp +/src/examples/cpp11/http/server/connection_manager.cpp +/src/examples/cpp11/http/server/connection_manager.hpp +/src/examples/cpp11/http/server/header.hpp +/src/examples/cpp11/http/server/main.cpp +/src/examples/cpp11/http/server/mime_types.cpp +/src/examples/cpp11/http/server/mime_types.hpp +/src/examples/cpp11/http/server/reply.cpp +/src/examples/cpp11/http/server/reply.hpp +/src/examples/cpp11/http/server/request_handler.cpp +/src/examples/cpp11/http/server/request_handler.hpp +/src/examples/cpp11/http/server/request.hpp +/src/examples/cpp11/http/server/request_parser.cpp +/src/examples/cpp11/http/server/request_parser.hpp +/src/examples/cpp11/http/server/server.cpp +/src/examples/cpp11/http/server/server.hpp +/src/examples/cpp11/Makefile.am +/src/examples/cpp11/Makefile.in +/src/examples/cpp11/spawn/ +/src/examples/cpp11/spawn/echo_server.cpp +/src/Makefile.am +/src/Makefile.in +/src/Makefile.mgw +/src/Makefile.msc +/src/tests/ +/src/tests/latency/ +/src/tests/latency/allocator.hpp +/src/tests/latency/coroutine.hpp +/src/tests/latency/high_res_clock.hpp +/src/tests/latency/tcp_client.cpp +/src/tests/latency/tcp_server.cpp +/src/tests/latency/udp_client.cpp +/src/tests/latency/udp_server.cpp +/src/tests/latency/unyield.hpp +/src/tests/latency/yield.hpp +/src/tests/Makefile.am +/src/tests/Makefile.in +/src/tests/performance/ +/src/tests/performance/client.cpp +/src/tests/performance/handler_allocator.hpp +/src/tests/performance/server.cpp +/src/tests/unit/ +/src/tests/unit/archetypes/ +/src/tests/unit/archetypes/async_result.hpp +/src/tests/unit/archetypes/gettable_socket_option.hpp +/src/tests/unit/archetypes/io_control_command.hpp +/src/tests/unit/archetypes/settable_socket_option.hpp +/src/tests/unit/basic_datagram_socket.cpp +/src/tests/unit/basic_deadline_timer.cpp +/src/tests/unit/basic_raw_socket.cpp +/src/tests/unit/basic_seq_packet_socket.cpp +/src/tests/unit/basic_serial_port.cpp +/src/tests/unit/basic_signal_set.cpp +/src/tests/unit/basic_socket_acceptor.cpp +/src/tests/unit/basic_streambuf.cpp +/src/tests/unit/basic_stream_socket.cpp +/src/tests/unit/basic_waitable_timer.cpp +/src/tests/unit/buffer.cpp +/src/tests/unit/buffered_read_stream.cpp +/src/tests/unit/buffered_stream.cpp +/src/tests/unit/buffered_write_stream.cpp +/src/tests/unit/buffers_iterator.cpp +/src/tests/unit/completion_condition.cpp +/src/tests/unit/connect.cpp +/src/tests/unit/coroutine.cpp +/src/tests/unit/datagram_socket_service.cpp +/src/tests/unit/deadline_timer.cpp +/src/tests/unit/deadline_timer_service.cpp +/src/tests/unit/error.cpp +/src/tests/unit/generic/ +/src/tests/unit/generic/basic_endpoint.cpp +/src/tests/unit/generic/datagram_protocol.cpp +/src/tests/unit/generic/raw_protocol.cpp +/src/tests/unit/generic/seq_packet_protocol.cpp +/src/tests/unit/generic/stream_protocol.cpp +/src/tests/unit/high_resolution_timer.cpp +/src/tests/unit/io_service.cpp +/src/tests/unit/ip/ +/src/tests/unit/ip/address.cpp +/src/tests/unit/ip/address_v4.cpp +/src/tests/unit/ip/address_v6.cpp +/src/tests/unit/ip/basic_endpoint.cpp +/src/tests/unit/ip/basic_resolver.cpp +/src/tests/unit/ip/basic_resolver_entry.cpp +/src/tests/unit/ip/basic_resolver_iterator.cpp +/src/tests/unit/ip/basic_resolver_query.cpp +/src/tests/unit/ip/host_name.cpp +/src/tests/unit/ip/icmp.cpp +/src/tests/unit/ip/multicast.cpp +/src/tests/unit/ip/resolver_query_base.cpp +/src/tests/unit/ip/resolver_service.cpp +/src/tests/unit/ip/tcp.cpp +/src/tests/unit/ip/udp.cpp +/src/tests/unit/ip/unicast.cpp +/src/tests/unit/ip/v6_only.cpp +/src/tests/unit/is_read_buffered.cpp +/src/tests/unit/is_write_buffered.cpp +/src/tests/unit/local/ +/src/tests/unit/local/basic_endpoint.cpp +/src/tests/unit/local/connect_pair.cpp +/src/tests/unit/local/datagram_protocol.cpp +/src/tests/unit/local/stream_protocol.cpp +/src/tests/unit/placeholders.cpp +/src/tests/unit/posix/ +/src/tests/unit/posix/basic_descriptor.cpp +/src/tests/unit/posix/basic_stream_descriptor.cpp +/src/tests/unit/posix/descriptor_base.cpp +/src/tests/unit/posix/stream_descriptor.cpp +/src/tests/unit/posix/stream_descriptor_service.cpp +/src/tests/unit/raw_socket_service.cpp +/src/tests/unit/read_at.cpp +/src/tests/unit/read.cpp +/src/tests/unit/read_until.cpp +/src/tests/unit/seq_packet_socket_service.cpp +/src/tests/unit/serial_port_base.cpp +/src/tests/unit/serial_port.cpp +/src/tests/unit/serial_port_service.cpp +/src/tests/unit/signal_set.cpp +/src/tests/unit/signal_set_service.cpp +/src/tests/unit/socket_acceptor_service.cpp +/src/tests/unit/socket_base.cpp +/src/tests/unit/ssl/ +/src/tests/unit/ssl/basic_context.cpp +/src/tests/unit/ssl/context_base.cpp +/src/tests/unit/ssl/context.cpp +/src/tests/unit/ssl/context_service.cpp +/src/tests/unit/ssl/rfc2818_verification.cpp +/src/tests/unit/ssl/stream_base.cpp +/src/tests/unit/ssl/stream.cpp +/src/tests/unit/ssl/stream_service.cpp +/src/tests/unit/steady_timer.cpp +/src/tests/unit/strand.cpp +/src/tests/unit/streambuf.cpp +/src/tests/unit/stream_socket_service.cpp +/src/tests/unit/system_timer.cpp +/src/tests/unit/thread.cpp +/src/tests/unit/time_traits.cpp +/src/tests/unit/unit_test.hpp +/src/tests/unit/waitable_timer_service.cpp +/src/tests/unit/wait_traits.cpp +/src/tests/unit/windows/ +/src/tests/unit/windows/basic_handle.cpp +/src/tests/unit/windows/basic_object_handle.cpp +/src/tests/unit/windows/basic_random_access_handle.cpp +/src/tests/unit/windows/basic_stream_handle.cpp +/src/tests/unit/windows/object_handle.cpp +/src/tests/unit/windows/object_handle_service.cpp +/src/tests/unit/windows/overlapped_ptr.cpp +/src/tests/unit/windows/random_access_handle.cpp +/src/tests/unit/windows/random_access_handle_service.cpp +/src/tests/unit/windows/stream_handle.cpp +/src/tests/unit/windows/stream_handle_service.cpp +/src/tests/unit/write_at.cpp +/src/tests/unit/write.cpp +/src/tools/ +/src/tools/handlerviz.pl +/test-driver diff --git a/utils/dnp3_src/deps/asio/asio/autogen.sh b/utils/dnp3_src/deps/asio/asio/autogen.sh new file mode 100755 index 0000000..42075e3 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/autogen.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +# Helps bootstrapping the application when checked out from CVS. +# Requires GNU autoconf, GNU automake and GNU which. +# +# Copyright (C) 2004, by +# +# Carlo Wood, Run on IRC +# RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt +# Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61 +# + +# Do sanity checks. +# Directory check. +if [ ! -f autogen.sh ]; then + echo "Run ./autogen.sh from the directory it exists in." + exit 1 +fi + +AUTOMAKE=${AUTOMAKE:-automake} +ACLOCAL=${ACLOCAL:-aclocal} +AUTOCONF=${AUTOCONF:-autoconf} + +($AUTOCONF --version) >/dev/null 2>/dev/null || (echo "You need GNU autoconf to install from CVS (ftp://ftp.gnu.org/gnu/autoconf/)"; exit 1) || exit 1 +($AUTOMAKE --version) >/dev/null 2>/dev/null || (echo "You need GNU automake 1.7 or higher to install from CVS (ftp://ftp.gnu.org/gnu/automake/)"; exit 1) || exit 1 + +# Determine the version of automake. +automake_version=`$AUTOMAKE --version | head -n 1 | sed -e 's/[^12]*\([12]\.[0-9][^ ]*\).*/\1/'` +automake_major=`echo $automake_version | cut -f1 -d.` +automake_minor=`echo $automake_version | cut -f2 -d.` +automake_version_number=`expr "$automake_major" \* 1000 \+ "$automake_minor"` + +# Require automake 1.7. +if expr "1007" \> "$automake_version_number" >/dev/null; then + $AUTOMAKE --version | head -n 1 + echo "" + echo "Fatal error: automake 1.7 or higher is required. Please set \$AUTOMAKE" + echo "to point to a newer automake, or upgrade." + echo "" + exit 1 +fi + +run() +{ + echo "Running $1 ..." + $1 +} + +# This is needed when someone just upgraded automake and this cache is still generated by an old version. +rm -rf autom4te.cache config.cache + +run "$ACLOCAL" +run "$AUTOCONF" +run "$AUTOMAKE --add-missing --foreign" + diff --git a/utils/dnp3_src/deps/asio/asio/boost_asio.manifest b/utils/dnp3_src/deps/asio/asio/boost_asio.manifest new file mode 100644 index 0000000..92a353a --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/boost_asio.manifest @@ -0,0 +1,4661 @@ +/ +/boost/ +/boost/asio/ +/boost/asio/async_result.hpp +/boost/asio/basic_datagram_socket.hpp +/boost/asio/basic_deadline_timer.hpp +/boost/asio/basic_io_object.hpp +/boost/asio/basic_raw_socket.hpp +/boost/asio/basic_seq_packet_socket.hpp +/boost/asio/basic_serial_port.hpp +/boost/asio/basic_signal_set.hpp +/boost/asio/basic_socket_acceptor.hpp +/boost/asio/basic_socket.hpp +/boost/asio/basic_socket_iostream.hpp +/boost/asio/basic_socket_streambuf.hpp +/boost/asio/basic_streambuf_fwd.hpp +/boost/asio/basic_streambuf.hpp +/boost/asio/basic_stream_socket.hpp +/boost/asio/basic_waitable_timer.hpp +/boost/asio/buffered_read_stream_fwd.hpp +/boost/asio/buffered_read_stream.hpp +/boost/asio/buffered_stream_fwd.hpp +/boost/asio/buffered_stream.hpp +/boost/asio/buffered_write_stream_fwd.hpp +/boost/asio/buffered_write_stream.hpp +/boost/asio/buffer.hpp +/boost/asio/buffers_iterator.hpp +/boost/asio/completion_condition.hpp +/boost/asio/connect.hpp +/boost/asio/coroutine.hpp +/boost/asio/datagram_socket_service.hpp +/boost/asio/deadline_timer.hpp +/boost/asio/deadline_timer_service.hpp +/boost/asio/detail/ +/boost/asio/detail/addressof.hpp +/boost/asio/detail/array_fwd.hpp +/boost/asio/detail/array.hpp +/boost/asio/detail/assert.hpp +/boost/asio/detail/atomic_count.hpp +/boost/asio/detail/base_from_completion_cond.hpp +/boost/asio/detail/bind_handler.hpp +/boost/asio/detail/buffered_stream_storage.hpp +/boost/asio/detail/buffer_resize_guard.hpp +/boost/asio/detail/buffer_sequence_adapter.hpp +/boost/asio/detail/call_stack.hpp +/boost/asio/detail/chrono_time_traits.hpp +/boost/asio/detail/completion_handler.hpp +/boost/asio/detail/config.hpp +/boost/asio/detail/consuming_buffers.hpp +/boost/asio/detail/cstdint.hpp +/boost/asio/detail/date_time_fwd.hpp +/boost/asio/detail/deadline_timer_service.hpp +/boost/asio/detail/dependent_type.hpp +/boost/asio/detail/descriptor_ops.hpp +/boost/asio/detail/descriptor_read_op.hpp +/boost/asio/detail/descriptor_write_op.hpp +/boost/asio/detail/dev_poll_reactor.hpp +/boost/asio/detail/epoll_reactor.hpp +/boost/asio/detail/eventfd_select_interrupter.hpp +/boost/asio/detail/event.hpp +/boost/asio/detail/fd_set_adapter.hpp +/boost/asio/detail/fenced_block.hpp +/boost/asio/detail/function.hpp +/boost/asio/detail/gcc_arm_fenced_block.hpp +/boost/asio/detail/gcc_hppa_fenced_block.hpp +/boost/asio/detail/gcc_sync_fenced_block.hpp +/boost/asio/detail/gcc_x86_fenced_block.hpp +/boost/asio/detail/handler_alloc_helpers.hpp +/boost/asio/detail/handler_cont_helpers.hpp +/boost/asio/detail/handler_invoke_helpers.hpp +/boost/asio/detail/handler_tracking.hpp +/boost/asio/detail/handler_type_requirements.hpp +/boost/asio/detail/hash_map.hpp +/boost/asio/detail/impl/ +/boost/asio/detail/impl/buffer_sequence_adapter.ipp +/boost/asio/detail/impl/descriptor_ops.ipp +/boost/asio/detail/impl/dev_poll_reactor.hpp +/boost/asio/detail/impl/dev_poll_reactor.ipp +/boost/asio/detail/impl/epoll_reactor.hpp +/boost/asio/detail/impl/epoll_reactor.ipp +/boost/asio/detail/impl/eventfd_select_interrupter.ipp +/boost/asio/detail/impl/handler_tracking.ipp +/boost/asio/detail/impl/kqueue_reactor.hpp +/boost/asio/detail/impl/kqueue_reactor.ipp +/boost/asio/detail/impl/pipe_select_interrupter.ipp +/boost/asio/detail/impl/posix_event.ipp +/boost/asio/detail/impl/posix_mutex.ipp +/boost/asio/detail/impl/posix_thread.ipp +/boost/asio/detail/impl/posix_tss_ptr.ipp +/boost/asio/detail/impl/reactive_descriptor_service.ipp +/boost/asio/detail/impl/reactive_serial_port_service.ipp +/boost/asio/detail/impl/reactive_socket_service_base.ipp +/boost/asio/detail/impl/resolver_service_base.ipp +/boost/asio/detail/impl/select_reactor.hpp +/boost/asio/detail/impl/select_reactor.ipp +/boost/asio/detail/impl/service_registry.hpp +/boost/asio/detail/impl/service_registry.ipp +/boost/asio/detail/impl/signal_set_service.ipp +/boost/asio/detail/impl/socket_ops.ipp +/boost/asio/detail/impl/socket_select_interrupter.ipp +/boost/asio/detail/impl/strand_service.hpp +/boost/asio/detail/impl/strand_service.ipp +/boost/asio/detail/impl/task_io_service.hpp +/boost/asio/detail/impl/task_io_service.ipp +/boost/asio/detail/impl/throw_error.ipp +/boost/asio/detail/impl/timer_queue_ptime.ipp +/boost/asio/detail/impl/timer_queue_set.ipp +/boost/asio/detail/impl/win_event.ipp +/boost/asio/detail/impl/win_iocp_handle_service.ipp +/boost/asio/detail/impl/win_iocp_io_service.hpp +/boost/asio/detail/impl/win_iocp_io_service.ipp +/boost/asio/detail/impl/win_iocp_serial_port_service.ipp +/boost/asio/detail/impl/win_iocp_socket_service_base.ipp +/boost/asio/detail/impl/win_mutex.ipp +/boost/asio/detail/impl/win_object_handle_service.ipp +/boost/asio/detail/impl/winrt_ssocket_service_base.ipp +/boost/asio/detail/impl/winrt_timer_scheduler.hpp +/boost/asio/detail/impl/winrt_timer_scheduler.ipp +/boost/asio/detail/impl/winsock_init.ipp +/boost/asio/detail/impl/win_static_mutex.ipp +/boost/asio/detail/impl/win_thread.ipp +/boost/asio/detail/impl/win_tss_ptr.ipp +/boost/asio/detail/io_control.hpp +/boost/asio/detail/keyword_tss_ptr.hpp +/boost/asio/detail/kqueue_reactor.hpp +/boost/asio/detail/limits.hpp +/boost/asio/detail/local_free_on_block_exit.hpp +/boost/asio/detail/macos_fenced_block.hpp +/boost/asio/detail/mutex.hpp +/boost/asio/detail/noncopyable.hpp +/boost/asio/detail/null_event.hpp +/boost/asio/detail/null_fenced_block.hpp +/boost/asio/detail/null_mutex.hpp +/boost/asio/detail/null_reactor.hpp +/boost/asio/detail/null_signal_blocker.hpp +/boost/asio/detail/null_socket_service.hpp +/boost/asio/detail/null_static_mutex.hpp +/boost/asio/detail/null_thread.hpp +/boost/asio/detail/null_tss_ptr.hpp +/boost/asio/detail/object_pool.hpp +/boost/asio/detail/old_win_sdk_compat.hpp +/boost/asio/detail/operation.hpp +/boost/asio/detail/op_queue.hpp +/boost/asio/detail/pipe_select_interrupter.hpp +/boost/asio/detail/pop_options.hpp +/boost/asio/detail/posix_event.hpp +/boost/asio/detail/posix_fd_set_adapter.hpp +/boost/asio/detail/posix_mutex.hpp +/boost/asio/detail/posix_signal_blocker.hpp +/boost/asio/detail/posix_static_mutex.hpp +/boost/asio/detail/posix_thread.hpp +/boost/asio/detail/posix_tss_ptr.hpp +/boost/asio/detail/push_options.hpp +/boost/asio/detail/reactive_descriptor_service.hpp +/boost/asio/detail/reactive_null_buffers_op.hpp +/boost/asio/detail/reactive_serial_port_service.hpp +/boost/asio/detail/reactive_socket_accept_op.hpp +/boost/asio/detail/reactive_socket_connect_op.hpp +/boost/asio/detail/reactive_socket_recvfrom_op.hpp +/boost/asio/detail/reactive_socket_recvmsg_op.hpp +/boost/asio/detail/reactive_socket_recv_op.hpp +/boost/asio/detail/reactive_socket_send_op.hpp +/boost/asio/detail/reactive_socket_sendto_op.hpp +/boost/asio/detail/reactive_socket_service_base.hpp +/boost/asio/detail/reactive_socket_service.hpp +/boost/asio/detail/reactor_fwd.hpp +/boost/asio/detail/reactor.hpp +/boost/asio/detail/reactor_op.hpp +/boost/asio/detail/reactor_op_queue.hpp +/boost/asio/detail/regex_fwd.hpp +/boost/asio/detail/resolve_endpoint_op.hpp +/boost/asio/detail/resolve_op.hpp +/boost/asio/detail/resolver_service_base.hpp +/boost/asio/detail/resolver_service.hpp +/boost/asio/detail/scoped_lock.hpp +/boost/asio/detail/scoped_ptr.hpp +/boost/asio/detail/select_interrupter.hpp +/boost/asio/detail/select_reactor.hpp +/boost/asio/detail/service_registry.hpp +/boost/asio/detail/shared_ptr.hpp +/boost/asio/detail/signal_blocker.hpp +/boost/asio/detail/signal_handler.hpp +/boost/asio/detail/signal_init.hpp +/boost/asio/detail/signal_op.hpp +/boost/asio/detail/signal_set_service.hpp +/boost/asio/detail/socket_holder.hpp +/boost/asio/detail/socket_ops.hpp +/boost/asio/detail/socket_option.hpp +/boost/asio/detail/socket_select_interrupter.hpp +/boost/asio/detail/socket_types.hpp +/boost/asio/detail/solaris_fenced_block.hpp +/boost/asio/detail/static_mutex.hpp +/boost/asio/detail/std_event.hpp +/boost/asio/detail/std_mutex.hpp +/boost/asio/detail/std_static_mutex.hpp +/boost/asio/detail/std_thread.hpp +/boost/asio/detail/strand_service.hpp +/boost/asio/detail/task_io_service.hpp +/boost/asio/detail/task_io_service_operation.hpp +/boost/asio/detail/task_io_service_thread_info.hpp +/boost/asio/detail/thread.hpp +/boost/asio/detail/thread_info_base.hpp +/boost/asio/detail/throw_error.hpp +/boost/asio/detail/throw_exception.hpp +/boost/asio/detail/timer_queue_base.hpp +/boost/asio/detail/timer_queue.hpp +/boost/asio/detail/timer_queue_ptime.hpp +/boost/asio/detail/timer_queue_set.hpp +/boost/asio/detail/timer_scheduler_fwd.hpp +/boost/asio/detail/timer_scheduler.hpp +/boost/asio/detail/tss_ptr.hpp +/boost/asio/detail/type_traits.hpp +/boost/asio/detail/variadic_templates.hpp +/boost/asio/detail/wait_handler.hpp +/boost/asio/detail/wait_op.hpp +/boost/asio/detail/weak_ptr.hpp +/boost/asio/detail/winapi_thread.hpp +/boost/asio/detail/win_event.hpp +/boost/asio/detail/win_fd_set_adapter.hpp +/boost/asio/detail/win_fenced_block.hpp +/boost/asio/detail/win_iocp_handle_read_op.hpp +/boost/asio/detail/win_iocp_handle_service.hpp +/boost/asio/detail/win_iocp_handle_write_op.hpp +/boost/asio/detail/win_iocp_io_service.hpp +/boost/asio/detail/win_iocp_null_buffers_op.hpp +/boost/asio/detail/win_iocp_operation.hpp +/boost/asio/detail/win_iocp_overlapped_op.hpp +/boost/asio/detail/win_iocp_overlapped_ptr.hpp +/boost/asio/detail/win_iocp_serial_port_service.hpp +/boost/asio/detail/win_iocp_socket_accept_op.hpp +/boost/asio/detail/win_iocp_socket_connect_op.hpp +/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp +/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp +/boost/asio/detail/win_iocp_socket_recv_op.hpp +/boost/asio/detail/win_iocp_socket_send_op.hpp +/boost/asio/detail/win_iocp_socket_service_base.hpp +/boost/asio/detail/win_iocp_socket_service.hpp +/boost/asio/detail/win_iocp_thread_info.hpp +/boost/asio/detail/win_mutex.hpp +/boost/asio/detail/win_object_handle_service.hpp +/boost/asio/detail/winrt_async_manager.hpp +/boost/asio/detail/winrt_async_op.hpp +/boost/asio/detail/winrt_resolve_op.hpp +/boost/asio/detail/winrt_resolver_service.hpp +/boost/asio/detail/winrt_socket_connect_op.hpp +/boost/asio/detail/winrt_socket_recv_op.hpp +/boost/asio/detail/winrt_socket_send_op.hpp +/boost/asio/detail/winrt_ssocket_service_base.hpp +/boost/asio/detail/winrt_ssocket_service.hpp +/boost/asio/detail/winrt_timer_scheduler.hpp +/boost/asio/detail/winrt_utils.hpp +/boost/asio/detail/winsock_init.hpp +/boost/asio/detail/win_static_mutex.hpp +/boost/asio/detail/win_thread.hpp +/boost/asio/detail/win_tss_ptr.hpp +/boost/asio/detail/wrapped_handler.hpp +/boost/asio/error.hpp +/boost/asio/generic/ +/boost/asio/generic/basic_endpoint.hpp +/boost/asio/generic/datagram_protocol.hpp +/boost/asio/generic/detail/ +/boost/asio/generic/detail/endpoint.hpp +/boost/asio/generic/detail/impl/ +/boost/asio/generic/detail/impl/endpoint.ipp +/boost/asio/generic/raw_protocol.hpp +/boost/asio/generic/seq_packet_protocol.hpp +/boost/asio/generic/stream_protocol.hpp +/boost/asio/handler_alloc_hook.hpp +/boost/asio/handler_continuation_hook.hpp +/boost/asio/handler_invoke_hook.hpp +/boost/asio/handler_type.hpp +/boost/asio/high_resolution_timer.hpp +/boost/asio.hpp +/boost/asio/impl/ +/boost/asio/impl/buffered_read_stream.hpp +/boost/asio/impl/buffered_write_stream.hpp +/boost/asio/impl/connect.hpp +/boost/asio/impl/error.ipp +/boost/asio/impl/handler_alloc_hook.ipp +/boost/asio/impl/io_service.hpp +/boost/asio/impl/io_service.ipp +/boost/asio/impl/read_at.hpp +/boost/asio/impl/read.hpp +/boost/asio/impl/read_until.hpp +/boost/asio/impl/serial_port_base.hpp +/boost/asio/impl/serial_port_base.ipp +/boost/asio/impl/spawn.hpp +/boost/asio/impl/src.cpp +/boost/asio/impl/src.hpp +/boost/asio/impl/use_future.hpp +/boost/asio/impl/write_at.hpp +/boost/asio/impl/write.hpp +/boost/asio/io_service.hpp +/boost/asio/ip/ +/boost/asio/ip/address.hpp +/boost/asio/ip/address_v4.hpp +/boost/asio/ip/address_v6.hpp +/boost/asio/ip/basic_endpoint.hpp +/boost/asio/ip/basic_resolver_entry.hpp +/boost/asio/ip/basic_resolver.hpp +/boost/asio/ip/basic_resolver_iterator.hpp +/boost/asio/ip/basic_resolver_query.hpp +/boost/asio/ip/detail/ +/boost/asio/ip/detail/endpoint.hpp +/boost/asio/ip/detail/impl/ +/boost/asio/ip/detail/impl/endpoint.ipp +/boost/asio/ip/detail/socket_option.hpp +/boost/asio/ip/host_name.hpp +/boost/asio/ip/icmp.hpp +/boost/asio/ip/impl/ +/boost/asio/ip/impl/address.hpp +/boost/asio/ip/impl/address.ipp +/boost/asio/ip/impl/address_v4.hpp +/boost/asio/ip/impl/address_v4.ipp +/boost/asio/ip/impl/address_v6.hpp +/boost/asio/ip/impl/address_v6.ipp +/boost/asio/ip/impl/basic_endpoint.hpp +/boost/asio/ip/impl/host_name.ipp +/boost/asio/ip/multicast.hpp +/boost/asio/ip/resolver_query_base.hpp +/boost/asio/ip/resolver_service.hpp +/boost/asio/ip/tcp.hpp +/boost/asio/ip/udp.hpp +/boost/asio/ip/unicast.hpp +/boost/asio/ip/v6_only.hpp +/boost/asio/is_read_buffered.hpp +/boost/asio/is_write_buffered.hpp +/boost/asio/local/ +/boost/asio/local/basic_endpoint.hpp +/boost/asio/local/connect_pair.hpp +/boost/asio/local/datagram_protocol.hpp +/boost/asio/local/detail/ +/boost/asio/local/detail/endpoint.hpp +/boost/asio/local/detail/impl/ +/boost/asio/local/detail/impl/endpoint.ipp +/boost/asio/local/stream_protocol.hpp +/boost/asio/placeholders.hpp +/boost/asio/posix/ +/boost/asio/posix/basic_descriptor.hpp +/boost/asio/posix/basic_stream_descriptor.hpp +/boost/asio/posix/descriptor_base.hpp +/boost/asio/posix/stream_descriptor.hpp +/boost/asio/posix/stream_descriptor_service.hpp +/boost/asio/raw_socket_service.hpp +/boost/asio/read_at.hpp +/boost/asio/read.hpp +/boost/asio/read_until.hpp +/boost/asio/seq_packet_socket_service.hpp +/boost/asio/serial_port_base.hpp +/boost/asio/serial_port.hpp +/boost/asio/serial_port_service.hpp +/boost/asio/signal_set.hpp +/boost/asio/signal_set_service.hpp +/boost/asio/socket_acceptor_service.hpp +/boost/asio/socket_base.hpp +/boost/asio/spawn.hpp +/boost/asio/ssl/ +/boost/asio/ssl/basic_context.hpp +/boost/asio/ssl/context_base.hpp +/boost/asio/ssl/context.hpp +/boost/asio/ssl/context_service.hpp +/boost/asio/ssl/detail/ +/boost/asio/ssl/detail/buffered_handshake_op.hpp +/boost/asio/ssl/detail/engine.hpp +/boost/asio/ssl/detail/handshake_op.hpp +/boost/asio/ssl/detail/impl/ +/boost/asio/ssl/detail/impl/engine.ipp +/boost/asio/ssl/detail/impl/openssl_init.ipp +/boost/asio/ssl/detail/io.hpp +/boost/asio/ssl/detail/openssl_init.hpp +/boost/asio/ssl/detail/openssl_types.hpp +/boost/asio/ssl/detail/password_callback.hpp +/boost/asio/ssl/detail/read_op.hpp +/boost/asio/ssl/detail/shutdown_op.hpp +/boost/asio/ssl/detail/stream_core.hpp +/boost/asio/ssl/detail/verify_callback.hpp +/boost/asio/ssl/detail/write_op.hpp +/boost/asio/ssl/error.hpp +/boost/asio/ssl.hpp +/boost/asio/ssl/impl/ +/boost/asio/ssl/impl/context.hpp +/boost/asio/ssl/impl/context.ipp +/boost/asio/ssl/impl/error.ipp +/boost/asio/ssl/impl/rfc2818_verification.ipp +/boost/asio/ssl/impl/src.hpp +/boost/asio/ssl/old/ +/boost/asio/ssl/old/basic_context.hpp +/boost/asio/ssl/old/context_service.hpp +/boost/asio/ssl/old/detail/ +/boost/asio/ssl/old/detail/openssl_context_service.hpp +/boost/asio/ssl/old/detail/openssl_operation.hpp +/boost/asio/ssl/old/detail/openssl_stream_service.hpp +/boost/asio/ssl/old/stream.hpp +/boost/asio/ssl/old/stream_service.hpp +/boost/asio/ssl/rfc2818_verification.hpp +/boost/asio/ssl/stream_base.hpp +/boost/asio/ssl/stream.hpp +/boost/asio/ssl/stream_service.hpp +/boost/asio/ssl/verify_context.hpp +/boost/asio/ssl/verify_mode.hpp +/boost/asio/steady_timer.hpp +/boost/asio/strand.hpp +/boost/asio/streambuf.hpp +/boost/asio/stream_socket_service.hpp +/boost/asio/system_timer.hpp +/boost/asio/time_traits.hpp +/boost/asio/unyield.hpp +/boost/asio/use_future.hpp +/boost/asio/version.hpp +/boost/asio/waitable_timer_service.hpp +/boost/asio/wait_traits.hpp +/boost/asio/windows/ +/boost/asio/windows/basic_handle.hpp +/boost/asio/windows/basic_object_handle.hpp +/boost/asio/windows/basic_random_access_handle.hpp +/boost/asio/windows/basic_stream_handle.hpp +/boost/asio/windows/object_handle.hpp +/boost/asio/windows/object_handle_service.hpp +/boost/asio/windows/overlapped_ptr.hpp +/boost/asio/windows/random_access_handle.hpp +/boost/asio/windows/random_access_handle_service.hpp +/boost/asio/windows/stream_handle.hpp +/boost/asio/windows/stream_handle_service.hpp +/boost/asio/write_at.hpp +/boost/asio/write.hpp +/boost/asio/yield.hpp +/boost/cerrno.hpp +/boost/config/ +/boost/config/warning_disable.hpp +/boost/system/ +/boost/system/api_config.hpp +/boost/system/config.hpp +/boost/system/cygwin_error.hpp +/boost/system/detail/ +/boost/system/detail/error_code.ipp +/boost/system/detail/local_free_on_destruction.hpp +/boost/system/error_code.hpp +/boost/system/linux_error.hpp +/boost/system/system_error.hpp +/boost/system/windows_error.hpp +/doc/ +/doc/html/ +/doc/html/boost_asio/ +/doc/html/boost_asio/async_op1.png +/doc/html/boost_asio/async_op2.png +/doc/html/boost_asio/example/ +/doc/html/boost_asio/example/cpp03/ +/doc/html/boost_asio/example/cpp03/allocation/ +/doc/html/boost_asio/example/cpp03/allocation/server.cpp +/doc/html/boost_asio/example/cpp03/buffers/ +/doc/html/boost_asio/example/cpp03/buffers/reference_counted.cpp +/doc/html/boost_asio/example/cpp03/chat/ +/doc/html/boost_asio/example/cpp03/chat/chat_client.cpp +/doc/html/boost_asio/example/cpp03/chat/chat_message.hpp +/doc/html/boost_asio/example/cpp03/chat/chat_server.cpp +/doc/html/boost_asio/example/cpp03/chat/posix_chat_client.cpp +/doc/html/boost_asio/example/cpp03/echo/ +/doc/html/boost_asio/example/cpp03/echo/async_tcp_echo_server.cpp +/doc/html/boost_asio/example/cpp03/echo/async_udp_echo_server.cpp +/doc/html/boost_asio/example/cpp03/echo/blocking_tcp_echo_client.cpp +/doc/html/boost_asio/example/cpp03/echo/blocking_tcp_echo_server.cpp +/doc/html/boost_asio/example/cpp03/echo/blocking_udp_echo_client.cpp +/doc/html/boost_asio/example/cpp03/echo/blocking_udp_echo_server.cpp +/doc/html/boost_asio/example/cpp03/fork/ +/doc/html/boost_asio/example/cpp03/fork/daemon.cpp +/doc/html/boost_asio/example/cpp03/fork/process_per_connection.cpp +/doc/html/boost_asio/example/cpp03/http/ +/doc/html/boost_asio/example/cpp03/http/client/ +/doc/html/boost_asio/example/cpp03/http/client/async_client.cpp +/doc/html/boost_asio/example/cpp03/http/client/sync_client.cpp +/doc/html/boost_asio/example/cpp03/http/server/ +/doc/html/boost_asio/example/cpp03/http/server2/ +/doc/html/boost_asio/example/cpp03/http/server2/connection.cpp +/doc/html/boost_asio/example/cpp03/http/server2/connection.hpp +/doc/html/boost_asio/example/cpp03/http/server2/header.hpp +/doc/html/boost_asio/example/cpp03/http/server2/io_service_pool.cpp +/doc/html/boost_asio/example/cpp03/http/server2/io_service_pool.hpp +/doc/html/boost_asio/example/cpp03/http/server2/main.cpp +/doc/html/boost_asio/example/cpp03/http/server2/mime_types.cpp +/doc/html/boost_asio/example/cpp03/http/server2/mime_types.hpp +/doc/html/boost_asio/example/cpp03/http/server2/reply.cpp +/doc/html/boost_asio/example/cpp03/http/server2/reply.hpp +/doc/html/boost_asio/example/cpp03/http/server2/request_handler.cpp +/doc/html/boost_asio/example/cpp03/http/server2/request_handler.hpp +/doc/html/boost_asio/example/cpp03/http/server2/request.hpp +/doc/html/boost_asio/example/cpp03/http/server2/request_parser.cpp +/doc/html/boost_asio/example/cpp03/http/server2/request_parser.hpp +/doc/html/boost_asio/example/cpp03/http/server2/server.cpp +/doc/html/boost_asio/example/cpp03/http/server2/server.hpp +/doc/html/boost_asio/example/cpp03/http/server3/ +/doc/html/boost_asio/example/cpp03/http/server3/connection.cpp +/doc/html/boost_asio/example/cpp03/http/server3/connection.hpp +/doc/html/boost_asio/example/cpp03/http/server3/header.hpp +/doc/html/boost_asio/example/cpp03/http/server3/main.cpp +/doc/html/boost_asio/example/cpp03/http/server3/mime_types.cpp +/doc/html/boost_asio/example/cpp03/http/server3/mime_types.hpp +/doc/html/boost_asio/example/cpp03/http/server3/reply.cpp +/doc/html/boost_asio/example/cpp03/http/server3/reply.hpp +/doc/html/boost_asio/example/cpp03/http/server3/request_handler.cpp +/doc/html/boost_asio/example/cpp03/http/server3/request_handler.hpp +/doc/html/boost_asio/example/cpp03/http/server3/request.hpp +/doc/html/boost_asio/example/cpp03/http/server3/request_parser.cpp +/doc/html/boost_asio/example/cpp03/http/server3/request_parser.hpp +/doc/html/boost_asio/example/cpp03/http/server3/server.cpp +/doc/html/boost_asio/example/cpp03/http/server3/server.hpp +/doc/html/boost_asio/example/cpp03/http/server4/ +/doc/html/boost_asio/example/cpp03/http/server4/file_handler.cpp +/doc/html/boost_asio/example/cpp03/http/server4/file_handler.hpp +/doc/html/boost_asio/example/cpp03/http/server4/header.hpp +/doc/html/boost_asio/example/cpp03/http/server4/main.cpp +/doc/html/boost_asio/example/cpp03/http/server4/mime_types.cpp +/doc/html/boost_asio/example/cpp03/http/server4/mime_types.hpp +/doc/html/boost_asio/example/cpp03/http/server4/reply.cpp +/doc/html/boost_asio/example/cpp03/http/server4/reply.hpp +/doc/html/boost_asio/example/cpp03/http/server4/request.hpp +/doc/html/boost_asio/example/cpp03/http/server4/request_parser.cpp +/doc/html/boost_asio/example/cpp03/http/server4/request_parser.hpp +/doc/html/boost_asio/example/cpp03/http/server4/server.cpp +/doc/html/boost_asio/example/cpp03/http/server4/server.hpp +/doc/html/boost_asio/example/cpp03/http/server/connection.cpp +/doc/html/boost_asio/example/cpp03/http/server/connection.hpp +/doc/html/boost_asio/example/cpp03/http/server/connection_manager.cpp +/doc/html/boost_asio/example/cpp03/http/server/connection_manager.hpp +/doc/html/boost_asio/example/cpp03/http/server/header.hpp +/doc/html/boost_asio/example/cpp03/http/server/main.cpp +/doc/html/boost_asio/example/cpp03/http/server/mime_types.cpp +/doc/html/boost_asio/example/cpp03/http/server/mime_types.hpp +/doc/html/boost_asio/example/cpp03/http/server/reply.cpp +/doc/html/boost_asio/example/cpp03/http/server/reply.hpp +/doc/html/boost_asio/example/cpp03/http/server/request_handler.cpp +/doc/html/boost_asio/example/cpp03/http/server/request_handler.hpp +/doc/html/boost_asio/example/cpp03/http/server/request.hpp +/doc/html/boost_asio/example/cpp03/http/server/request_parser.cpp +/doc/html/boost_asio/example/cpp03/http/server/request_parser.hpp +/doc/html/boost_asio/example/cpp03/http/server/server.cpp +/doc/html/boost_asio/example/cpp03/http/server/server.hpp +/doc/html/boost_asio/example/cpp03/icmp/ +/doc/html/boost_asio/example/cpp03/icmp/icmp_header.hpp +/doc/html/boost_asio/example/cpp03/icmp/ipv4_header.hpp +/doc/html/boost_asio/example/cpp03/icmp/ping.cpp +/doc/html/boost_asio/example/cpp03/invocation/ +/doc/html/boost_asio/example/cpp03/invocation/prioritised_handlers.cpp +/doc/html/boost_asio/example/cpp03/iostreams/ +/doc/html/boost_asio/example/cpp03/iostreams/daytime_client.cpp +/doc/html/boost_asio/example/cpp03/iostreams/daytime_server.cpp +/doc/html/boost_asio/example/cpp03/iostreams/http_client.cpp +/doc/html/boost_asio/example/cpp03/local/ +/doc/html/boost_asio/example/cpp03/local/connect_pair.cpp +/doc/html/boost_asio/example/cpp03/local/iostream_client.cpp +/doc/html/boost_asio/example/cpp03/local/stream_client.cpp +/doc/html/boost_asio/example/cpp03/local/stream_server.cpp +/doc/html/boost_asio/example/cpp03/multicast/ +/doc/html/boost_asio/example/cpp03/multicast/receiver.cpp +/doc/html/boost_asio/example/cpp03/multicast/sender.cpp +/doc/html/boost_asio/example/cpp03/nonblocking/ +/doc/html/boost_asio/example/cpp03/nonblocking/third_party_lib.cpp +/doc/html/boost_asio/example/cpp03/porthopper/ +/doc/html/boost_asio/example/cpp03/porthopper/client.cpp +/doc/html/boost_asio/example/cpp03/porthopper/protocol.hpp +/doc/html/boost_asio/example/cpp03/porthopper/server.cpp +/doc/html/boost_asio/example/cpp03/serialization/ +/doc/html/boost_asio/example/cpp03/serialization/client.cpp +/doc/html/boost_asio/example/cpp03/serialization/connection.hpp +/doc/html/boost_asio/example/cpp03/serialization/server.cpp +/doc/html/boost_asio/example/cpp03/serialization/stock.hpp +/doc/html/boost_asio/example/cpp03/services/ +/doc/html/boost_asio/example/cpp03/services/basic_logger.hpp +/doc/html/boost_asio/example/cpp03/services/daytime_client.cpp +/doc/html/boost_asio/example/cpp03/services/logger.hpp +/doc/html/boost_asio/example/cpp03/services/logger_service.cpp +/doc/html/boost_asio/example/cpp03/services/logger_service.hpp +/doc/html/boost_asio/example/cpp03/services/stream_socket_service.hpp +/doc/html/boost_asio/example/cpp03/socks4/ +/doc/html/boost_asio/example/cpp03/socks4/socks4.hpp +/doc/html/boost_asio/example/cpp03/socks4/sync_client.cpp +/doc/html/boost_asio/example/cpp03/spawn/ +/doc/html/boost_asio/example/cpp03/spawn/echo_server.cpp +/doc/html/boost_asio/example/cpp03/ssl/ +/doc/html/boost_asio/example/cpp03/ssl/client.cpp +/doc/html/boost_asio/example/cpp03/ssl/server.cpp +/doc/html/boost_asio/example/cpp03/timeouts/ +/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp +/doc/html/boost_asio/example/cpp03/timeouts/blocking_tcp_client.cpp +/doc/html/boost_asio/example/cpp03/timeouts/blocking_udp_client.cpp +/doc/html/boost_asio/example/cpp03/timeouts/server.cpp +/doc/html/boost_asio/example/cpp03/timers/ +/doc/html/boost_asio/example/cpp03/timers/tick_count_timer.cpp +/doc/html/boost_asio/example/cpp03/timers/time_t_timer.cpp +/doc/html/boost_asio/example/cpp03/windows/ +/doc/html/boost_asio/example/cpp03/windows/transmit_file.cpp +/doc/html/boost_asio/example/cpp11/ +/doc/html/boost_asio/example/cpp11/allocation/ +/doc/html/boost_asio/example/cpp11/allocation/server.cpp +/doc/html/boost_asio/example/cpp11/buffers/ +/doc/html/boost_asio/example/cpp11/buffers/reference_counted.cpp +/doc/html/boost_asio/example/cpp11/chat/ +/doc/html/boost_asio/example/cpp11/chat/chat_client.cpp +/doc/html/boost_asio/example/cpp11/chat/chat_message.hpp +/doc/html/boost_asio/example/cpp11/chat/chat_server.cpp +/doc/html/boost_asio/example/cpp11/echo/ +/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp +/doc/html/boost_asio/example/cpp11/echo/async_udp_echo_server.cpp +/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_client.cpp +/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_server.cpp +/doc/html/boost_asio/example/cpp11/echo/blocking_udp_echo_client.cpp +/doc/html/boost_asio/example/cpp11/echo/blocking_udp_echo_server.cpp +/doc/html/boost_asio/example/cpp11/futures/ +/doc/html/boost_asio/example/cpp11/futures/daytime_client.cpp +/doc/html/boost_asio/example/cpp11/http/ +/doc/html/boost_asio/example/cpp11/http/server/ +/doc/html/boost_asio/example/cpp11/http/server/connection.cpp +/doc/html/boost_asio/example/cpp11/http/server/connection.hpp +/doc/html/boost_asio/example/cpp11/http/server/connection_manager.cpp +/doc/html/boost_asio/example/cpp11/http/server/connection_manager.hpp +/doc/html/boost_asio/example/cpp11/http/server/header.hpp +/doc/html/boost_asio/example/cpp11/http/server/main.cpp +/doc/html/boost_asio/example/cpp11/http/server/mime_types.cpp +/doc/html/boost_asio/example/cpp11/http/server/mime_types.hpp +/doc/html/boost_asio/example/cpp11/http/server/reply.cpp +/doc/html/boost_asio/example/cpp11/http/server/reply.hpp +/doc/html/boost_asio/example/cpp11/http/server/request_handler.cpp +/doc/html/boost_asio/example/cpp11/http/server/request_handler.hpp +/doc/html/boost_asio/example/cpp11/http/server/request.hpp +/doc/html/boost_asio/example/cpp11/http/server/request_parser.cpp +/doc/html/boost_asio/example/cpp11/http/server/request_parser.hpp +/doc/html/boost_asio/example/cpp11/http/server/server.cpp +/doc/html/boost_asio/example/cpp11/http/server/server.hpp +/doc/html/boost_asio/example/cpp11/spawn/ +/doc/html/boost_asio/example/cpp11/spawn/echo_server.cpp +/doc/html/boost_asio/examples/ +/doc/html/boost_asio/examples/cpp03_examples.html +/doc/html/boost_asio/examples/cpp11_examples.html +/doc/html/boost_asio/examples.html +/doc/html/boost_asio/history.html +/doc/html/boost_asio.html +/doc/html/boost_asio/index.html +/doc/html/boost_asio/overview/ +/doc/html/boost_asio/overview/core/ +/doc/html/boost_asio/overview/core/allocation.html +/doc/html/boost_asio/overview/core/async.html +/doc/html/boost_asio/overview/core/basics.html +/doc/html/boost_asio/overview/core/buffers.html +/doc/html/boost_asio/overview/core/coroutine.html +/doc/html/boost_asio/overview/core/handler_tracking.html +/doc/html/boost_asio/overview/core.html +/doc/html/boost_asio/overview/core/line_based.html +/doc/html/boost_asio/overview/core/reactor.html +/doc/html/boost_asio/overview/core/spawn.html +/doc/html/boost_asio/overview/core/strands.html +/doc/html/boost_asio/overview/core/streams.html +/doc/html/boost_asio/overview/core/threads.html +/doc/html/boost_asio/overview/cpp2011/ +/doc/html/boost_asio/overview/cpp2011/array.html +/doc/html/boost_asio/overview/cpp2011/atomic.html +/doc/html/boost_asio/overview/cpp2011/chrono.html +/doc/html/boost_asio/overview/cpp2011/futures.html +/doc/html/boost_asio/overview/cpp2011.html +/doc/html/boost_asio/overview/cpp2011/move_handlers.html +/doc/html/boost_asio/overview/cpp2011/move_objects.html +/doc/html/boost_asio/overview/cpp2011/shared_ptr.html +/doc/html/boost_asio/overview/cpp2011/variadic.html +/doc/html/boost_asio/overview.html +/doc/html/boost_asio/overview/implementation.html +/doc/html/boost_asio/overview/networking/ +/doc/html/boost_asio/overview/networking/bsd_sockets.html +/doc/html/boost_asio/overview/networking.html +/doc/html/boost_asio/overview/networking/iostreams.html +/doc/html/boost_asio/overview/networking/other_protocols.html +/doc/html/boost_asio/overview/networking/protocols.html +/doc/html/boost_asio/overview/posix/ +/doc/html/boost_asio/overview/posix/fork.html +/doc/html/boost_asio/overview/posix.html +/doc/html/boost_asio/overview/posix/local.html +/doc/html/boost_asio/overview/posix/stream_descriptor.html +/doc/html/boost_asio/overview/rationale.html +/doc/html/boost_asio/overview/serial_ports.html +/doc/html/boost_asio/overview/signals.html +/doc/html/boost_asio/overview/ssl.html +/doc/html/boost_asio/overview/timers.html +/doc/html/boost_asio/overview/windows/ +/doc/html/boost_asio/overview/windows.html +/doc/html/boost_asio/overview/windows/object_handle.html +/doc/html/boost_asio/overview/windows/random_access_handle.html +/doc/html/boost_asio/overview/windows/stream_handle.html +/doc/html/boost_asio/proactor.png +/doc/html/boost_asio/reference/ +/doc/html/boost_asio/reference/AcceptHandler.html +/doc/html/boost_asio/reference/add_service.html +/doc/html/boost_asio/reference/asio_handler_allocate.html +/doc/html/boost_asio/reference/asio_handler_deallocate.html +/doc/html/boost_asio/reference/asio_handler_invoke/ +/doc/html/boost_asio/reference/asio_handler_invoke.html +/doc/html/boost_asio/reference/asio_handler_invoke/overload1.html +/doc/html/boost_asio/reference/asio_handler_invoke/overload2.html +/doc/html/boost_asio/reference/asio_handler_is_continuation.html +/doc/html/boost_asio/reference/async_connect/ +/doc/html/boost_asio/reference/async_connect.html +/doc/html/boost_asio/reference/async_connect/overload1.html +/doc/html/boost_asio/reference/async_connect/overload2.html +/doc/html/boost_asio/reference/async_connect/overload3.html +/doc/html/boost_asio/reference/async_connect/overload4.html +/doc/html/boost_asio/reference/asynchronous_operations.html +/doc/html/boost_asio/reference/AsyncRandomAccessReadDevice.html +/doc/html/boost_asio/reference/AsyncRandomAccessWriteDevice.html +/doc/html/boost_asio/reference/async_read/ +/doc/html/boost_asio/reference/async_read_at/ +/doc/html/boost_asio/reference/async_read_at.html +/doc/html/boost_asio/reference/async_read_at/overload1.html +/doc/html/boost_asio/reference/async_read_at/overload2.html +/doc/html/boost_asio/reference/async_read_at/overload3.html +/doc/html/boost_asio/reference/async_read_at/overload4.html +/doc/html/boost_asio/reference/async_read.html +/doc/html/boost_asio/reference/async_read/overload1.html +/doc/html/boost_asio/reference/async_read/overload2.html +/doc/html/boost_asio/reference/async_read/overload3.html +/doc/html/boost_asio/reference/async_read/overload4.html +/doc/html/boost_asio/reference/AsyncReadStream.html +/doc/html/boost_asio/reference/async_read_until/ +/doc/html/boost_asio/reference/async_read_until.html +/doc/html/boost_asio/reference/async_read_until/overload1.html +/doc/html/boost_asio/reference/async_read_until/overload2.html +/doc/html/boost_asio/reference/async_read_until/overload3.html +/doc/html/boost_asio/reference/async_read_until/overload4.html +/doc/html/boost_asio/reference/async_result/ +/doc/html/boost_asio/reference/async_result/async_result.html +/doc/html/boost_asio/reference/async_result/get.html +/doc/html/boost_asio/reference/async_result.html +/doc/html/boost_asio/reference/async_result/type.html +/doc/html/boost_asio/reference/async_write/ +/doc/html/boost_asio/reference/async_write_at/ +/doc/html/boost_asio/reference/async_write_at.html +/doc/html/boost_asio/reference/async_write_at/overload1.html +/doc/html/boost_asio/reference/async_write_at/overload2.html +/doc/html/boost_asio/reference/async_write_at/overload3.html +/doc/html/boost_asio/reference/async_write_at/overload4.html +/doc/html/boost_asio/reference/async_write.html +/doc/html/boost_asio/reference/async_write/overload1.html +/doc/html/boost_asio/reference/async_write/overload2.html +/doc/html/boost_asio/reference/async_write/overload3.html +/doc/html/boost_asio/reference/async_write/overload4.html +/doc/html/boost_asio/reference/AsyncWriteStream.html +/doc/html/boost_asio/reference/basic_datagram_socket/ +/doc/html/boost_asio/reference/basic_datagram_socket/assign/ +/doc/html/boost_asio/reference/basic_datagram_socket/assign.html +/doc/html/boost_asio/reference/basic_datagram_socket/assign/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/assign/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_connect.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive/ +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive_from/ +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive_from.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive_from/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive_from/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_receive/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_send/ +/doc/html/boost_asio/reference/basic_datagram_socket/async_send.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_send/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_send/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_send_to/ +/doc/html/boost_asio/reference/basic_datagram_socket/async_send_to.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_send_to/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/async_send_to/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/at_mark/ +/doc/html/boost_asio/reference/basic_datagram_socket/at_mark.html +/doc/html/boost_asio/reference/basic_datagram_socket/at_mark/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/at_mark/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/available/ +/doc/html/boost_asio/reference/basic_datagram_socket/available.html +/doc/html/boost_asio/reference/basic_datagram_socket/available/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/available/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/ +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/overload4.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/overload5.html +/doc/html/boost_asio/reference/basic_datagram_socket/basic_datagram_socket/overload6.html +/doc/html/boost_asio/reference/basic_datagram_socket/bind/ +/doc/html/boost_asio/reference/basic_datagram_socket/bind.html +/doc/html/boost_asio/reference/basic_datagram_socket/bind/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/bind/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/broadcast.html +/doc/html/boost_asio/reference/basic_datagram_socket/bytes_readable.html +/doc/html/boost_asio/reference/basic_datagram_socket/cancel/ +/doc/html/boost_asio/reference/basic_datagram_socket/cancel.html +/doc/html/boost_asio/reference/basic_datagram_socket/cancel/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/cancel/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/close/ +/doc/html/boost_asio/reference/basic_datagram_socket/close.html +/doc/html/boost_asio/reference/basic_datagram_socket/close/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/close/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/connect/ +/doc/html/boost_asio/reference/basic_datagram_socket/connect.html +/doc/html/boost_asio/reference/basic_datagram_socket/connect/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/connect/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/debug.html +/doc/html/boost_asio/reference/basic_datagram_socket/do_not_route.html +/doc/html/boost_asio/reference/basic_datagram_socket/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_datagram_socket/endpoint_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_implementation/ +/doc/html/boost_asio/reference/basic_datagram_socket/get_implementation.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_io_service.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_option/ +/doc/html/boost_asio/reference/basic_datagram_socket/get_option.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_option/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_option/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_service/ +/doc/html/boost_asio/reference/basic_datagram_socket/get_service.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_service/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/get_service/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket.html +/doc/html/boost_asio/reference/basic_datagram_socket/implementation.html +/doc/html/boost_asio/reference/basic_datagram_socket/implementation_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/io_control/ +/doc/html/boost_asio/reference/basic_datagram_socket/io_control.html +/doc/html/boost_asio/reference/basic_datagram_socket/io_control/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/io_control/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/is_open.html +/doc/html/boost_asio/reference/basic_datagram_socket/keep_alive.html +/doc/html/boost_asio/reference/basic_datagram_socket/linger.html +/doc/html/boost_asio/reference/basic_datagram_socket/local_endpoint/ +/doc/html/boost_asio/reference/basic_datagram_socket/local_endpoint.html +/doc/html/boost_asio/reference/basic_datagram_socket/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/lowest_layer/ +/doc/html/boost_asio/reference/basic_datagram_socket/lowest_layer.html +/doc/html/boost_asio/reference/basic_datagram_socket/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/max_connections.html +/doc/html/boost_asio/reference/basic_datagram_socket/message_do_not_route.html +/doc/html/boost_asio/reference/basic_datagram_socket/message_end_of_record.html +/doc/html/boost_asio/reference/basic_datagram_socket/message_flags.html +/doc/html/boost_asio/reference/basic_datagram_socket/message_out_of_band.html +/doc/html/boost_asio/reference/basic_datagram_socket/message_peek.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_handle.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_handle_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/native.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_non_blocking/ +/doc/html/boost_asio/reference/basic_datagram_socket/native_non_blocking.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/native_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/non_blocking/ +/doc/html/boost_asio/reference/basic_datagram_socket/non_blocking.html +/doc/html/boost_asio/reference/basic_datagram_socket/non_blocking_io.html +/doc/html/boost_asio/reference/basic_datagram_socket/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/open/ +/doc/html/boost_asio/reference/basic_datagram_socket/open.html +/doc/html/boost_asio/reference/basic_datagram_socket/open/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/open/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/operator_eq_/ +/doc/html/boost_asio/reference/basic_datagram_socket/operator_eq_.html +/doc/html/boost_asio/reference/basic_datagram_socket/operator_eq_/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/operator_eq_/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/protocol_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive/ +/doc/html/boost_asio/reference/basic_datagram_socket/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive_from/ +/doc/html/boost_asio/reference/basic_datagram_socket/receive_from.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive_from/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive_from/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive_from/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/receive/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/remote_endpoint/ +/doc/html/boost_asio/reference/basic_datagram_socket/remote_endpoint.html +/doc/html/boost_asio/reference/basic_datagram_socket/remote_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/remote_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/reuse_address.html +/doc/html/boost_asio/reference/basic_datagram_socket/send/ +/doc/html/boost_asio/reference/basic_datagram_socket/send_buffer_size.html +/doc/html/boost_asio/reference/basic_datagram_socket/send.html +/doc/html/boost_asio/reference/basic_datagram_socket/send_low_watermark.html +/doc/html/boost_asio/reference/basic_datagram_socket/send/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/send/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/send/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/send_to/ +/doc/html/boost_asio/reference/basic_datagram_socket/send_to.html +/doc/html/boost_asio/reference/basic_datagram_socket/send_to/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/send_to/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/send_to/overload3.html +/doc/html/boost_asio/reference/basic_datagram_socket/service.html +/doc/html/boost_asio/reference/basic_datagram_socket/service_type.html +/doc/html/boost_asio/reference/basic_datagram_socket/set_option/ +/doc/html/boost_asio/reference/basic_datagram_socket/set_option.html +/doc/html/boost_asio/reference/basic_datagram_socket/set_option/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/set_option/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/shutdown/ +/doc/html/boost_asio/reference/basic_datagram_socket/shutdown.html +/doc/html/boost_asio/reference/basic_datagram_socket/shutdown/overload1.html +/doc/html/boost_asio/reference/basic_datagram_socket/shutdown/overload2.html +/doc/html/boost_asio/reference/basic_datagram_socket/shutdown_type.html +/doc/html/boost_asio/reference/basic_deadline_timer/ +/doc/html/boost_asio/reference/basic_deadline_timer/async_wait.html +/doc/html/boost_asio/reference/basic_deadline_timer/basic_deadline_timer/ +/doc/html/boost_asio/reference/basic_deadline_timer/basic_deadline_timer.html +/doc/html/boost_asio/reference/basic_deadline_timer/basic_deadline_timer/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/basic_deadline_timer/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer/basic_deadline_timer/overload3.html +/doc/html/boost_asio/reference/basic_deadline_timer/cancel/ +/doc/html/boost_asio/reference/basic_deadline_timer/cancel.html +/doc/html/boost_asio/reference/basic_deadline_timer/cancel_one/ +/doc/html/boost_asio/reference/basic_deadline_timer/cancel_one.html +/doc/html/boost_asio/reference/basic_deadline_timer/cancel_one/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/cancel_one/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer/cancel/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/cancel/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer/duration_type.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_at/ +/doc/html/boost_asio/reference/basic_deadline_timer/expires_at.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_at/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_at/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_at/overload3.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_from_now/ +/doc/html/boost_asio/reference/basic_deadline_timer/expires_from_now.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_from_now/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_from_now/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer/expires_from_now/overload3.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_implementation/ +/doc/html/boost_asio/reference/basic_deadline_timer/get_implementation.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_io_service.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_service/ +/doc/html/boost_asio/reference/basic_deadline_timer/get_service.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_service/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/get_service/overload2.html +/doc/html/boost_asio/reference/basic_deadline_timer.html +/doc/html/boost_asio/reference/basic_deadline_timer/implementation.html +/doc/html/boost_asio/reference/basic_deadline_timer/implementation_type.html +/doc/html/boost_asio/reference/basic_deadline_timer/service.html +/doc/html/boost_asio/reference/basic_deadline_timer/service_type.html +/doc/html/boost_asio/reference/basic_deadline_timer/time_type.html +/doc/html/boost_asio/reference/basic_deadline_timer/traits_type.html +/doc/html/boost_asio/reference/basic_deadline_timer/wait/ +/doc/html/boost_asio/reference/basic_deadline_timer/wait.html +/doc/html/boost_asio/reference/basic_deadline_timer/wait/overload1.html +/doc/html/boost_asio/reference/basic_deadline_timer/wait/overload2.html +/doc/html/boost_asio/reference/basic_io_object/ +/doc/html/boost_asio/reference/basic_io_object/basic_io_object/ +/doc/html/boost_asio/reference/basic_io_object/_basic_io_object.html +/doc/html/boost_asio/reference/basic_io_object/basic_io_object.html +/doc/html/boost_asio/reference/basic_io_object/basic_io_object/overload1.html +/doc/html/boost_asio/reference/basic_io_object/basic_io_object/overload2.html +/doc/html/boost_asio/reference/basic_io_object/get_implementation/ +/doc/html/boost_asio/reference/basic_io_object/get_implementation.html +/doc/html/boost_asio/reference/basic_io_object/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_io_object/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_io_object/get_io_service.html +/doc/html/boost_asio/reference/basic_io_object/get_service/ +/doc/html/boost_asio/reference/basic_io_object/get_service.html +/doc/html/boost_asio/reference/basic_io_object/get_service/overload1.html +/doc/html/boost_asio/reference/basic_io_object/get_service/overload2.html +/doc/html/boost_asio/reference/basic_io_object.html +/doc/html/boost_asio/reference/basic_io_object/implementation.html +/doc/html/boost_asio/reference/basic_io_object/implementation_type.html +/doc/html/boost_asio/reference/basic_io_object/operator_eq_.html +/doc/html/boost_asio/reference/basic_io_object/service.html +/doc/html/boost_asio/reference/basic_io_object/service_type.html +/doc/html/boost_asio/reference/basic_raw_socket/ +/doc/html/boost_asio/reference/basic_raw_socket/assign/ +/doc/html/boost_asio/reference/basic_raw_socket/assign.html +/doc/html/boost_asio/reference/basic_raw_socket/assign/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/assign/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/async_connect.html +/doc/html/boost_asio/reference/basic_raw_socket/async_receive/ +/doc/html/boost_asio/reference/basic_raw_socket/async_receive_from/ +/doc/html/boost_asio/reference/basic_raw_socket/async_receive_from.html +/doc/html/boost_asio/reference/basic_raw_socket/async_receive_from/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/async_receive_from/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/async_receive.html +/doc/html/boost_asio/reference/basic_raw_socket/async_receive/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/async_receive/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/async_send/ +/doc/html/boost_asio/reference/basic_raw_socket/async_send.html +/doc/html/boost_asio/reference/basic_raw_socket/async_send/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/async_send/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/async_send_to/ +/doc/html/boost_asio/reference/basic_raw_socket/async_send_to.html +/doc/html/boost_asio/reference/basic_raw_socket/async_send_to/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/async_send_to/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/at_mark/ +/doc/html/boost_asio/reference/basic_raw_socket/at_mark.html +/doc/html/boost_asio/reference/basic_raw_socket/at_mark/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/at_mark/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/available/ +/doc/html/boost_asio/reference/basic_raw_socket/available.html +/doc/html/boost_asio/reference/basic_raw_socket/available/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/available/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/ +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/overload4.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/overload5.html +/doc/html/boost_asio/reference/basic_raw_socket/basic_raw_socket/overload6.html +/doc/html/boost_asio/reference/basic_raw_socket/bind/ +/doc/html/boost_asio/reference/basic_raw_socket/bind.html +/doc/html/boost_asio/reference/basic_raw_socket/bind/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/bind/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/broadcast.html +/doc/html/boost_asio/reference/basic_raw_socket/bytes_readable.html +/doc/html/boost_asio/reference/basic_raw_socket/cancel/ +/doc/html/boost_asio/reference/basic_raw_socket/cancel.html +/doc/html/boost_asio/reference/basic_raw_socket/cancel/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/cancel/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/close/ +/doc/html/boost_asio/reference/basic_raw_socket/close.html +/doc/html/boost_asio/reference/basic_raw_socket/close/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/close/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/connect/ +/doc/html/boost_asio/reference/basic_raw_socket/connect.html +/doc/html/boost_asio/reference/basic_raw_socket/connect/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/connect/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/debug.html +/doc/html/boost_asio/reference/basic_raw_socket/do_not_route.html +/doc/html/boost_asio/reference/basic_raw_socket/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_raw_socket/endpoint_type.html +/doc/html/boost_asio/reference/basic_raw_socket/get_implementation/ +/doc/html/boost_asio/reference/basic_raw_socket/get_implementation.html +/doc/html/boost_asio/reference/basic_raw_socket/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/get_io_service.html +/doc/html/boost_asio/reference/basic_raw_socket/get_option/ +/doc/html/boost_asio/reference/basic_raw_socket/get_option.html +/doc/html/boost_asio/reference/basic_raw_socket/get_option/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/get_option/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/get_service/ +/doc/html/boost_asio/reference/basic_raw_socket/get_service.html +/doc/html/boost_asio/reference/basic_raw_socket/get_service/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/get_service/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket.html +/doc/html/boost_asio/reference/basic_raw_socket/implementation.html +/doc/html/boost_asio/reference/basic_raw_socket/implementation_type.html +/doc/html/boost_asio/reference/basic_raw_socket/io_control/ +/doc/html/boost_asio/reference/basic_raw_socket/io_control.html +/doc/html/boost_asio/reference/basic_raw_socket/io_control/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/io_control/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/is_open.html +/doc/html/boost_asio/reference/basic_raw_socket/keep_alive.html +/doc/html/boost_asio/reference/basic_raw_socket/linger.html +/doc/html/boost_asio/reference/basic_raw_socket/local_endpoint/ +/doc/html/boost_asio/reference/basic_raw_socket/local_endpoint.html +/doc/html/boost_asio/reference/basic_raw_socket/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/lowest_layer/ +/doc/html/boost_asio/reference/basic_raw_socket/lowest_layer.html +/doc/html/boost_asio/reference/basic_raw_socket/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_raw_socket/max_connections.html +/doc/html/boost_asio/reference/basic_raw_socket/message_do_not_route.html +/doc/html/boost_asio/reference/basic_raw_socket/message_end_of_record.html +/doc/html/boost_asio/reference/basic_raw_socket/message_flags.html +/doc/html/boost_asio/reference/basic_raw_socket/message_out_of_band.html +/doc/html/boost_asio/reference/basic_raw_socket/message_peek.html +/doc/html/boost_asio/reference/basic_raw_socket/native_handle.html +/doc/html/boost_asio/reference/basic_raw_socket/native_handle_type.html +/doc/html/boost_asio/reference/basic_raw_socket/native.html +/doc/html/boost_asio/reference/basic_raw_socket/native_non_blocking/ +/doc/html/boost_asio/reference/basic_raw_socket/native_non_blocking.html +/doc/html/boost_asio/reference/basic_raw_socket/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/native_type.html +/doc/html/boost_asio/reference/basic_raw_socket/non_blocking/ +/doc/html/boost_asio/reference/basic_raw_socket/non_blocking.html +/doc/html/boost_asio/reference/basic_raw_socket/non_blocking_io.html +/doc/html/boost_asio/reference/basic_raw_socket/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/open/ +/doc/html/boost_asio/reference/basic_raw_socket/open.html +/doc/html/boost_asio/reference/basic_raw_socket/open/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/open/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/operator_eq_/ +/doc/html/boost_asio/reference/basic_raw_socket/operator_eq_.html +/doc/html/boost_asio/reference/basic_raw_socket/operator_eq_/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/operator_eq_/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/protocol_type.html +/doc/html/boost_asio/reference/basic_raw_socket/receive/ +/doc/html/boost_asio/reference/basic_raw_socket/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_raw_socket/receive_from/ +/doc/html/boost_asio/reference/basic_raw_socket/receive_from.html +/doc/html/boost_asio/reference/basic_raw_socket/receive_from/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/receive_from/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/receive_from/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/receive.html +/doc/html/boost_asio/reference/basic_raw_socket/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_raw_socket/receive/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/receive/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/receive/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/remote_endpoint/ +/doc/html/boost_asio/reference/basic_raw_socket/remote_endpoint.html +/doc/html/boost_asio/reference/basic_raw_socket/remote_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/remote_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/reuse_address.html +/doc/html/boost_asio/reference/basic_raw_socket/send/ +/doc/html/boost_asio/reference/basic_raw_socket/send_buffer_size.html +/doc/html/boost_asio/reference/basic_raw_socket/send.html +/doc/html/boost_asio/reference/basic_raw_socket/send_low_watermark.html +/doc/html/boost_asio/reference/basic_raw_socket/send/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/send/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/send/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/send_to/ +/doc/html/boost_asio/reference/basic_raw_socket/send_to.html +/doc/html/boost_asio/reference/basic_raw_socket/send_to/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/send_to/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/send_to/overload3.html +/doc/html/boost_asio/reference/basic_raw_socket/service.html +/doc/html/boost_asio/reference/basic_raw_socket/service_type.html +/doc/html/boost_asio/reference/basic_raw_socket/set_option/ +/doc/html/boost_asio/reference/basic_raw_socket/set_option.html +/doc/html/boost_asio/reference/basic_raw_socket/set_option/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/set_option/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/shutdown/ +/doc/html/boost_asio/reference/basic_raw_socket/shutdown.html +/doc/html/boost_asio/reference/basic_raw_socket/shutdown/overload1.html +/doc/html/boost_asio/reference/basic_raw_socket/shutdown/overload2.html +/doc/html/boost_asio/reference/basic_raw_socket/shutdown_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/assign/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/assign.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/assign/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/assign/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/async_connect.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/async_receive/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/async_receive.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/async_receive/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/async_receive/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/async_send.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/at_mark/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/at_mark.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/at_mark/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/at_mark/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/available/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/available.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/available/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/available/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload3.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload4.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload5.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/basic_seq_packet_socket/overload6.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/bind/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/bind.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/bind/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/bind/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/broadcast.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/bytes_readable.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/cancel/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/cancel.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/cancel/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/cancel/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/close/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/close.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/close/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/close/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/connect/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/connect.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/connect/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/connect/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/debug.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/do_not_route.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/endpoint_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_implementation/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_implementation.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_io_service.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_option/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_option.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_option/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_option/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_service/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_service.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_service/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/get_service/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/implementation.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/implementation_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/io_control/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/io_control.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/io_control/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/io_control/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/is_open.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/keep_alive.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/linger.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/local_endpoint/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/local_endpoint.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/lowest_layer/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/lowest_layer.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/max_connections.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/message_do_not_route.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/message_end_of_record.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/message_flags.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/message_out_of_band.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/message_peek.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_handle.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_handle_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_non_blocking/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_non_blocking.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/native_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/non_blocking/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/non_blocking.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/non_blocking_io.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/open/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/open.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/open/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/open/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/operator_eq_/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/operator_eq_.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/operator_eq_/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/operator_eq_/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/protocol_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/receive/overload3.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/remote_endpoint/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/remote_endpoint.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/remote_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/remote_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/reuse_address.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/send/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/send_buffer_size.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/send.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/send_low_watermark.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/send/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/send/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/service.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/service_type.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/set_option/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/set_option.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/set_option/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/set_option/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/shutdown/ +/doc/html/boost_asio/reference/basic_seq_packet_socket/shutdown.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/shutdown/overload1.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/shutdown/overload2.html +/doc/html/boost_asio/reference/basic_seq_packet_socket/shutdown_type.html +/doc/html/boost_asio/reference/basic_serial_port/ +/doc/html/boost_asio/reference/basic_serial_port/assign/ +/doc/html/boost_asio/reference/basic_serial_port/assign.html +/doc/html/boost_asio/reference/basic_serial_port/assign/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/assign/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/async_read_some.html +/doc/html/boost_asio/reference/basic_serial_port/async_write_some.html +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port/ +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port.html +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port/overload3.html +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port/overload4.html +/doc/html/boost_asio/reference/basic_serial_port/basic_serial_port/overload5.html +/doc/html/boost_asio/reference/basic_serial_port/cancel/ +/doc/html/boost_asio/reference/basic_serial_port/cancel.html +/doc/html/boost_asio/reference/basic_serial_port/cancel/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/cancel/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/close/ +/doc/html/boost_asio/reference/basic_serial_port/close.html +/doc/html/boost_asio/reference/basic_serial_port/close/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/close/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/get_implementation/ +/doc/html/boost_asio/reference/basic_serial_port/get_implementation.html +/doc/html/boost_asio/reference/basic_serial_port/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/get_io_service.html +/doc/html/boost_asio/reference/basic_serial_port/get_option/ +/doc/html/boost_asio/reference/basic_serial_port/get_option.html +/doc/html/boost_asio/reference/basic_serial_port/get_option/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/get_option/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/get_service/ +/doc/html/boost_asio/reference/basic_serial_port/get_service.html +/doc/html/boost_asio/reference/basic_serial_port/get_service/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/get_service/overload2.html +/doc/html/boost_asio/reference/basic_serial_port.html +/doc/html/boost_asio/reference/basic_serial_port/implementation.html +/doc/html/boost_asio/reference/basic_serial_port/implementation_type.html +/doc/html/boost_asio/reference/basic_serial_port/is_open.html +/doc/html/boost_asio/reference/basic_serial_port/lowest_layer/ +/doc/html/boost_asio/reference/basic_serial_port/lowest_layer.html +/doc/html/boost_asio/reference/basic_serial_port/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_serial_port/native_handle.html +/doc/html/boost_asio/reference/basic_serial_port/native_handle_type.html +/doc/html/boost_asio/reference/basic_serial_port/native.html +/doc/html/boost_asio/reference/basic_serial_port/native_type.html +/doc/html/boost_asio/reference/basic_serial_port/open/ +/doc/html/boost_asio/reference/basic_serial_port/open.html +/doc/html/boost_asio/reference/basic_serial_port/open/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/open/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/operator_eq_.html +/doc/html/boost_asio/reference/basic_serial_port/read_some/ +/doc/html/boost_asio/reference/basic_serial_port/read_some.html +/doc/html/boost_asio/reference/basic_serial_port/read_some/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/read_some/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/send_break/ +/doc/html/boost_asio/reference/basic_serial_port/send_break.html +/doc/html/boost_asio/reference/basic_serial_port/send_break/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/send_break/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/service.html +/doc/html/boost_asio/reference/basic_serial_port/service_type.html +/doc/html/boost_asio/reference/basic_serial_port/set_option/ +/doc/html/boost_asio/reference/basic_serial_port/set_option.html +/doc/html/boost_asio/reference/basic_serial_port/set_option/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/set_option/overload2.html +/doc/html/boost_asio/reference/basic_serial_port/write_some/ +/doc/html/boost_asio/reference/basic_serial_port/write_some.html +/doc/html/boost_asio/reference/basic_serial_port/write_some/overload1.html +/doc/html/boost_asio/reference/basic_serial_port/write_some/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/ +/doc/html/boost_asio/reference/basic_signal_set/add/ +/doc/html/boost_asio/reference/basic_signal_set/add.html +/doc/html/boost_asio/reference/basic_signal_set/add/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/add/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/async_wait.html +/doc/html/boost_asio/reference/basic_signal_set/basic_signal_set/ +/doc/html/boost_asio/reference/basic_signal_set/basic_signal_set.html +/doc/html/boost_asio/reference/basic_signal_set/basic_signal_set/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/basic_signal_set/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/basic_signal_set/overload3.html +/doc/html/boost_asio/reference/basic_signal_set/basic_signal_set/overload4.html +/doc/html/boost_asio/reference/basic_signal_set/cancel/ +/doc/html/boost_asio/reference/basic_signal_set/cancel.html +/doc/html/boost_asio/reference/basic_signal_set/cancel/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/cancel/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/clear/ +/doc/html/boost_asio/reference/basic_signal_set/clear.html +/doc/html/boost_asio/reference/basic_signal_set/clear/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/clear/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/get_implementation/ +/doc/html/boost_asio/reference/basic_signal_set/get_implementation.html +/doc/html/boost_asio/reference/basic_signal_set/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/get_io_service.html +/doc/html/boost_asio/reference/basic_signal_set/get_service/ +/doc/html/boost_asio/reference/basic_signal_set/get_service.html +/doc/html/boost_asio/reference/basic_signal_set/get_service/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/get_service/overload2.html +/doc/html/boost_asio/reference/basic_signal_set.html +/doc/html/boost_asio/reference/basic_signal_set/implementation.html +/doc/html/boost_asio/reference/basic_signal_set/implementation_type.html +/doc/html/boost_asio/reference/basic_signal_set/remove/ +/doc/html/boost_asio/reference/basic_signal_set/remove.html +/doc/html/boost_asio/reference/basic_signal_set/remove/overload1.html +/doc/html/boost_asio/reference/basic_signal_set/remove/overload2.html +/doc/html/boost_asio/reference/basic_signal_set/service.html +/doc/html/boost_asio/reference/basic_signal_set/service_type.html +/doc/html/boost_asio/reference/basic_socket/ +/doc/html/boost_asio/reference/basic_socket_acceptor/ +/doc/html/boost_asio/reference/basic_socket_acceptor/accept/ +/doc/html/boost_asio/reference/basic_socket_acceptor/accept.html +/doc/html/boost_asio/reference/basic_socket_acceptor/accept/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/accept/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/accept/overload3.html +/doc/html/boost_asio/reference/basic_socket_acceptor/accept/overload4.html +/doc/html/boost_asio/reference/basic_socket_acceptor/assign/ +/doc/html/boost_asio/reference/basic_socket_acceptor/assign.html +/doc/html/boost_asio/reference/basic_socket_acceptor/assign/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/assign/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/ +/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html +/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/ +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload3.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload4.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload5.html +/doc/html/boost_asio/reference/basic_socket_acceptor/basic_socket_acceptor/overload6.html +/doc/html/boost_asio/reference/basic_socket_acceptor/bind/ +/doc/html/boost_asio/reference/basic_socket_acceptor/bind.html +/doc/html/boost_asio/reference/basic_socket_acceptor/bind/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/bind/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/broadcast.html +/doc/html/boost_asio/reference/basic_socket_acceptor/bytes_readable.html +/doc/html/boost_asio/reference/basic_socket_acceptor/cancel/ +/doc/html/boost_asio/reference/basic_socket_acceptor/cancel.html +/doc/html/boost_asio/reference/basic_socket_acceptor/cancel/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/cancel/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/close/ +/doc/html/boost_asio/reference/basic_socket_acceptor/close.html +/doc/html/boost_asio/reference/basic_socket_acceptor/close/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/close/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/debug.html +/doc/html/boost_asio/reference/basic_socket_acceptor/do_not_route.html +/doc/html/boost_asio/reference/basic_socket_acceptor/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_socket_acceptor/endpoint_type.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_implementation/ +/doc/html/boost_asio/reference/basic_socket_acceptor/get_implementation.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_io_service.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_option/ +/doc/html/boost_asio/reference/basic_socket_acceptor/get_option.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_option/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_option/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_service/ +/doc/html/boost_asio/reference/basic_socket_acceptor/get_service.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_service/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/get_service/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor.html +/doc/html/boost_asio/reference/basic_socket_acceptor/implementation.html +/doc/html/boost_asio/reference/basic_socket_acceptor/implementation_type.html +/doc/html/boost_asio/reference/basic_socket_acceptor/io_control/ +/doc/html/boost_asio/reference/basic_socket_acceptor/io_control.html +/doc/html/boost_asio/reference/basic_socket_acceptor/io_control/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/io_control/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/is_open.html +/doc/html/boost_asio/reference/basic_socket_acceptor/keep_alive.html +/doc/html/boost_asio/reference/basic_socket_acceptor/linger.html +/doc/html/boost_asio/reference/basic_socket_acceptor/listen/ +/doc/html/boost_asio/reference/basic_socket_acceptor/listen.html +/doc/html/boost_asio/reference/basic_socket_acceptor/listen/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/listen/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/local_endpoint/ +/doc/html/boost_asio/reference/basic_socket_acceptor/local_endpoint.html +/doc/html/boost_asio/reference/basic_socket_acceptor/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/max_connections.html +/doc/html/boost_asio/reference/basic_socket_acceptor/message_do_not_route.html +/doc/html/boost_asio/reference/basic_socket_acceptor/message_end_of_record.html +/doc/html/boost_asio/reference/basic_socket_acceptor/message_flags.html +/doc/html/boost_asio/reference/basic_socket_acceptor/message_out_of_band.html +/doc/html/boost_asio/reference/basic_socket_acceptor/message_peek.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_handle.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_handle_type.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_non_blocking/ +/doc/html/boost_asio/reference/basic_socket_acceptor/native_non_blocking.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_socket_acceptor/native_type.html +/doc/html/boost_asio/reference/basic_socket_acceptor/non_blocking/ +/doc/html/boost_asio/reference/basic_socket_acceptor/non_blocking.html +/doc/html/boost_asio/reference/basic_socket_acceptor/non_blocking_io.html +/doc/html/boost_asio/reference/basic_socket_acceptor/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_socket_acceptor/open/ +/doc/html/boost_asio/reference/basic_socket_acceptor/open.html +/doc/html/boost_asio/reference/basic_socket_acceptor/open/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/open/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/operator_eq_/ +/doc/html/boost_asio/reference/basic_socket_acceptor/operator_eq_.html +/doc/html/boost_asio/reference/basic_socket_acceptor/operator_eq_/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/operator_eq_/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/protocol_type.html +/doc/html/boost_asio/reference/basic_socket_acceptor/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_socket_acceptor/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_socket_acceptor/reuse_address.html +/doc/html/boost_asio/reference/basic_socket_acceptor/send_buffer_size.html +/doc/html/boost_asio/reference/basic_socket_acceptor/send_low_watermark.html +/doc/html/boost_asio/reference/basic_socket_acceptor/service.html +/doc/html/boost_asio/reference/basic_socket_acceptor/service_type.html +/doc/html/boost_asio/reference/basic_socket_acceptor/set_option/ +/doc/html/boost_asio/reference/basic_socket_acceptor/set_option.html +/doc/html/boost_asio/reference/basic_socket_acceptor/set_option/overload1.html +/doc/html/boost_asio/reference/basic_socket_acceptor/set_option/overload2.html +/doc/html/boost_asio/reference/basic_socket_acceptor/shutdown_type.html +/doc/html/boost_asio/reference/basic_socket/assign/ +/doc/html/boost_asio/reference/basic_socket/assign.html +/doc/html/boost_asio/reference/basic_socket/assign/overload1.html +/doc/html/boost_asio/reference/basic_socket/assign/overload2.html +/doc/html/boost_asio/reference/basic_socket/async_connect.html +/doc/html/boost_asio/reference/basic_socket/at_mark/ +/doc/html/boost_asio/reference/basic_socket/at_mark.html +/doc/html/boost_asio/reference/basic_socket/at_mark/overload1.html +/doc/html/boost_asio/reference/basic_socket/at_mark/overload2.html +/doc/html/boost_asio/reference/basic_socket/available/ +/doc/html/boost_asio/reference/basic_socket/available.html +/doc/html/boost_asio/reference/basic_socket/available/overload1.html +/doc/html/boost_asio/reference/basic_socket/available/overload2.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/ +/doc/html/boost_asio/reference/basic_socket/_basic_socket.html +/doc/html/boost_asio/reference/basic_socket/basic_socket.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/overload1.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/overload2.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/overload3.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/overload4.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/overload5.html +/doc/html/boost_asio/reference/basic_socket/basic_socket/overload6.html +/doc/html/boost_asio/reference/basic_socket/bind/ +/doc/html/boost_asio/reference/basic_socket/bind.html +/doc/html/boost_asio/reference/basic_socket/bind/overload1.html +/doc/html/boost_asio/reference/basic_socket/bind/overload2.html +/doc/html/boost_asio/reference/basic_socket/broadcast.html +/doc/html/boost_asio/reference/basic_socket/bytes_readable.html +/doc/html/boost_asio/reference/basic_socket/cancel/ +/doc/html/boost_asio/reference/basic_socket/cancel.html +/doc/html/boost_asio/reference/basic_socket/cancel/overload1.html +/doc/html/boost_asio/reference/basic_socket/cancel/overload2.html +/doc/html/boost_asio/reference/basic_socket/close/ +/doc/html/boost_asio/reference/basic_socket/close.html +/doc/html/boost_asio/reference/basic_socket/close/overload1.html +/doc/html/boost_asio/reference/basic_socket/close/overload2.html +/doc/html/boost_asio/reference/basic_socket/connect/ +/doc/html/boost_asio/reference/basic_socket/connect.html +/doc/html/boost_asio/reference/basic_socket/connect/overload1.html +/doc/html/boost_asio/reference/basic_socket/connect/overload2.html +/doc/html/boost_asio/reference/basic_socket/debug.html +/doc/html/boost_asio/reference/basic_socket/do_not_route.html +/doc/html/boost_asio/reference/basic_socket/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_socket/endpoint_type.html +/doc/html/boost_asio/reference/basic_socket/get_implementation/ +/doc/html/boost_asio/reference/basic_socket/get_implementation.html +/doc/html/boost_asio/reference/basic_socket/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_socket/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_socket/get_io_service.html +/doc/html/boost_asio/reference/basic_socket/get_option/ +/doc/html/boost_asio/reference/basic_socket/get_option.html +/doc/html/boost_asio/reference/basic_socket/get_option/overload1.html +/doc/html/boost_asio/reference/basic_socket/get_option/overload2.html +/doc/html/boost_asio/reference/basic_socket/get_service/ +/doc/html/boost_asio/reference/basic_socket/get_service.html +/doc/html/boost_asio/reference/basic_socket/get_service/overload1.html +/doc/html/boost_asio/reference/basic_socket/get_service/overload2.html +/doc/html/boost_asio/reference/basic_socket.html +/doc/html/boost_asio/reference/basic_socket/implementation.html +/doc/html/boost_asio/reference/basic_socket/implementation_type.html +/doc/html/boost_asio/reference/basic_socket/io_control/ +/doc/html/boost_asio/reference/basic_socket/io_control.html +/doc/html/boost_asio/reference/basic_socket/io_control/overload1.html +/doc/html/boost_asio/reference/basic_socket/io_control/overload2.html +/doc/html/boost_asio/reference/basic_socket_iostream/ +/doc/html/boost_asio/reference/basic_socket_iostream/basic_socket_iostream/ +/doc/html/boost_asio/reference/basic_socket_iostream/basic_socket_iostream.html +/doc/html/boost_asio/reference/basic_socket_iostream/basic_socket_iostream/overload1.html +/doc/html/boost_asio/reference/basic_socket_iostream/basic_socket_iostream/overload2.html +/doc/html/boost_asio/reference/basic_socket_iostream/close.html +/doc/html/boost_asio/reference/basic_socket_iostream/connect.html +/doc/html/boost_asio/reference/basic_socket_iostream/duration_type.html +/doc/html/boost_asio/reference/basic_socket_iostream/endpoint_type.html +/doc/html/boost_asio/reference/basic_socket_iostream/error.html +/doc/html/boost_asio/reference/basic_socket_iostream/expires_at/ +/doc/html/boost_asio/reference/basic_socket_iostream/expires_at.html +/doc/html/boost_asio/reference/basic_socket_iostream/expires_at/overload1.html +/doc/html/boost_asio/reference/basic_socket_iostream/expires_at/overload2.html +/doc/html/boost_asio/reference/basic_socket_iostream/expires_from_now/ +/doc/html/boost_asio/reference/basic_socket_iostream/expires_from_now.html +/doc/html/boost_asio/reference/basic_socket_iostream/expires_from_now/overload1.html +/doc/html/boost_asio/reference/basic_socket_iostream/expires_from_now/overload2.html +/doc/html/boost_asio/reference/basic_socket_iostream.html +/doc/html/boost_asio/reference/basic_socket_iostream/rdbuf.html +/doc/html/boost_asio/reference/basic_socket_iostream/time_type.html +/doc/html/boost_asio/reference/basic_socket/is_open.html +/doc/html/boost_asio/reference/basic_socket/keep_alive.html +/doc/html/boost_asio/reference/basic_socket/linger.html +/doc/html/boost_asio/reference/basic_socket/local_endpoint/ +/doc/html/boost_asio/reference/basic_socket/local_endpoint.html +/doc/html/boost_asio/reference/basic_socket/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_socket/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_socket/lowest_layer/ +/doc/html/boost_asio/reference/basic_socket/lowest_layer.html +/doc/html/boost_asio/reference/basic_socket/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_socket/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_socket/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_socket/max_connections.html +/doc/html/boost_asio/reference/basic_socket/message_do_not_route.html +/doc/html/boost_asio/reference/basic_socket/message_end_of_record.html +/doc/html/boost_asio/reference/basic_socket/message_flags.html +/doc/html/boost_asio/reference/basic_socket/message_out_of_band.html +/doc/html/boost_asio/reference/basic_socket/message_peek.html +/doc/html/boost_asio/reference/basic_socket/native_handle.html +/doc/html/boost_asio/reference/basic_socket/native_handle_type.html +/doc/html/boost_asio/reference/basic_socket/native.html +/doc/html/boost_asio/reference/basic_socket/native_non_blocking/ +/doc/html/boost_asio/reference/basic_socket/native_non_blocking.html +/doc/html/boost_asio/reference/basic_socket/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_socket/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_socket/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_socket/native_type.html +/doc/html/boost_asio/reference/basic_socket/non_blocking/ +/doc/html/boost_asio/reference/basic_socket/non_blocking.html +/doc/html/boost_asio/reference/basic_socket/non_blocking_io.html +/doc/html/boost_asio/reference/basic_socket/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_socket/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_socket/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_socket/open/ +/doc/html/boost_asio/reference/basic_socket/open.html +/doc/html/boost_asio/reference/basic_socket/open/overload1.html +/doc/html/boost_asio/reference/basic_socket/open/overload2.html +/doc/html/boost_asio/reference/basic_socket/operator_eq_/ +/doc/html/boost_asio/reference/basic_socket/operator_eq_.html +/doc/html/boost_asio/reference/basic_socket/operator_eq_/overload1.html +/doc/html/boost_asio/reference/basic_socket/operator_eq_/overload2.html +/doc/html/boost_asio/reference/basic_socket/protocol_type.html +/doc/html/boost_asio/reference/basic_socket/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_socket/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_socket/remote_endpoint/ +/doc/html/boost_asio/reference/basic_socket/remote_endpoint.html +/doc/html/boost_asio/reference/basic_socket/remote_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_socket/remote_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_socket/reuse_address.html +/doc/html/boost_asio/reference/basic_socket/send_buffer_size.html +/doc/html/boost_asio/reference/basic_socket/send_low_watermark.html +/doc/html/boost_asio/reference/basic_socket/service.html +/doc/html/boost_asio/reference/basic_socket/service_type.html +/doc/html/boost_asio/reference/basic_socket/set_option/ +/doc/html/boost_asio/reference/basic_socket/set_option.html +/doc/html/boost_asio/reference/basic_socket/set_option/overload1.html +/doc/html/boost_asio/reference/basic_socket/set_option/overload2.html +/doc/html/boost_asio/reference/basic_socket/shutdown/ +/doc/html/boost_asio/reference/basic_socket/shutdown.html +/doc/html/boost_asio/reference/basic_socket/shutdown/overload1.html +/doc/html/boost_asio/reference/basic_socket/shutdown/overload2.html +/doc/html/boost_asio/reference/basic_socket/shutdown_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/ +/doc/html/boost_asio/reference/basic_socket_streambuf/assign/ +/doc/html/boost_asio/reference/basic_socket_streambuf/assign.html +/doc/html/boost_asio/reference/basic_socket_streambuf/assign/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/assign/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/async_connect.html +/doc/html/boost_asio/reference/basic_socket_streambuf/at_mark/ +/doc/html/boost_asio/reference/basic_socket_streambuf/at_mark.html +/doc/html/boost_asio/reference/basic_socket_streambuf/at_mark/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/at_mark/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/available/ +/doc/html/boost_asio/reference/basic_socket_streambuf/available.html +/doc/html/boost_asio/reference/basic_socket_streambuf/available/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/available/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/_basic_socket_streambuf.html +/doc/html/boost_asio/reference/basic_socket_streambuf/basic_socket_streambuf.html +/doc/html/boost_asio/reference/basic_socket_streambuf/bind/ +/doc/html/boost_asio/reference/basic_socket_streambuf/bind.html +/doc/html/boost_asio/reference/basic_socket_streambuf/bind/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/bind/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/broadcast.html +/doc/html/boost_asio/reference/basic_socket_streambuf/bytes_readable.html +/doc/html/boost_asio/reference/basic_socket_streambuf/cancel/ +/doc/html/boost_asio/reference/basic_socket_streambuf/cancel.html +/doc/html/boost_asio/reference/basic_socket_streambuf/cancel/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/cancel/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/close/ +/doc/html/boost_asio/reference/basic_socket_streambuf/close.html +/doc/html/boost_asio/reference/basic_socket_streambuf/close/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/close/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/connect/ +/doc/html/boost_asio/reference/basic_socket_streambuf/connect.html +/doc/html/boost_asio/reference/basic_socket_streambuf/connect/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/connect/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/connect/overload3.html +/doc/html/boost_asio/reference/basic_socket_streambuf/debug.html +/doc/html/boost_asio/reference/basic_socket_streambuf/do_not_route.html +/doc/html/boost_asio/reference/basic_socket_streambuf/duration_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_socket_streambuf/endpoint_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/error.html +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_at/ +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_at.html +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_at/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_at/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_from_now/ +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_from_now.html +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_from_now/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/expires_from_now/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_implementation/ +/doc/html/boost_asio/reference/basic_socket_streambuf/get_implementation.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_io_service.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_option/ +/doc/html/boost_asio/reference/basic_socket_streambuf/get_option.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_option/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_option/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_service/ +/doc/html/boost_asio/reference/basic_socket_streambuf/get_service.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_service/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/get_service/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf.html +/doc/html/boost_asio/reference/basic_socket_streambuf/implementation.html +/doc/html/boost_asio/reference/basic_socket_streambuf/implementation_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/io_control/ +/doc/html/boost_asio/reference/basic_socket_streambuf/io_control.html +/doc/html/boost_asio/reference/basic_socket_streambuf/io_control/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/io_control/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/io_handler.html +/doc/html/boost_asio/reference/basic_socket_streambuf/is_open.html +/doc/html/boost_asio/reference/basic_socket_streambuf/keep_alive.html +/doc/html/boost_asio/reference/basic_socket_streambuf/linger.html +/doc/html/boost_asio/reference/basic_socket_streambuf/local_endpoint/ +/doc/html/boost_asio/reference/basic_socket_streambuf/local_endpoint.html +/doc/html/boost_asio/reference/basic_socket_streambuf/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/lowest_layer/ +/doc/html/boost_asio/reference/basic_socket_streambuf/lowest_layer.html +/doc/html/boost_asio/reference/basic_socket_streambuf/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/max_connections.html +/doc/html/boost_asio/reference/basic_socket_streambuf/message_do_not_route.html +/doc/html/boost_asio/reference/basic_socket_streambuf/message_end_of_record.html +/doc/html/boost_asio/reference/basic_socket_streambuf/message_flags.html +/doc/html/boost_asio/reference/basic_socket_streambuf/message_out_of_band.html +/doc/html/boost_asio/reference/basic_socket_streambuf/message_peek.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_handle.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_handle_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_non_blocking/ +/doc/html/boost_asio/reference/basic_socket_streambuf/native_non_blocking.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_socket_streambuf/native_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/non_blocking/ +/doc/html/boost_asio/reference/basic_socket_streambuf/non_blocking.html +/doc/html/boost_asio/reference/basic_socket_streambuf/non_blocking_io.html +/doc/html/boost_asio/reference/basic_socket_streambuf/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_socket_streambuf/open/ +/doc/html/boost_asio/reference/basic_socket_streambuf/open.html +/doc/html/boost_asio/reference/basic_socket_streambuf/open/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/open/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/overflow.html +/doc/html/boost_asio/reference/basic_socket_streambuf/protocol_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/puberror.html +/doc/html/boost_asio/reference/basic_socket_streambuf/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_socket_streambuf/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_socket_streambuf/remote_endpoint/ +/doc/html/boost_asio/reference/basic_socket_streambuf/remote_endpoint.html +/doc/html/boost_asio/reference/basic_socket_streambuf/remote_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/remote_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/reuse_address.html +/doc/html/boost_asio/reference/basic_socket_streambuf/send_buffer_size.html +/doc/html/boost_asio/reference/basic_socket_streambuf/send_low_watermark.html +/doc/html/boost_asio/reference/basic_socket_streambuf/service.html +/doc/html/boost_asio/reference/basic_socket_streambuf/service_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/setbuf.html +/doc/html/boost_asio/reference/basic_socket_streambuf/set_option/ +/doc/html/boost_asio/reference/basic_socket_streambuf/set_option.html +/doc/html/boost_asio/reference/basic_socket_streambuf/set_option/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/set_option/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/shutdown/ +/doc/html/boost_asio/reference/basic_socket_streambuf/shutdown.html +/doc/html/boost_asio/reference/basic_socket_streambuf/shutdown/overload1.html +/doc/html/boost_asio/reference/basic_socket_streambuf/shutdown/overload2.html +/doc/html/boost_asio/reference/basic_socket_streambuf/shutdown_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/sync.html +/doc/html/boost_asio/reference/basic_socket_streambuf/timer_handler.html +/doc/html/boost_asio/reference/basic_socket_streambuf/time_type.html +/doc/html/boost_asio/reference/basic_socket_streambuf/underflow.html +/doc/html/boost_asio/reference/basic_streambuf/ +/doc/html/boost_asio/reference/basic_streambuf/basic_streambuf.html +/doc/html/boost_asio/reference/basic_streambuf/commit.html +/doc/html/boost_asio/reference/basic_streambuf/const_buffers_type.html +/doc/html/boost_asio/reference/basic_streambuf/consume.html +/doc/html/boost_asio/reference/basic_streambuf/data.html +/doc/html/boost_asio/reference/basic_streambuf.html +/doc/html/boost_asio/reference/basic_streambuf/max_size.html +/doc/html/boost_asio/reference/basic_streambuf/mutable_buffers_type.html +/doc/html/boost_asio/reference/basic_streambuf/overflow.html +/doc/html/boost_asio/reference/basic_streambuf/prepare.html +/doc/html/boost_asio/reference/basic_streambuf/reserve.html +/doc/html/boost_asio/reference/basic_streambuf/size.html +/doc/html/boost_asio/reference/basic_streambuf/underflow.html +/doc/html/boost_asio/reference/basic_stream_socket/ +/doc/html/boost_asio/reference/basic_stream_socket/assign/ +/doc/html/boost_asio/reference/basic_stream_socket/assign.html +/doc/html/boost_asio/reference/basic_stream_socket/assign/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/assign/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/async_connect.html +/doc/html/boost_asio/reference/basic_stream_socket/async_read_some.html +/doc/html/boost_asio/reference/basic_stream_socket/async_receive/ +/doc/html/boost_asio/reference/basic_stream_socket/async_receive.html +/doc/html/boost_asio/reference/basic_stream_socket/async_receive/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/async_receive/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/async_send/ +/doc/html/boost_asio/reference/basic_stream_socket/async_send.html +/doc/html/boost_asio/reference/basic_stream_socket/async_send/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/async_send/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/async_write_some.html +/doc/html/boost_asio/reference/basic_stream_socket/at_mark/ +/doc/html/boost_asio/reference/basic_stream_socket/at_mark.html +/doc/html/boost_asio/reference/basic_stream_socket/at_mark/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/at_mark/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/available/ +/doc/html/boost_asio/reference/basic_stream_socket/available.html +/doc/html/boost_asio/reference/basic_stream_socket/available/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/available/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/ +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload3.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload4.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload5.html +/doc/html/boost_asio/reference/basic_stream_socket/basic_stream_socket/overload6.html +/doc/html/boost_asio/reference/basic_stream_socket/bind/ +/doc/html/boost_asio/reference/basic_stream_socket/bind.html +/doc/html/boost_asio/reference/basic_stream_socket/bind/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/bind/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/broadcast.html +/doc/html/boost_asio/reference/basic_stream_socket/bytes_readable.html +/doc/html/boost_asio/reference/basic_stream_socket/cancel/ +/doc/html/boost_asio/reference/basic_stream_socket/cancel.html +/doc/html/boost_asio/reference/basic_stream_socket/cancel/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/cancel/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/close/ +/doc/html/boost_asio/reference/basic_stream_socket/close.html +/doc/html/boost_asio/reference/basic_stream_socket/close/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/close/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/connect/ +/doc/html/boost_asio/reference/basic_stream_socket/connect.html +/doc/html/boost_asio/reference/basic_stream_socket/connect/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/connect/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/debug.html +/doc/html/boost_asio/reference/basic_stream_socket/do_not_route.html +/doc/html/boost_asio/reference/basic_stream_socket/enable_connection_aborted.html +/doc/html/boost_asio/reference/basic_stream_socket/endpoint_type.html +/doc/html/boost_asio/reference/basic_stream_socket/get_implementation/ +/doc/html/boost_asio/reference/basic_stream_socket/get_implementation.html +/doc/html/boost_asio/reference/basic_stream_socket/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/get_io_service.html +/doc/html/boost_asio/reference/basic_stream_socket/get_option/ +/doc/html/boost_asio/reference/basic_stream_socket/get_option.html +/doc/html/boost_asio/reference/basic_stream_socket/get_option/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/get_option/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/get_service/ +/doc/html/boost_asio/reference/basic_stream_socket/get_service.html +/doc/html/boost_asio/reference/basic_stream_socket/get_service/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/get_service/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket.html +/doc/html/boost_asio/reference/basic_stream_socket/implementation.html +/doc/html/boost_asio/reference/basic_stream_socket/implementation_type.html +/doc/html/boost_asio/reference/basic_stream_socket/io_control/ +/doc/html/boost_asio/reference/basic_stream_socket/io_control.html +/doc/html/boost_asio/reference/basic_stream_socket/io_control/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/io_control/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/is_open.html +/doc/html/boost_asio/reference/basic_stream_socket/keep_alive.html +/doc/html/boost_asio/reference/basic_stream_socket/linger.html +/doc/html/boost_asio/reference/basic_stream_socket/local_endpoint/ +/doc/html/boost_asio/reference/basic_stream_socket/local_endpoint.html +/doc/html/boost_asio/reference/basic_stream_socket/local_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/local_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/lowest_layer/ +/doc/html/boost_asio/reference/basic_stream_socket/lowest_layer.html +/doc/html/boost_asio/reference/basic_stream_socket/lowest_layer/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/lowest_layer/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/lowest_layer_type.html +/doc/html/boost_asio/reference/basic_stream_socket/max_connections.html +/doc/html/boost_asio/reference/basic_stream_socket/message_do_not_route.html +/doc/html/boost_asio/reference/basic_stream_socket/message_end_of_record.html +/doc/html/boost_asio/reference/basic_stream_socket/message_flags.html +/doc/html/boost_asio/reference/basic_stream_socket/message_out_of_band.html +/doc/html/boost_asio/reference/basic_stream_socket/message_peek.html +/doc/html/boost_asio/reference/basic_stream_socket/native_handle.html +/doc/html/boost_asio/reference/basic_stream_socket/native_handle_type.html +/doc/html/boost_asio/reference/basic_stream_socket/native.html +/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking/ +/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking.html +/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_stream_socket/native_type.html +/doc/html/boost_asio/reference/basic_stream_socket/non_blocking/ +/doc/html/boost_asio/reference/basic_stream_socket/non_blocking.html +/doc/html/boost_asio/reference/basic_stream_socket/non_blocking_io.html +/doc/html/boost_asio/reference/basic_stream_socket/non_blocking/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/non_blocking/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/non_blocking/overload3.html +/doc/html/boost_asio/reference/basic_stream_socket/open/ +/doc/html/boost_asio/reference/basic_stream_socket/open.html +/doc/html/boost_asio/reference/basic_stream_socket/open/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/open/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/operator_eq_/ +/doc/html/boost_asio/reference/basic_stream_socket/operator_eq_.html +/doc/html/boost_asio/reference/basic_stream_socket/operator_eq_/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/operator_eq_/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/protocol_type.html +/doc/html/boost_asio/reference/basic_stream_socket/read_some/ +/doc/html/boost_asio/reference/basic_stream_socket/read_some.html +/doc/html/boost_asio/reference/basic_stream_socket/read_some/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/read_some/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/receive/ +/doc/html/boost_asio/reference/basic_stream_socket/receive_buffer_size.html +/doc/html/boost_asio/reference/basic_stream_socket/receive.html +/doc/html/boost_asio/reference/basic_stream_socket/receive_low_watermark.html +/doc/html/boost_asio/reference/basic_stream_socket/receive/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/receive/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/receive/overload3.html +/doc/html/boost_asio/reference/basic_stream_socket/remote_endpoint/ +/doc/html/boost_asio/reference/basic_stream_socket/remote_endpoint.html +/doc/html/boost_asio/reference/basic_stream_socket/remote_endpoint/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/remote_endpoint/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/reuse_address.html +/doc/html/boost_asio/reference/basic_stream_socket/send/ +/doc/html/boost_asio/reference/basic_stream_socket/send_buffer_size.html +/doc/html/boost_asio/reference/basic_stream_socket/send.html +/doc/html/boost_asio/reference/basic_stream_socket/send_low_watermark.html +/doc/html/boost_asio/reference/basic_stream_socket/send/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/send/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/send/overload3.html +/doc/html/boost_asio/reference/basic_stream_socket/service.html +/doc/html/boost_asio/reference/basic_stream_socket/service_type.html +/doc/html/boost_asio/reference/basic_stream_socket/set_option/ +/doc/html/boost_asio/reference/basic_stream_socket/set_option.html +/doc/html/boost_asio/reference/basic_stream_socket/set_option/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/set_option/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/shutdown/ +/doc/html/boost_asio/reference/basic_stream_socket/shutdown.html +/doc/html/boost_asio/reference/basic_stream_socket/shutdown/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/shutdown/overload2.html +/doc/html/boost_asio/reference/basic_stream_socket/shutdown_type.html +/doc/html/boost_asio/reference/basic_stream_socket/write_some/ +/doc/html/boost_asio/reference/basic_stream_socket/write_some.html +/doc/html/boost_asio/reference/basic_stream_socket/write_some/overload1.html +/doc/html/boost_asio/reference/basic_stream_socket/write_some/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/ +/doc/html/boost_asio/reference/basic_waitable_timer/async_wait.html +/doc/html/boost_asio/reference/basic_waitable_timer/basic_waitable_timer/ +/doc/html/boost_asio/reference/basic_waitable_timer/basic_waitable_timer.html +/doc/html/boost_asio/reference/basic_waitable_timer/basic_waitable_timer/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/basic_waitable_timer/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/basic_waitable_timer/overload3.html +/doc/html/boost_asio/reference/basic_waitable_timer/cancel/ +/doc/html/boost_asio/reference/basic_waitable_timer/cancel.html +/doc/html/boost_asio/reference/basic_waitable_timer/cancel_one/ +/doc/html/boost_asio/reference/basic_waitable_timer/cancel_one.html +/doc/html/boost_asio/reference/basic_waitable_timer/cancel_one/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/cancel_one/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/cancel/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/cancel/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/clock_type.html +/doc/html/boost_asio/reference/basic_waitable_timer/duration.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_at/ +/doc/html/boost_asio/reference/basic_waitable_timer/expires_at.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_at/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_at/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_at/overload3.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_from_now/ +/doc/html/boost_asio/reference/basic_waitable_timer/expires_from_now.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_from_now/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_from_now/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/expires_from_now/overload3.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_implementation/ +/doc/html/boost_asio/reference/basic_waitable_timer/get_implementation.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_implementation/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_implementation/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_io_service.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_service/ +/doc/html/boost_asio/reference/basic_waitable_timer/get_service.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_service/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/get_service/overload2.html +/doc/html/boost_asio/reference/basic_waitable_timer.html +/doc/html/boost_asio/reference/basic_waitable_timer/implementation.html +/doc/html/boost_asio/reference/basic_waitable_timer/implementation_type.html +/doc/html/boost_asio/reference/basic_waitable_timer/service.html +/doc/html/boost_asio/reference/basic_waitable_timer/service_type.html +/doc/html/boost_asio/reference/basic_waitable_timer/time_point.html +/doc/html/boost_asio/reference/basic_waitable_timer/traits_type.html +/doc/html/boost_asio/reference/basic_waitable_timer/wait/ +/doc/html/boost_asio/reference/basic_waitable_timer/wait.html +/doc/html/boost_asio/reference/basic_waitable_timer/wait/overload1.html +/doc/html/boost_asio/reference/basic_waitable_timer/wait/overload2.html +/doc/html/boost_asio/reference/basic_yield_context/ +/doc/html/boost_asio/reference/basic_yield_context/basic_yield_context.html +/doc/html/boost_asio/reference/basic_yield_context/callee_type.html +/doc/html/boost_asio/reference/basic_yield_context/caller_type.html +/doc/html/boost_asio/reference/basic_yield_context.html +/doc/html/boost_asio/reference/basic_yield_context/operator_lb__rb_.html +/doc/html/boost_asio/reference/buffer/ +/doc/html/boost_asio/reference/buffer_cast/ +/doc/html/boost_asio/reference/buffer_cast.html +/doc/html/boost_asio/reference/buffer_cast/overload1.html +/doc/html/boost_asio/reference/buffer_cast/overload2.html +/doc/html/boost_asio/reference/buffer_copy/ +/doc/html/boost_asio/reference/buffer_copy.html +/doc/html/boost_asio/reference/buffer_copy/overload10.html +/doc/html/boost_asio/reference/buffer_copy/overload11.html +/doc/html/boost_asio/reference/buffer_copy/overload12.html +/doc/html/boost_asio/reference/buffer_copy/overload13.html +/doc/html/boost_asio/reference/buffer_copy/overload14.html +/doc/html/boost_asio/reference/buffer_copy/overload15.html +/doc/html/boost_asio/reference/buffer_copy/overload16.html +/doc/html/boost_asio/reference/buffer_copy/overload17.html +/doc/html/boost_asio/reference/buffer_copy/overload18.html +/doc/html/boost_asio/reference/buffer_copy/overload19.html +/doc/html/boost_asio/reference/buffer_copy/overload1.html +/doc/html/boost_asio/reference/buffer_copy/overload20.html +/doc/html/boost_asio/reference/buffer_copy/overload21.html +/doc/html/boost_asio/reference/buffer_copy/overload22.html +/doc/html/boost_asio/reference/buffer_copy/overload23.html +/doc/html/boost_asio/reference/buffer_copy/overload24.html +/doc/html/boost_asio/reference/buffer_copy/overload25.html +/doc/html/boost_asio/reference/buffer_copy/overload26.html +/doc/html/boost_asio/reference/buffer_copy/overload27.html +/doc/html/boost_asio/reference/buffer_copy/overload28.html +/doc/html/boost_asio/reference/buffer_copy/overload29.html +/doc/html/boost_asio/reference/buffer_copy/overload2.html +/doc/html/boost_asio/reference/buffer_copy/overload30.html +/doc/html/boost_asio/reference/buffer_copy/overload3.html +/doc/html/boost_asio/reference/buffer_copy/overload4.html +/doc/html/boost_asio/reference/buffer_copy/overload5.html +/doc/html/boost_asio/reference/buffer_copy/overload6.html +/doc/html/boost_asio/reference/buffer_copy/overload7.html +/doc/html/boost_asio/reference/buffer_copy/overload8.html +/doc/html/boost_asio/reference/buffer_copy/overload9.html +/doc/html/boost_asio/reference/BufferedHandshakeHandler.html +/doc/html/boost_asio/reference/buffered_read_stream/ +/doc/html/boost_asio/reference/buffered_read_stream/async_fill.html +/doc/html/boost_asio/reference/buffered_read_stream/async_read_some.html +/doc/html/boost_asio/reference/buffered_read_stream/async_write_some.html +/doc/html/boost_asio/reference/buffered_read_stream/buffered_read_stream/ +/doc/html/boost_asio/reference/buffered_read_stream/buffered_read_stream.html +/doc/html/boost_asio/reference/buffered_read_stream/buffered_read_stream/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/buffered_read_stream/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/close/ +/doc/html/boost_asio/reference/buffered_read_stream/close.html +/doc/html/boost_asio/reference/buffered_read_stream/close/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/close/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/default_buffer_size.html +/doc/html/boost_asio/reference/buffered_read_stream/fill/ +/doc/html/boost_asio/reference/buffered_read_stream/fill.html +/doc/html/boost_asio/reference/buffered_read_stream/fill/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/fill/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/get_io_service.html +/doc/html/boost_asio/reference/buffered_read_stream.html +/doc/html/boost_asio/reference/buffered_read_stream/in_avail/ +/doc/html/boost_asio/reference/buffered_read_stream/in_avail.html +/doc/html/boost_asio/reference/buffered_read_stream/in_avail/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/in_avail/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/lowest_layer/ +/doc/html/boost_asio/reference/buffered_read_stream/lowest_layer.html +/doc/html/boost_asio/reference/buffered_read_stream/lowest_layer/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/lowest_layer/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/lowest_layer_type.html +/doc/html/boost_asio/reference/buffered_read_stream/next_layer.html +/doc/html/boost_asio/reference/buffered_read_stream/next_layer_type.html +/doc/html/boost_asio/reference/buffered_read_stream/peek/ +/doc/html/boost_asio/reference/buffered_read_stream/peek.html +/doc/html/boost_asio/reference/buffered_read_stream/peek/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/peek/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/read_some/ +/doc/html/boost_asio/reference/buffered_read_stream/read_some.html +/doc/html/boost_asio/reference/buffered_read_stream/read_some/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/read_some/overload2.html +/doc/html/boost_asio/reference/buffered_read_stream/write_some/ +/doc/html/boost_asio/reference/buffered_read_stream/write_some.html +/doc/html/boost_asio/reference/buffered_read_stream/write_some/overload1.html +/doc/html/boost_asio/reference/buffered_read_stream/write_some/overload2.html +/doc/html/boost_asio/reference/buffered_stream/ +/doc/html/boost_asio/reference/buffered_stream/async_fill.html +/doc/html/boost_asio/reference/buffered_stream/async_flush.html +/doc/html/boost_asio/reference/buffered_stream/async_read_some.html +/doc/html/boost_asio/reference/buffered_stream/async_write_some.html +/doc/html/boost_asio/reference/buffered_stream/buffered_stream/ +/doc/html/boost_asio/reference/buffered_stream/buffered_stream.html +/doc/html/boost_asio/reference/buffered_stream/buffered_stream/overload1.html +/doc/html/boost_asio/reference/buffered_stream/buffered_stream/overload2.html +/doc/html/boost_asio/reference/buffered_stream/close/ +/doc/html/boost_asio/reference/buffered_stream/close.html +/doc/html/boost_asio/reference/buffered_stream/close/overload1.html +/doc/html/boost_asio/reference/buffered_stream/close/overload2.html +/doc/html/boost_asio/reference/buffered_stream/fill/ +/doc/html/boost_asio/reference/buffered_stream/fill.html +/doc/html/boost_asio/reference/buffered_stream/fill/overload1.html +/doc/html/boost_asio/reference/buffered_stream/fill/overload2.html +/doc/html/boost_asio/reference/buffered_stream/flush/ +/doc/html/boost_asio/reference/buffered_stream/flush.html +/doc/html/boost_asio/reference/buffered_stream/flush/overload1.html +/doc/html/boost_asio/reference/buffered_stream/flush/overload2.html +/doc/html/boost_asio/reference/buffered_stream/get_io_service.html +/doc/html/boost_asio/reference/buffered_stream.html +/doc/html/boost_asio/reference/buffered_stream/in_avail/ +/doc/html/boost_asio/reference/buffered_stream/in_avail.html +/doc/html/boost_asio/reference/buffered_stream/in_avail/overload1.html +/doc/html/boost_asio/reference/buffered_stream/in_avail/overload2.html +/doc/html/boost_asio/reference/buffered_stream/lowest_layer/ +/doc/html/boost_asio/reference/buffered_stream/lowest_layer.html +/doc/html/boost_asio/reference/buffered_stream/lowest_layer/overload1.html +/doc/html/boost_asio/reference/buffered_stream/lowest_layer/overload2.html +/doc/html/boost_asio/reference/buffered_stream/lowest_layer_type.html +/doc/html/boost_asio/reference/buffered_stream/next_layer.html +/doc/html/boost_asio/reference/buffered_stream/next_layer_type.html +/doc/html/boost_asio/reference/buffered_stream/peek/ +/doc/html/boost_asio/reference/buffered_stream/peek.html +/doc/html/boost_asio/reference/buffered_stream/peek/overload1.html +/doc/html/boost_asio/reference/buffered_stream/peek/overload2.html +/doc/html/boost_asio/reference/buffered_stream/read_some/ +/doc/html/boost_asio/reference/buffered_stream/read_some.html +/doc/html/boost_asio/reference/buffered_stream/read_some/overload1.html +/doc/html/boost_asio/reference/buffered_stream/read_some/overload2.html +/doc/html/boost_asio/reference/buffered_stream/write_some/ +/doc/html/boost_asio/reference/buffered_stream/write_some.html +/doc/html/boost_asio/reference/buffered_stream/write_some/overload1.html +/doc/html/boost_asio/reference/buffered_stream/write_some/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/ +/doc/html/boost_asio/reference/buffered_write_stream/async_flush.html +/doc/html/boost_asio/reference/buffered_write_stream/async_read_some.html +/doc/html/boost_asio/reference/buffered_write_stream/async_write_some.html +/doc/html/boost_asio/reference/buffered_write_stream/buffered_write_stream/ +/doc/html/boost_asio/reference/buffered_write_stream/buffered_write_stream.html +/doc/html/boost_asio/reference/buffered_write_stream/buffered_write_stream/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/buffered_write_stream/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/close/ +/doc/html/boost_asio/reference/buffered_write_stream/close.html +/doc/html/boost_asio/reference/buffered_write_stream/close/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/close/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/default_buffer_size.html +/doc/html/boost_asio/reference/buffered_write_stream/flush/ +/doc/html/boost_asio/reference/buffered_write_stream/flush.html +/doc/html/boost_asio/reference/buffered_write_stream/flush/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/flush/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/get_io_service.html +/doc/html/boost_asio/reference/buffered_write_stream.html +/doc/html/boost_asio/reference/buffered_write_stream/in_avail/ +/doc/html/boost_asio/reference/buffered_write_stream/in_avail.html +/doc/html/boost_asio/reference/buffered_write_stream/in_avail/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/in_avail/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/lowest_layer/ +/doc/html/boost_asio/reference/buffered_write_stream/lowest_layer.html +/doc/html/boost_asio/reference/buffered_write_stream/lowest_layer/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/lowest_layer/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/lowest_layer_type.html +/doc/html/boost_asio/reference/buffered_write_stream/next_layer.html +/doc/html/boost_asio/reference/buffered_write_stream/next_layer_type.html +/doc/html/boost_asio/reference/buffered_write_stream/peek/ +/doc/html/boost_asio/reference/buffered_write_stream/peek.html +/doc/html/boost_asio/reference/buffered_write_stream/peek/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/peek/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/read_some/ +/doc/html/boost_asio/reference/buffered_write_stream/read_some.html +/doc/html/boost_asio/reference/buffered_write_stream/read_some/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/read_some/overload2.html +/doc/html/boost_asio/reference/buffered_write_stream/write_some/ +/doc/html/boost_asio/reference/buffered_write_stream/write_some.html +/doc/html/boost_asio/reference/buffered_write_stream/write_some/overload1.html +/doc/html/boost_asio/reference/buffered_write_stream/write_some/overload2.html +/doc/html/boost_asio/reference/buffer.html +/doc/html/boost_asio/reference/buffer/overload10.html +/doc/html/boost_asio/reference/buffer/overload11.html +/doc/html/boost_asio/reference/buffer/overload12.html +/doc/html/boost_asio/reference/buffer/overload13.html +/doc/html/boost_asio/reference/buffer/overload14.html +/doc/html/boost_asio/reference/buffer/overload15.html +/doc/html/boost_asio/reference/buffer/overload16.html +/doc/html/boost_asio/reference/buffer/overload17.html +/doc/html/boost_asio/reference/buffer/overload18.html +/doc/html/boost_asio/reference/buffer/overload19.html +/doc/html/boost_asio/reference/buffer/overload1.html +/doc/html/boost_asio/reference/buffer/overload20.html +/doc/html/boost_asio/reference/buffer/overload21.html +/doc/html/boost_asio/reference/buffer/overload22.html +/doc/html/boost_asio/reference/buffer/overload23.html +/doc/html/boost_asio/reference/buffer/overload24.html +/doc/html/boost_asio/reference/buffer/overload25.html +/doc/html/boost_asio/reference/buffer/overload26.html +/doc/html/boost_asio/reference/buffer/overload27.html +/doc/html/boost_asio/reference/buffer/overload28.html +/doc/html/boost_asio/reference/buffer/overload2.html +/doc/html/boost_asio/reference/buffer/overload3.html +/doc/html/boost_asio/reference/buffer/overload4.html +/doc/html/boost_asio/reference/buffer/overload5.html +/doc/html/boost_asio/reference/buffer/overload6.html +/doc/html/boost_asio/reference/buffer/overload7.html +/doc/html/boost_asio/reference/buffer/overload8.html +/doc/html/boost_asio/reference/buffer/overload9.html +/doc/html/boost_asio/reference/buffers_begin.html +/doc/html/boost_asio/reference/buffers_end.html +/doc/html/boost_asio/reference/buffers_iterator/ +/doc/html/boost_asio/reference/buffers_iterator/begin.html +/doc/html/boost_asio/reference/buffers_iterator/buffers_iterator.html +/doc/html/boost_asio/reference/buffers_iterator/difference_type.html +/doc/html/boost_asio/reference/buffers_iterator/end.html +/doc/html/boost_asio/reference/buffers_iterator.html +/doc/html/boost_asio/reference/buffers_iterator/iterator_category.html +/doc/html/boost_asio/reference/buffers_iterator/operator_arrow_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_eq__eq_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_gt__eq_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_gt_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_lb__rb_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_lt__eq_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_lt_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus_/ +/doc/html/boost_asio/reference/buffers_iterator/operator_minus__eq_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus__minus_/ +/doc/html/boost_asio/reference/buffers_iterator/operator_minus__minus_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus__minus_/overload1.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus__minus_/overload2.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus_/overload1.html +/doc/html/boost_asio/reference/buffers_iterator/operator_minus_/overload2.html +/doc/html/boost_asio/reference/buffers_iterator/operator_not__eq_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus_/ +/doc/html/boost_asio/reference/buffers_iterator/operator_plus__eq_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus_/overload1.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus_/overload2.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus__plus_/ +/doc/html/boost_asio/reference/buffers_iterator/operator_plus__plus_.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus__plus_/overload1.html +/doc/html/boost_asio/reference/buffers_iterator/operator_plus__plus_/overload2.html +/doc/html/boost_asio/reference/buffers_iterator/operator__star_.html +/doc/html/boost_asio/reference/buffers_iterator/pointer.html +/doc/html/boost_asio/reference/buffers_iterator/reference.html +/doc/html/boost_asio/reference/buffers_iterator/value_type.html +/doc/html/boost_asio/reference/buffer_size/ +/doc/html/boost_asio/reference/buffer_size.html +/doc/html/boost_asio/reference/buffer_size/overload1.html +/doc/html/boost_asio/reference/buffer_size/overload2.html +/doc/html/boost_asio/reference/buffer_size/overload3.html +/doc/html/boost_asio/reference/buffer_size/overload4.html +/doc/html/boost_asio/reference/buffer_size/overload5.html +/doc/html/boost_asio/reference/CompletionHandler.html +/doc/html/boost_asio/reference/ComposedConnectHandler.html +/doc/html/boost_asio/reference/connect/ +/doc/html/boost_asio/reference/ConnectHandler.html +/doc/html/boost_asio/reference/connect.html +/doc/html/boost_asio/reference/connect/overload1.html +/doc/html/boost_asio/reference/connect/overload2.html +/doc/html/boost_asio/reference/connect/overload3.html +/doc/html/boost_asio/reference/connect/overload4.html +/doc/html/boost_asio/reference/connect/overload5.html +/doc/html/boost_asio/reference/connect/overload6.html +/doc/html/boost_asio/reference/connect/overload7.html +/doc/html/boost_asio/reference/connect/overload8.html +/doc/html/boost_asio/reference/const_buffer/ +/doc/html/boost_asio/reference/const_buffer/const_buffer/ +/doc/html/boost_asio/reference/const_buffer/const_buffer.html +/doc/html/boost_asio/reference/const_buffer/const_buffer/overload1.html +/doc/html/boost_asio/reference/const_buffer/const_buffer/overload2.html +/doc/html/boost_asio/reference/const_buffer/const_buffer/overload3.html +/doc/html/boost_asio/reference/const_buffer.html +/doc/html/boost_asio/reference/const_buffer/operator_plus_/ +/doc/html/boost_asio/reference/const_buffer/operator_plus_.html +/doc/html/boost_asio/reference/const_buffer/operator_plus_/overload1.html +/doc/html/boost_asio/reference/const_buffer/operator_plus_/overload2.html +/doc/html/boost_asio/reference/const_buffers_1/ +/doc/html/boost_asio/reference/const_buffers_1/begin.html +/doc/html/boost_asio/reference/const_buffers_1/const_buffers_1/ +/doc/html/boost_asio/reference/const_buffers_1/const_buffers_1.html +/doc/html/boost_asio/reference/const_buffers_1/const_buffers_1/overload1.html +/doc/html/boost_asio/reference/const_buffers_1/const_buffers_1/overload2.html +/doc/html/boost_asio/reference/const_buffers_1/const_iterator.html +/doc/html/boost_asio/reference/const_buffers_1/end.html +/doc/html/boost_asio/reference/const_buffers_1.html +/doc/html/boost_asio/reference/const_buffers_1/operator_plus_/ +/doc/html/boost_asio/reference/const_buffers_1/operator_plus_.html +/doc/html/boost_asio/reference/const_buffers_1/operator_plus_/overload1.html +/doc/html/boost_asio/reference/const_buffers_1/operator_plus_/overload2.html +/doc/html/boost_asio/reference/const_buffers_1/value_type.html +/doc/html/boost_asio/reference/ConstBufferSequence.html +/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html +/doc/html/boost_asio/reference/ConvertibleToMutableBuffer.html +/doc/html/boost_asio/reference/coroutine/ +/doc/html/boost_asio/reference/coroutine/coroutine.html +/doc/html/boost_asio/reference/coroutine.html +/doc/html/boost_asio/reference/coroutine/is_child.html +/doc/html/boost_asio/reference/coroutine/is_complete.html +/doc/html/boost_asio/reference/coroutine/is_parent.html +/doc/html/boost_asio/reference/datagram_socket_service/ +/doc/html/boost_asio/reference/datagram_socket_service/assign.html +/doc/html/boost_asio/reference/datagram_socket_service/async_connect.html +/doc/html/boost_asio/reference/datagram_socket_service/async_receive_from.html +/doc/html/boost_asio/reference/datagram_socket_service/async_receive.html +/doc/html/boost_asio/reference/datagram_socket_service/async_send.html +/doc/html/boost_asio/reference/datagram_socket_service/async_send_to.html +/doc/html/boost_asio/reference/datagram_socket_service/at_mark.html +/doc/html/boost_asio/reference/datagram_socket_service/available.html +/doc/html/boost_asio/reference/datagram_socket_service/bind.html +/doc/html/boost_asio/reference/datagram_socket_service/cancel.html +/doc/html/boost_asio/reference/datagram_socket_service/close.html +/doc/html/boost_asio/reference/datagram_socket_service/connect.html +/doc/html/boost_asio/reference/datagram_socket_service/construct.html +/doc/html/boost_asio/reference/datagram_socket_service/converting_move_construct.html +/doc/html/boost_asio/reference/datagram_socket_service/datagram_socket_service.html +/doc/html/boost_asio/reference/datagram_socket_service/destroy.html +/doc/html/boost_asio/reference/datagram_socket_service/endpoint_type.html +/doc/html/boost_asio/reference/datagram_socket_service/get_io_service.html +/doc/html/boost_asio/reference/datagram_socket_service/get_option.html +/doc/html/boost_asio/reference/datagram_socket_service.html +/doc/html/boost_asio/reference/DatagramSocketService.html +/doc/html/boost_asio/reference/datagram_socket_service/id.html +/doc/html/boost_asio/reference/datagram_socket_service/implementation_type.html +/doc/html/boost_asio/reference/datagram_socket_service/io_control.html +/doc/html/boost_asio/reference/datagram_socket_service/is_open.html +/doc/html/boost_asio/reference/datagram_socket_service/local_endpoint.html +/doc/html/boost_asio/reference/datagram_socket_service/move_assign.html +/doc/html/boost_asio/reference/datagram_socket_service/move_construct.html +/doc/html/boost_asio/reference/datagram_socket_service/native_handle.html +/doc/html/boost_asio/reference/datagram_socket_service/native_handle_type.html +/doc/html/boost_asio/reference/datagram_socket_service/native.html +/doc/html/boost_asio/reference/datagram_socket_service/native_non_blocking/ +/doc/html/boost_asio/reference/datagram_socket_service/native_non_blocking.html +/doc/html/boost_asio/reference/datagram_socket_service/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/datagram_socket_service/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/datagram_socket_service/native_type.html +/doc/html/boost_asio/reference/datagram_socket_service/non_blocking/ +/doc/html/boost_asio/reference/datagram_socket_service/non_blocking.html +/doc/html/boost_asio/reference/datagram_socket_service/non_blocking/overload1.html +/doc/html/boost_asio/reference/datagram_socket_service/non_blocking/overload2.html +/doc/html/boost_asio/reference/datagram_socket_service/open.html +/doc/html/boost_asio/reference/datagram_socket_service/protocol_type.html +/doc/html/boost_asio/reference/datagram_socket_service/receive_from.html +/doc/html/boost_asio/reference/datagram_socket_service/receive.html +/doc/html/boost_asio/reference/datagram_socket_service/remote_endpoint.html +/doc/html/boost_asio/reference/datagram_socket_service/send.html +/doc/html/boost_asio/reference/datagram_socket_service/send_to.html +/doc/html/boost_asio/reference/datagram_socket_service/set_option.html +/doc/html/boost_asio/reference/datagram_socket_service/shutdown.html +/doc/html/boost_asio/reference/deadline_timer.html +/doc/html/boost_asio/reference/deadline_timer_service/ +/doc/html/boost_asio/reference/deadline_timer_service/async_wait.html +/doc/html/boost_asio/reference/deadline_timer_service/cancel.html +/doc/html/boost_asio/reference/deadline_timer_service/cancel_one.html +/doc/html/boost_asio/reference/deadline_timer_service/construct.html +/doc/html/boost_asio/reference/deadline_timer_service/deadline_timer_service.html +/doc/html/boost_asio/reference/deadline_timer_service/destroy.html +/doc/html/boost_asio/reference/deadline_timer_service/duration_type.html +/doc/html/boost_asio/reference/deadline_timer_service/expires_at/ +/doc/html/boost_asio/reference/deadline_timer_service/expires_at.html +/doc/html/boost_asio/reference/deadline_timer_service/expires_at/overload1.html +/doc/html/boost_asio/reference/deadline_timer_service/expires_at/overload2.html +/doc/html/boost_asio/reference/deadline_timer_service/expires_from_now/ +/doc/html/boost_asio/reference/deadline_timer_service/expires_from_now.html +/doc/html/boost_asio/reference/deadline_timer_service/expires_from_now/overload1.html +/doc/html/boost_asio/reference/deadline_timer_service/expires_from_now/overload2.html +/doc/html/boost_asio/reference/deadline_timer_service/get_io_service.html +/doc/html/boost_asio/reference/deadline_timer_service.html +/doc/html/boost_asio/reference/deadline_timer_service/id.html +/doc/html/boost_asio/reference/deadline_timer_service/implementation_type.html +/doc/html/boost_asio/reference/deadline_timer_service/time_type.html +/doc/html/boost_asio/reference/deadline_timer_service/traits_type.html +/doc/html/boost_asio/reference/deadline_timer_service/wait.html +/doc/html/boost_asio/reference/DescriptorService.html +/doc/html/boost_asio/reference/Endpoint.html +/doc/html/boost_asio/reference/error__addrinfo_category.html +/doc/html/boost_asio/reference/error__addrinfo_errors.html +/doc/html/boost_asio/reference/error__basic_errors.html +/doc/html/boost_asio/reference/error__get_addrinfo_category.html +/doc/html/boost_asio/reference/error__get_misc_category.html +/doc/html/boost_asio/reference/error__get_netdb_category.html +/doc/html/boost_asio/reference/error__get_ssl_category.html +/doc/html/boost_asio/reference/error__get_system_category.html +/doc/html/boost_asio/reference/error__make_error_code/ +/doc/html/boost_asio/reference/error__make_error_code.html +/doc/html/boost_asio/reference/error__make_error_code/overload1.html +/doc/html/boost_asio/reference/error__make_error_code/overload2.html +/doc/html/boost_asio/reference/error__make_error_code/overload3.html +/doc/html/boost_asio/reference/error__make_error_code/overload4.html +/doc/html/boost_asio/reference/error__make_error_code/overload5.html +/doc/html/boost_asio/reference/error__misc_category.html +/doc/html/boost_asio/reference/error__misc_errors.html +/doc/html/boost_asio/reference/error__netdb_category.html +/doc/html/boost_asio/reference/error__netdb_errors.html +/doc/html/boost_asio/reference/error__ssl_category.html +/doc/html/boost_asio/reference/error__ssl_errors.html +/doc/html/boost_asio/reference/error__system_category.html +/doc/html/boost_asio/reference/generic__basic_endpoint/ +/doc/html/boost_asio/reference/generic__basic_endpoint/basic_endpoint/ +/doc/html/boost_asio/reference/generic__basic_endpoint/basic_endpoint.html +/doc/html/boost_asio/reference/generic__basic_endpoint/basic_endpoint/overload1.html +/doc/html/boost_asio/reference/generic__basic_endpoint/basic_endpoint/overload2.html +/doc/html/boost_asio/reference/generic__basic_endpoint/basic_endpoint/overload3.html +/doc/html/boost_asio/reference/generic__basic_endpoint/basic_endpoint/overload4.html +/doc/html/boost_asio/reference/generic__basic_endpoint/capacity.html +/doc/html/boost_asio/reference/generic__basic_endpoint/data/ +/doc/html/boost_asio/reference/generic__basic_endpoint/data.html +/doc/html/boost_asio/reference/generic__basic_endpoint/data/overload1.html +/doc/html/boost_asio/reference/generic__basic_endpoint/data/overload2.html +/doc/html/boost_asio/reference/generic__basic_endpoint/data_type.html +/doc/html/boost_asio/reference/generic__basic_endpoint.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_eq__eq_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_eq_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_gt__eq_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_gt_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_lt__eq_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_lt_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/operator_not__eq_.html +/doc/html/boost_asio/reference/generic__basic_endpoint/protocol.html +/doc/html/boost_asio/reference/generic__basic_endpoint/protocol_type.html +/doc/html/boost_asio/reference/generic__basic_endpoint/resize.html +/doc/html/boost_asio/reference/generic__basic_endpoint/size.html +/doc/html/boost_asio/reference/generic__datagram_protocol/ +/doc/html/boost_asio/reference/generic__datagram_protocol/datagram_protocol/ +/doc/html/boost_asio/reference/generic__datagram_protocol/datagram_protocol.html +/doc/html/boost_asio/reference/generic__datagram_protocol/datagram_protocol/overload1.html +/doc/html/boost_asio/reference/generic__datagram_protocol/datagram_protocol/overload2.html +/doc/html/boost_asio/reference/generic__datagram_protocol/endpoint.html +/doc/html/boost_asio/reference/generic__datagram_protocol/family.html +/doc/html/boost_asio/reference/generic__datagram_protocol.html +/doc/html/boost_asio/reference/generic__datagram_protocol/operator_eq__eq_.html +/doc/html/boost_asio/reference/generic__datagram_protocol/operator_not__eq_.html +/doc/html/boost_asio/reference/generic__datagram_protocol/protocol.html +/doc/html/boost_asio/reference/generic__datagram_protocol/socket.html +/doc/html/boost_asio/reference/generic__datagram_protocol/type.html +/doc/html/boost_asio/reference/generic__raw_protocol/ +/doc/html/boost_asio/reference/generic__raw_protocol/endpoint.html +/doc/html/boost_asio/reference/generic__raw_protocol/family.html +/doc/html/boost_asio/reference/generic__raw_protocol.html +/doc/html/boost_asio/reference/generic__raw_protocol/operator_eq__eq_.html +/doc/html/boost_asio/reference/generic__raw_protocol/operator_not__eq_.html +/doc/html/boost_asio/reference/generic__raw_protocol/protocol.html +/doc/html/boost_asio/reference/generic__raw_protocol/raw_protocol/ +/doc/html/boost_asio/reference/generic__raw_protocol/raw_protocol.html +/doc/html/boost_asio/reference/generic__raw_protocol/raw_protocol/overload1.html +/doc/html/boost_asio/reference/generic__raw_protocol/raw_protocol/overload2.html +/doc/html/boost_asio/reference/generic__raw_protocol/socket.html +/doc/html/boost_asio/reference/generic__raw_protocol/type.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/ +/doc/html/boost_asio/reference/generic__seq_packet_protocol/endpoint.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/family.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/operator_eq__eq_.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/operator_not__eq_.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/protocol.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/seq_packet_protocol/ +/doc/html/boost_asio/reference/generic__seq_packet_protocol/seq_packet_protocol.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/seq_packet_protocol/overload1.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/seq_packet_protocol/overload2.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/socket.html +/doc/html/boost_asio/reference/generic__seq_packet_protocol/type.html +/doc/html/boost_asio/reference/generic__stream_protocol/ +/doc/html/boost_asio/reference/generic__stream_protocol/endpoint.html +/doc/html/boost_asio/reference/generic__stream_protocol/family.html +/doc/html/boost_asio/reference/generic__stream_protocol.html +/doc/html/boost_asio/reference/generic__stream_protocol/iostream.html +/doc/html/boost_asio/reference/generic__stream_protocol/operator_eq__eq_.html +/doc/html/boost_asio/reference/generic__stream_protocol/operator_not__eq_.html +/doc/html/boost_asio/reference/generic__stream_protocol/protocol.html +/doc/html/boost_asio/reference/generic__stream_protocol/socket.html +/doc/html/boost_asio/reference/generic__stream_protocol/stream_protocol/ +/doc/html/boost_asio/reference/generic__stream_protocol/stream_protocol.html +/doc/html/boost_asio/reference/generic__stream_protocol/stream_protocol/overload1.html +/doc/html/boost_asio/reference/generic__stream_protocol/stream_protocol/overload2.html +/doc/html/boost_asio/reference/generic__stream_protocol/type.html +/doc/html/boost_asio/reference/GettableSerialPortOption.html +/doc/html/boost_asio/reference/GettableSocketOption.html +/doc/html/boost_asio/reference/Handler.html +/doc/html/boost_asio/reference/handler_type/ +/doc/html/boost_asio/reference/handler_type.html +/doc/html/boost_asio/reference/handler_type/type.html +/doc/html/boost_asio/reference/HandleService.html +/doc/html/boost_asio/reference/HandshakeHandler.html +/doc/html/boost_asio/reference/has_service.html +/doc/html/boost_asio/reference/high_resolution_timer.html +/doc/html/boost_asio/reference.html +/doc/html/boost_asio/reference/InternetProtocol.html +/doc/html/boost_asio/reference/invalid_service_owner/ +/doc/html/boost_asio/reference/invalid_service_owner.html +/doc/html/boost_asio/reference/invalid_service_owner/invalid_service_owner.html +/doc/html/boost_asio/reference/IoControlCommand.html +/doc/html/boost_asio/reference/IoObjectService.html +/doc/html/boost_asio/reference/io_service/ +/doc/html/boost_asio/reference/io_service/add_service.html +/doc/html/boost_asio/reference/io_service/dispatch.html +/doc/html/boost_asio/reference/io_service/fork_event.html +/doc/html/boost_asio/reference/io_service/has_service.html +/doc/html/boost_asio/reference/io_service.html +/doc/html/boost_asio/reference/io_service__id/ +/doc/html/boost_asio/reference/io_service__id.html +/doc/html/boost_asio/reference/io_service__id/id.html +/doc/html/boost_asio/reference/io_service/io_service/ +/doc/html/boost_asio/reference/io_service/_io_service.html +/doc/html/boost_asio/reference/io_service/io_service.html +/doc/html/boost_asio/reference/io_service/io_service/overload1.html +/doc/html/boost_asio/reference/io_service/io_service/overload2.html +/doc/html/boost_asio/reference/io_service/notify_fork.html +/doc/html/boost_asio/reference/io_service/poll/ +/doc/html/boost_asio/reference/io_service/poll.html +/doc/html/boost_asio/reference/io_service/poll_one/ +/doc/html/boost_asio/reference/io_service/poll_one.html +/doc/html/boost_asio/reference/io_service/poll_one/overload1.html +/doc/html/boost_asio/reference/io_service/poll_one/overload2.html +/doc/html/boost_asio/reference/io_service/poll/overload1.html +/doc/html/boost_asio/reference/io_service/poll/overload2.html +/doc/html/boost_asio/reference/io_service/post.html +/doc/html/boost_asio/reference/io_service/reset.html +/doc/html/boost_asio/reference/io_service/run/ +/doc/html/boost_asio/reference/io_service/run.html +/doc/html/boost_asio/reference/io_service/run_one/ +/doc/html/boost_asio/reference/io_service/run_one.html +/doc/html/boost_asio/reference/io_service/run_one/overload1.html +/doc/html/boost_asio/reference/io_service/run_one/overload2.html +/doc/html/boost_asio/reference/io_service/run/overload1.html +/doc/html/boost_asio/reference/io_service/run/overload2.html +/doc/html/boost_asio/reference/io_service__service/ +/doc/html/boost_asio/reference/io_service__service/fork_service.html +/doc/html/boost_asio/reference/io_service__service/get_io_service.html +/doc/html/boost_asio/reference/io_service__service.html +/doc/html/boost_asio/reference/io_service__service/_service.html +/doc/html/boost_asio/reference/io_service__service/service.html +/doc/html/boost_asio/reference/io_service__service/shutdown_service.html +/doc/html/boost_asio/reference/io_service/stop.html +/doc/html/boost_asio/reference/io_service/stopped.html +/doc/html/boost_asio/reference/io_service__strand/ +/doc/html/boost_asio/reference/io_service__strand/dispatch.html +/doc/html/boost_asio/reference/io_service__strand/get_io_service.html +/doc/html/boost_asio/reference/io_service__strand.html +/doc/html/boost_asio/reference/io_service__strand/post.html +/doc/html/boost_asio/reference/io_service__strand/running_in_this_thread.html +/doc/html/boost_asio/reference/io_service__strand/_strand.html +/doc/html/boost_asio/reference/io_service__strand/strand.html +/doc/html/boost_asio/reference/io_service__strand/wrap.html +/doc/html/boost_asio/reference/io_service/use_service.html +/doc/html/boost_asio/reference/io_service__work/ +/doc/html/boost_asio/reference/io_service__work/get_io_service.html +/doc/html/boost_asio/reference/io_service__work.html +/doc/html/boost_asio/reference/io_service__work/work/ +/doc/html/boost_asio/reference/io_service__work/_work.html +/doc/html/boost_asio/reference/io_service__work/work.html +/doc/html/boost_asio/reference/io_service__work/work/overload1.html +/doc/html/boost_asio/reference/io_service__work/work/overload2.html +/doc/html/boost_asio/reference/io_service/wrap.html +/doc/html/boost_asio/reference/ip__address/ +/doc/html/boost_asio/reference/ip__address/address/ +/doc/html/boost_asio/reference/ip__address/address.html +/doc/html/boost_asio/reference/ip__address/address/overload1.html +/doc/html/boost_asio/reference/ip__address/address/overload2.html +/doc/html/boost_asio/reference/ip__address/address/overload3.html +/doc/html/boost_asio/reference/ip__address/address/overload4.html +/doc/html/boost_asio/reference/ip__address/from_string/ +/doc/html/boost_asio/reference/ip__address/from_string.html +/doc/html/boost_asio/reference/ip__address/from_string/overload1.html +/doc/html/boost_asio/reference/ip__address/from_string/overload2.html +/doc/html/boost_asio/reference/ip__address/from_string/overload3.html +/doc/html/boost_asio/reference/ip__address/from_string/overload4.html +/doc/html/boost_asio/reference/ip__address.html +/doc/html/boost_asio/reference/ip__address/is_loopback.html +/doc/html/boost_asio/reference/ip__address/is_multicast.html +/doc/html/boost_asio/reference/ip__address/is_unspecified.html +/doc/html/boost_asio/reference/ip__address/is_v4.html +/doc/html/boost_asio/reference/ip__address/is_v6.html +/doc/html/boost_asio/reference/ip__address/operator_eq_/ +/doc/html/boost_asio/reference/ip__address/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__address/operator_eq_.html +/doc/html/boost_asio/reference/ip__address/operator_eq_/overload1.html +/doc/html/boost_asio/reference/ip__address/operator_eq_/overload2.html +/doc/html/boost_asio/reference/ip__address/operator_eq_/overload3.html +/doc/html/boost_asio/reference/ip__address/operator_gt__eq_.html +/doc/html/boost_asio/reference/ip__address/operator_gt_.html +/doc/html/boost_asio/reference/ip__address/operator_lt__eq_.html +/doc/html/boost_asio/reference/ip__address/operator_lt_.html +/doc/html/boost_asio/reference/ip__address/operator_lt__lt_.html +/doc/html/boost_asio/reference/ip__address/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__address/to_string/ +/doc/html/boost_asio/reference/ip__address/to_string.html +/doc/html/boost_asio/reference/ip__address/to_string/overload1.html +/doc/html/boost_asio/reference/ip__address/to_string/overload2.html +/doc/html/boost_asio/reference/ip__address/to_v4.html +/doc/html/boost_asio/reference/ip__address/to_v6.html +/doc/html/boost_asio/reference/ip__address_v4/ +/doc/html/boost_asio/reference/ip__address_v4/address_v4/ +/doc/html/boost_asio/reference/ip__address_v4/address_v4.html +/doc/html/boost_asio/reference/ip__address_v4/address_v4/overload1.html +/doc/html/boost_asio/reference/ip__address_v4/address_v4/overload2.html +/doc/html/boost_asio/reference/ip__address_v4/address_v4/overload3.html +/doc/html/boost_asio/reference/ip__address_v4/address_v4/overload4.html +/doc/html/boost_asio/reference/ip__address_v4/any.html +/doc/html/boost_asio/reference/ip__address_v4/broadcast/ +/doc/html/boost_asio/reference/ip__address_v4/broadcast.html +/doc/html/boost_asio/reference/ip__address_v4/broadcast/overload1.html +/doc/html/boost_asio/reference/ip__address_v4/broadcast/overload2.html +/doc/html/boost_asio/reference/ip__address_v4/bytes_type.html +/doc/html/boost_asio/reference/ip__address_v4/from_string/ +/doc/html/boost_asio/reference/ip__address_v4/from_string.html +/doc/html/boost_asio/reference/ip__address_v4/from_string/overload1.html +/doc/html/boost_asio/reference/ip__address_v4/from_string/overload2.html +/doc/html/boost_asio/reference/ip__address_v4/from_string/overload3.html +/doc/html/boost_asio/reference/ip__address_v4/from_string/overload4.html +/doc/html/boost_asio/reference/ip__address_v4.html +/doc/html/boost_asio/reference/ip__address_v4/is_class_a.html +/doc/html/boost_asio/reference/ip__address_v4/is_class_b.html +/doc/html/boost_asio/reference/ip__address_v4/is_class_c.html +/doc/html/boost_asio/reference/ip__address_v4/is_loopback.html +/doc/html/boost_asio/reference/ip__address_v4/is_multicast.html +/doc/html/boost_asio/reference/ip__address_v4/is_unspecified.html +/doc/html/boost_asio/reference/ip__address_v4/loopback.html +/doc/html/boost_asio/reference/ip__address_v4/netmask.html +/doc/html/boost_asio/reference/ip__address_v4/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_eq_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_gt__eq_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_gt_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_lt__eq_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_lt_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_lt__lt_.html +/doc/html/boost_asio/reference/ip__address_v4/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__address_v4/to_bytes.html +/doc/html/boost_asio/reference/ip__address_v4/to_string/ +/doc/html/boost_asio/reference/ip__address_v4/to_string.html +/doc/html/boost_asio/reference/ip__address_v4/to_string/overload1.html +/doc/html/boost_asio/reference/ip__address_v4/to_string/overload2.html +/doc/html/boost_asio/reference/ip__address_v4/to_ulong.html +/doc/html/boost_asio/reference/ip__address_v6/ +/doc/html/boost_asio/reference/ip__address_v6/address_v6/ +/doc/html/boost_asio/reference/ip__address_v6/address_v6.html +/doc/html/boost_asio/reference/ip__address_v6/address_v6/overload1.html +/doc/html/boost_asio/reference/ip__address_v6/address_v6/overload2.html +/doc/html/boost_asio/reference/ip__address_v6/address_v6/overload3.html +/doc/html/boost_asio/reference/ip__address_v6/any.html +/doc/html/boost_asio/reference/ip__address_v6/bytes_type.html +/doc/html/boost_asio/reference/ip__address_v6/from_string/ +/doc/html/boost_asio/reference/ip__address_v6/from_string.html +/doc/html/boost_asio/reference/ip__address_v6/from_string/overload1.html +/doc/html/boost_asio/reference/ip__address_v6/from_string/overload2.html +/doc/html/boost_asio/reference/ip__address_v6/from_string/overload3.html +/doc/html/boost_asio/reference/ip__address_v6/from_string/overload4.html +/doc/html/boost_asio/reference/ip__address_v6.html +/doc/html/boost_asio/reference/ip__address_v6/is_link_local.html +/doc/html/boost_asio/reference/ip__address_v6/is_loopback.html +/doc/html/boost_asio/reference/ip__address_v6/is_multicast_global.html +/doc/html/boost_asio/reference/ip__address_v6/is_multicast.html +/doc/html/boost_asio/reference/ip__address_v6/is_multicast_link_local.html +/doc/html/boost_asio/reference/ip__address_v6/is_multicast_node_local.html +/doc/html/boost_asio/reference/ip__address_v6/is_multicast_org_local.html +/doc/html/boost_asio/reference/ip__address_v6/is_multicast_site_local.html +/doc/html/boost_asio/reference/ip__address_v6/is_site_local.html +/doc/html/boost_asio/reference/ip__address_v6/is_unspecified.html +/doc/html/boost_asio/reference/ip__address_v6/is_v4_compatible.html +/doc/html/boost_asio/reference/ip__address_v6/is_v4_mapped.html +/doc/html/boost_asio/reference/ip__address_v6/loopback.html +/doc/html/boost_asio/reference/ip__address_v6/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_eq_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_gt__eq_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_gt_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_lt__eq_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_lt_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_lt__lt_.html +/doc/html/boost_asio/reference/ip__address_v6/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__address_v6/scope_id/ +/doc/html/boost_asio/reference/ip__address_v6/scope_id.html +/doc/html/boost_asio/reference/ip__address_v6/scope_id/overload1.html +/doc/html/boost_asio/reference/ip__address_v6/scope_id/overload2.html +/doc/html/boost_asio/reference/ip__address_v6/to_bytes.html +/doc/html/boost_asio/reference/ip__address_v6/to_string/ +/doc/html/boost_asio/reference/ip__address_v6/to_string.html +/doc/html/boost_asio/reference/ip__address_v6/to_string/overload1.html +/doc/html/boost_asio/reference/ip__address_v6/to_string/overload2.html +/doc/html/boost_asio/reference/ip__address_v6/to_v4.html +/doc/html/boost_asio/reference/ip__address_v6/v4_compatible.html +/doc/html/boost_asio/reference/ip__address_v6/v4_mapped.html +/doc/html/boost_asio/reference/ip__basic_endpoint/ +/doc/html/boost_asio/reference/ip__basic_endpoint/address/ +/doc/html/boost_asio/reference/ip__basic_endpoint/address.html +/doc/html/boost_asio/reference/ip__basic_endpoint/address/overload1.html +/doc/html/boost_asio/reference/ip__basic_endpoint/address/overload2.html +/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/ +/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint.html +/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/overload1.html +/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/overload2.html +/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/overload3.html +/doc/html/boost_asio/reference/ip__basic_endpoint/basic_endpoint/overload4.html +/doc/html/boost_asio/reference/ip__basic_endpoint/capacity.html +/doc/html/boost_asio/reference/ip__basic_endpoint/data/ +/doc/html/boost_asio/reference/ip__basic_endpoint/data.html +/doc/html/boost_asio/reference/ip__basic_endpoint/data/overload1.html +/doc/html/boost_asio/reference/ip__basic_endpoint/data/overload2.html +/doc/html/boost_asio/reference/ip__basic_endpoint/data_type.html +/doc/html/boost_asio/reference/ip__basic_endpoint.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_eq_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_gt__eq_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_gt_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_lt__eq_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_lt_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_lt__lt_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__basic_endpoint/port/ +/doc/html/boost_asio/reference/ip__basic_endpoint/port.html +/doc/html/boost_asio/reference/ip__basic_endpoint/port/overload1.html +/doc/html/boost_asio/reference/ip__basic_endpoint/port/overload2.html +/doc/html/boost_asio/reference/ip__basic_endpoint/protocol.html +/doc/html/boost_asio/reference/ip__basic_endpoint/protocol_type.html +/doc/html/boost_asio/reference/ip__basic_endpoint/resize.html +/doc/html/boost_asio/reference/ip__basic_endpoint/size.html +/doc/html/boost_asio/reference/ip__basic_resolver/ +/doc/html/boost_asio/reference/ip__basic_resolver/async_resolve/ +/doc/html/boost_asio/reference/ip__basic_resolver/async_resolve.html +/doc/html/boost_asio/reference/ip__basic_resolver/async_resolve/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver/async_resolve/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver/basic_resolver.html +/doc/html/boost_asio/reference/ip__basic_resolver/cancel.html +/doc/html/boost_asio/reference/ip__basic_resolver/endpoint_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/ +/doc/html/boost_asio/reference/ip__basic_resolver_entry/basic_resolver_entry/ +/doc/html/boost_asio/reference/ip__basic_resolver_entry/basic_resolver_entry.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/basic_resolver_entry/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/basic_resolver_entry/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/endpoint.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/endpoint_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/host_name.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/operator_endpoint_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/protocol_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_entry/service_name.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_implementation/ +/doc/html/boost_asio/reference/ip__basic_resolver/get_implementation.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_implementation/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_implementation/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_io_service.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_service/ +/doc/html/boost_asio/reference/ip__basic_resolver/get_service.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_service/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver/get_service/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver.html +/doc/html/boost_asio/reference/ip__basic_resolver/implementation.html +/doc/html/boost_asio/reference/ip__basic_resolver/implementation_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/ +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/basic_resolver_iterator.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/create/ +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/create.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/create/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/create/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/create/overload3.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/difference_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator.html +/doc/html/boost_asio/reference/ip__basic_resolver/iterator.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/iterator_category.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_arrow_.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_plus__plus_/ +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_plus__plus_.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_plus__plus_/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator_plus__plus_/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/operator__star_.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/pointer.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/reference.html +/doc/html/boost_asio/reference/ip__basic_resolver_iterator/value_type.html +/doc/html/boost_asio/reference/ip__basic_resolver/protocol_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/ +/doc/html/boost_asio/reference/ip__basic_resolver_query/address_configured.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/all_matching.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/basic_resolver_query/ +/doc/html/boost_asio/reference/ip__basic_resolver_query/basic_resolver_query.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/basic_resolver_query/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/basic_resolver_query/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/basic_resolver_query/overload3.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/basic_resolver_query/overload4.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/canonical_name.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/flags.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/hints.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/host_name.html +/doc/html/boost_asio/reference/ip__basic_resolver_query.html +/doc/html/boost_asio/reference/ip__basic_resolver/query.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/numeric_host.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/numeric_service.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/passive.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/protocol_type.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/service_name.html +/doc/html/boost_asio/reference/ip__basic_resolver_query/v4_mapped.html +/doc/html/boost_asio/reference/ip__basic_resolver/resolve/ +/doc/html/boost_asio/reference/ip__basic_resolver/resolve.html +/doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload1.html +/doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload2.html +/doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload3.html +/doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload4.html +/doc/html/boost_asio/reference/ip__basic_resolver/service.html +/doc/html/boost_asio/reference/ip__basic_resolver/service_type.html +/doc/html/boost_asio/reference/ip__host_name/ +/doc/html/boost_asio/reference/ip__host_name.html +/doc/html/boost_asio/reference/ip__host_name/overload1.html +/doc/html/boost_asio/reference/ip__host_name/overload2.html +/doc/html/boost_asio/reference/ip__icmp/ +/doc/html/boost_asio/reference/ip__icmp/endpoint.html +/doc/html/boost_asio/reference/ip__icmp/family.html +/doc/html/boost_asio/reference/ip__icmp.html +/doc/html/boost_asio/reference/ip__icmp/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__icmp/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__icmp/protocol.html +/doc/html/boost_asio/reference/ip__icmp/resolver.html +/doc/html/boost_asio/reference/ip__icmp/socket.html +/doc/html/boost_asio/reference/ip__icmp/type.html +/doc/html/boost_asio/reference/ip__icmp/v4.html +/doc/html/boost_asio/reference/ip__icmp/v6.html +/doc/html/boost_asio/reference/ip__multicast__enable_loopback.html +/doc/html/boost_asio/reference/ip__multicast__hops.html +/doc/html/boost_asio/reference/ip__multicast__join_group.html +/doc/html/boost_asio/reference/ip__multicast__leave_group.html +/doc/html/boost_asio/reference/ip__multicast__outbound_interface.html +/doc/html/boost_asio/reference/ip__resolver_query_base/ +/doc/html/boost_asio/reference/ip__resolver_query_base/address_configured.html +/doc/html/boost_asio/reference/ip__resolver_query_base/all_matching.html +/doc/html/boost_asio/reference/ip__resolver_query_base/canonical_name.html +/doc/html/boost_asio/reference/ip__resolver_query_base/flags.html +/doc/html/boost_asio/reference/ip__resolver_query_base.html +/doc/html/boost_asio/reference/ip__resolver_query_base/numeric_host.html +/doc/html/boost_asio/reference/ip__resolver_query_base/numeric_service.html +/doc/html/boost_asio/reference/ip__resolver_query_base/passive.html +/doc/html/boost_asio/reference/ip__resolver_query_base/_resolver_query_base.html +/doc/html/boost_asio/reference/ip__resolver_query_base/v4_mapped.html +/doc/html/boost_asio/reference/ip__resolver_service/ +/doc/html/boost_asio/reference/ip__resolver_service/async_resolve/ +/doc/html/boost_asio/reference/ip__resolver_service/async_resolve.html +/doc/html/boost_asio/reference/ip__resolver_service/async_resolve/overload1.html +/doc/html/boost_asio/reference/ip__resolver_service/async_resolve/overload2.html +/doc/html/boost_asio/reference/ip__resolver_service/cancel.html +/doc/html/boost_asio/reference/ip__resolver_service/construct.html +/doc/html/boost_asio/reference/ip__resolver_service/destroy.html +/doc/html/boost_asio/reference/ip__resolver_service/endpoint_type.html +/doc/html/boost_asio/reference/ip__resolver_service/get_io_service.html +/doc/html/boost_asio/reference/ip__resolver_service.html +/doc/html/boost_asio/reference/ip__resolver_service/id.html +/doc/html/boost_asio/reference/ip__resolver_service/implementation_type.html +/doc/html/boost_asio/reference/ip__resolver_service/iterator_type.html +/doc/html/boost_asio/reference/ip__resolver_service/protocol_type.html +/doc/html/boost_asio/reference/ip__resolver_service/query_type.html +/doc/html/boost_asio/reference/ip__resolver_service/resolve/ +/doc/html/boost_asio/reference/ip__resolver_service/resolve.html +/doc/html/boost_asio/reference/ip__resolver_service/resolve/overload1.html +/doc/html/boost_asio/reference/ip__resolver_service/resolve/overload2.html +/doc/html/boost_asio/reference/ip__resolver_service/resolver_service.html +/doc/html/boost_asio/reference/ip__tcp/ +/doc/html/boost_asio/reference/ip__tcp/acceptor.html +/doc/html/boost_asio/reference/ip__tcp/endpoint.html +/doc/html/boost_asio/reference/ip__tcp/family.html +/doc/html/boost_asio/reference/ip__tcp.html +/doc/html/boost_asio/reference/ip__tcp/iostream.html +/doc/html/boost_asio/reference/ip__tcp/no_delay.html +/doc/html/boost_asio/reference/ip__tcp/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__tcp/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__tcp/protocol.html +/doc/html/boost_asio/reference/ip__tcp/resolver.html +/doc/html/boost_asio/reference/ip__tcp/socket.html +/doc/html/boost_asio/reference/ip__tcp/type.html +/doc/html/boost_asio/reference/ip__tcp/v4.html +/doc/html/boost_asio/reference/ip__tcp/v6.html +/doc/html/boost_asio/reference/ip__udp/ +/doc/html/boost_asio/reference/ip__udp/endpoint.html +/doc/html/boost_asio/reference/ip__udp/family.html +/doc/html/boost_asio/reference/ip__udp.html +/doc/html/boost_asio/reference/ip__udp/operator_eq__eq_.html +/doc/html/boost_asio/reference/ip__udp/operator_not__eq_.html +/doc/html/boost_asio/reference/ip__udp/protocol.html +/doc/html/boost_asio/reference/ip__udp/resolver.html +/doc/html/boost_asio/reference/ip__udp/socket.html +/doc/html/boost_asio/reference/ip__udp/type.html +/doc/html/boost_asio/reference/ip__udp/v4.html +/doc/html/boost_asio/reference/ip__udp/v6.html +/doc/html/boost_asio/reference/ip__unicast__hops.html +/doc/html/boost_asio/reference/ip__v6_only.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__addrinfo_errors__gt_/ +/doc/html/boost_asio/reference/is_error_code_enum_lt__addrinfo_errors__gt_.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__addrinfo_errors__gt_/value.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__basic_errors__gt_/ +/doc/html/boost_asio/reference/is_error_code_enum_lt__basic_errors__gt_.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__basic_errors__gt_/value.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__boost__asio__ssl__error__stream_errors__gt_/ +/doc/html/boost_asio/reference/is_error_code_enum_lt__boost__asio__ssl__error__stream_errors__gt_.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__boost__asio__ssl__error__stream_errors__gt_/value.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__misc_errors__gt_/ +/doc/html/boost_asio/reference/is_error_code_enum_lt__misc_errors__gt_.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__misc_errors__gt_/value.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__netdb_errors__gt_/ +/doc/html/boost_asio/reference/is_error_code_enum_lt__netdb_errors__gt_.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__netdb_errors__gt_/value.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__ssl_errors__gt_/ +/doc/html/boost_asio/reference/is_error_code_enum_lt__ssl_errors__gt_.html +/doc/html/boost_asio/reference/is_error_code_enum_lt__ssl_errors__gt_/value.html +/doc/html/boost_asio/reference/is_match_condition/ +/doc/html/boost_asio/reference/is_match_condition.html +/doc/html/boost_asio/reference/is_match_condition/value.html +/doc/html/boost_asio/reference/is_read_buffered/ +/doc/html/boost_asio/reference/is_read_buffered.html +/doc/html/boost_asio/reference/is_read_buffered/value.html +/doc/html/boost_asio/reference/is_write_buffered/ +/doc/html/boost_asio/reference/is_write_buffered.html +/doc/html/boost_asio/reference/is_write_buffered/value.html +/doc/html/boost_asio/reference/local__basic_endpoint/ +/doc/html/boost_asio/reference/local__basic_endpoint/basic_endpoint/ +/doc/html/boost_asio/reference/local__basic_endpoint/basic_endpoint.html +/doc/html/boost_asio/reference/local__basic_endpoint/basic_endpoint/overload1.html +/doc/html/boost_asio/reference/local__basic_endpoint/basic_endpoint/overload2.html +/doc/html/boost_asio/reference/local__basic_endpoint/basic_endpoint/overload3.html +/doc/html/boost_asio/reference/local__basic_endpoint/basic_endpoint/overload4.html +/doc/html/boost_asio/reference/local__basic_endpoint/capacity.html +/doc/html/boost_asio/reference/local__basic_endpoint/data/ +/doc/html/boost_asio/reference/local__basic_endpoint/data.html +/doc/html/boost_asio/reference/local__basic_endpoint/data/overload1.html +/doc/html/boost_asio/reference/local__basic_endpoint/data/overload2.html +/doc/html/boost_asio/reference/local__basic_endpoint/data_type.html +/doc/html/boost_asio/reference/local__basic_endpoint.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_eq__eq_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_eq_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_gt__eq_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_gt_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_lt__eq_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_lt_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_lt__lt_.html +/doc/html/boost_asio/reference/local__basic_endpoint/operator_not__eq_.html +/doc/html/boost_asio/reference/local__basic_endpoint/path/ +/doc/html/boost_asio/reference/local__basic_endpoint/path.html +/doc/html/boost_asio/reference/local__basic_endpoint/path/overload1.html +/doc/html/boost_asio/reference/local__basic_endpoint/path/overload2.html +/doc/html/boost_asio/reference/local__basic_endpoint/path/overload3.html +/doc/html/boost_asio/reference/local__basic_endpoint/protocol.html +/doc/html/boost_asio/reference/local__basic_endpoint/protocol_type.html +/doc/html/boost_asio/reference/local__basic_endpoint/resize.html +/doc/html/boost_asio/reference/local__basic_endpoint/size.html +/doc/html/boost_asio/reference/local__connect_pair/ +/doc/html/boost_asio/reference/local__connect_pair.html +/doc/html/boost_asio/reference/local__connect_pair/overload1.html +/doc/html/boost_asio/reference/local__connect_pair/overload2.html +/doc/html/boost_asio/reference/local__datagram_protocol/ +/doc/html/boost_asio/reference/local__datagram_protocol/endpoint.html +/doc/html/boost_asio/reference/local__datagram_protocol/family.html +/doc/html/boost_asio/reference/local__datagram_protocol.html +/doc/html/boost_asio/reference/local__datagram_protocol/protocol.html +/doc/html/boost_asio/reference/local__datagram_protocol/socket.html +/doc/html/boost_asio/reference/local__datagram_protocol/type.html +/doc/html/boost_asio/reference/local__stream_protocol/ +/doc/html/boost_asio/reference/local__stream_protocol/acceptor.html +/doc/html/boost_asio/reference/local__stream_protocol/endpoint.html +/doc/html/boost_asio/reference/local__stream_protocol/family.html +/doc/html/boost_asio/reference/local__stream_protocol.html +/doc/html/boost_asio/reference/local__stream_protocol/iostream.html +/doc/html/boost_asio/reference/local__stream_protocol/protocol.html +/doc/html/boost_asio/reference/local__stream_protocol/socket.html +/doc/html/boost_asio/reference/local__stream_protocol/type.html +/doc/html/boost_asio/reference/mutable_buffer/ +/doc/html/boost_asio/reference/mutable_buffer.html +/doc/html/boost_asio/reference/mutable_buffer/mutable_buffer/ +/doc/html/boost_asio/reference/mutable_buffer/mutable_buffer.html +/doc/html/boost_asio/reference/mutable_buffer/mutable_buffer/overload1.html +/doc/html/boost_asio/reference/mutable_buffer/mutable_buffer/overload2.html +/doc/html/boost_asio/reference/mutable_buffer/operator_plus_/ +/doc/html/boost_asio/reference/mutable_buffer/operator_plus_.html +/doc/html/boost_asio/reference/mutable_buffer/operator_plus_/overload1.html +/doc/html/boost_asio/reference/mutable_buffer/operator_plus_/overload2.html +/doc/html/boost_asio/reference/mutable_buffers_1/ +/doc/html/boost_asio/reference/mutable_buffers_1/begin.html +/doc/html/boost_asio/reference/mutable_buffers_1/const_iterator.html +/doc/html/boost_asio/reference/mutable_buffers_1/end.html +/doc/html/boost_asio/reference/mutable_buffers_1.html +/doc/html/boost_asio/reference/mutable_buffers_1/mutable_buffers_1/ +/doc/html/boost_asio/reference/mutable_buffers_1/mutable_buffers_1.html +/doc/html/boost_asio/reference/mutable_buffers_1/mutable_buffers_1/overload1.html +/doc/html/boost_asio/reference/mutable_buffers_1/mutable_buffers_1/overload2.html +/doc/html/boost_asio/reference/mutable_buffers_1/operator_plus_/ +/doc/html/boost_asio/reference/mutable_buffers_1/operator_plus_.html +/doc/html/boost_asio/reference/mutable_buffers_1/operator_plus_/overload1.html +/doc/html/boost_asio/reference/mutable_buffers_1/operator_plus_/overload2.html +/doc/html/boost_asio/reference/mutable_buffers_1/value_type.html +/doc/html/boost_asio/reference/MutableBufferSequence.html +/doc/html/boost_asio/reference/null_buffers/ +/doc/html/boost_asio/reference/null_buffers/begin.html +/doc/html/boost_asio/reference/null_buffers/const_iterator.html +/doc/html/boost_asio/reference/null_buffers/end.html +/doc/html/boost_asio/reference/null_buffers.html +/doc/html/boost_asio/reference/null_buffers/value_type.html +/doc/html/boost_asio/reference/ObjectHandleService.html +/doc/html/boost_asio/reference/placeholders__bytes_transferred.html +/doc/html/boost_asio/reference/placeholders__error.html +/doc/html/boost_asio/reference/placeholders__iterator.html +/doc/html/boost_asio/reference/placeholders__signal_number.html +/doc/html/boost_asio/reference/posix__basic_descriptor/ +/doc/html/boost_asio/reference/posix__basic_descriptor/assign/ +/doc/html/boost_asio/reference/posix__basic_descriptor/assign.html +/doc/html/boost_asio/reference/posix__basic_descriptor/assign/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/assign/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/basic_descriptor/ +/doc/html/boost_asio/reference/posix__basic_descriptor/_basic_descriptor.html +/doc/html/boost_asio/reference/posix__basic_descriptor/basic_descriptor.html +/doc/html/boost_asio/reference/posix__basic_descriptor/basic_descriptor/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/basic_descriptor/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/basic_descriptor/overload3.html +/doc/html/boost_asio/reference/posix__basic_descriptor/bytes_readable.html +/doc/html/boost_asio/reference/posix__basic_descriptor/cancel/ +/doc/html/boost_asio/reference/posix__basic_descriptor/cancel.html +/doc/html/boost_asio/reference/posix__basic_descriptor/cancel/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/cancel/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/close/ +/doc/html/boost_asio/reference/posix__basic_descriptor/close.html +/doc/html/boost_asio/reference/posix__basic_descriptor/close/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/close/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_implementation/ +/doc/html/boost_asio/reference/posix__basic_descriptor/get_implementation.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_implementation/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_implementation/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_io_service.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_service/ +/doc/html/boost_asio/reference/posix__basic_descriptor/get_service.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_service/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/get_service/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor.html +/doc/html/boost_asio/reference/posix__basic_descriptor/implementation.html +/doc/html/boost_asio/reference/posix__basic_descriptor/implementation_type.html +/doc/html/boost_asio/reference/posix__basic_descriptor/io_control/ +/doc/html/boost_asio/reference/posix__basic_descriptor/io_control.html +/doc/html/boost_asio/reference/posix__basic_descriptor/io_control/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/io_control/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/is_open.html +/doc/html/boost_asio/reference/posix__basic_descriptor/lowest_layer/ +/doc/html/boost_asio/reference/posix__basic_descriptor/lowest_layer.html +/doc/html/boost_asio/reference/posix__basic_descriptor/lowest_layer/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/lowest_layer/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/lowest_layer_type.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_handle.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_handle_type.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_non_blocking/ +/doc/html/boost_asio/reference/posix__basic_descriptor/native_non_blocking.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/posix__basic_descriptor/native_type.html +/doc/html/boost_asio/reference/posix__basic_descriptor/non_blocking/ +/doc/html/boost_asio/reference/posix__basic_descriptor/non_blocking.html +/doc/html/boost_asio/reference/posix__basic_descriptor/non_blocking_io.html +/doc/html/boost_asio/reference/posix__basic_descriptor/non_blocking/overload1.html +/doc/html/boost_asio/reference/posix__basic_descriptor/non_blocking/overload2.html +/doc/html/boost_asio/reference/posix__basic_descriptor/non_blocking/overload3.html +/doc/html/boost_asio/reference/posix__basic_descriptor/operator_eq_.html +/doc/html/boost_asio/reference/posix__basic_descriptor/release.html +/doc/html/boost_asio/reference/posix__basic_descriptor/service.html +/doc/html/boost_asio/reference/posix__basic_descriptor/service_type.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/assign/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/assign.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/assign/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/assign/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/async_read_some.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/async_write_some.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/basic_stream_descriptor/overload3.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/bytes_readable.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/cancel/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/cancel.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/cancel/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/cancel/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/close/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/close.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/close/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/close/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_implementation/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_implementation.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_implementation/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_implementation/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_io_service.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_service/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_service.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_service/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/get_service/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/implementation.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/implementation_type.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/io_control/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/io_control.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/io_control/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/io_control/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/is_open.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/lowest_layer/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/lowest_layer.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/lowest_layer/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/lowest_layer/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/lowest_layer_type.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_handle.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_handle_type.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_non_blocking/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_non_blocking.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_non_blocking/overload3.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/native_type.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/non_blocking/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/non_blocking.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/non_blocking_io.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/non_blocking/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/non_blocking/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/non_blocking/overload3.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/operator_eq_.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/read_some/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/read_some.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/read_some/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/read_some/overload2.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/release.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/service.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/service_type.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/write_some/ +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/write_some.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/write_some/overload1.html +/doc/html/boost_asio/reference/posix__basic_stream_descriptor/write_some/overload2.html +/doc/html/boost_asio/reference/posix__descriptor_base/ +/doc/html/boost_asio/reference/posix__descriptor_base/bytes_readable.html +/doc/html/boost_asio/reference/posix__descriptor_base/_descriptor_base.html +/doc/html/boost_asio/reference/posix__descriptor_base.html +/doc/html/boost_asio/reference/posix__descriptor_base/non_blocking_io.html +/doc/html/boost_asio/reference/posix__stream_descriptor.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/ +/doc/html/boost_asio/reference/posix__stream_descriptor_service/assign.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/async_read_some.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/async_write_some.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/cancel.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/close.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/construct.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/destroy.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/get_io_service.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/id.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/implementation_type.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/io_control.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/is_open.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/move_assign.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/move_construct.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_handle.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_handle_type.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_non_blocking/ +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_non_blocking.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/native_type.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/non_blocking/ +/doc/html/boost_asio/reference/posix__stream_descriptor_service/non_blocking.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/non_blocking/overload1.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/non_blocking/overload2.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/read_some.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/release.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/stream_descriptor_service.html +/doc/html/boost_asio/reference/posix__stream_descriptor_service/write_some.html +/doc/html/boost_asio/reference/Protocol.html +/doc/html/boost_asio/reference/RandomAccessHandleService.html +/doc/html/boost_asio/reference/raw_socket_service/ +/doc/html/boost_asio/reference/raw_socket_service/assign.html +/doc/html/boost_asio/reference/raw_socket_service/async_connect.html +/doc/html/boost_asio/reference/raw_socket_service/async_receive_from.html +/doc/html/boost_asio/reference/raw_socket_service/async_receive.html +/doc/html/boost_asio/reference/raw_socket_service/async_send.html +/doc/html/boost_asio/reference/raw_socket_service/async_send_to.html +/doc/html/boost_asio/reference/raw_socket_service/at_mark.html +/doc/html/boost_asio/reference/raw_socket_service/available.html +/doc/html/boost_asio/reference/raw_socket_service/bind.html +/doc/html/boost_asio/reference/raw_socket_service/cancel.html +/doc/html/boost_asio/reference/raw_socket_service/close.html +/doc/html/boost_asio/reference/raw_socket_service/connect.html +/doc/html/boost_asio/reference/raw_socket_service/construct.html +/doc/html/boost_asio/reference/raw_socket_service/converting_move_construct.html +/doc/html/boost_asio/reference/raw_socket_service/destroy.html +/doc/html/boost_asio/reference/raw_socket_service/endpoint_type.html +/doc/html/boost_asio/reference/raw_socket_service/get_io_service.html +/doc/html/boost_asio/reference/raw_socket_service/get_option.html +/doc/html/boost_asio/reference/raw_socket_service.html +/doc/html/boost_asio/reference/RawSocketService.html +/doc/html/boost_asio/reference/raw_socket_service/id.html +/doc/html/boost_asio/reference/raw_socket_service/implementation_type.html +/doc/html/boost_asio/reference/raw_socket_service/io_control.html +/doc/html/boost_asio/reference/raw_socket_service/is_open.html +/doc/html/boost_asio/reference/raw_socket_service/local_endpoint.html +/doc/html/boost_asio/reference/raw_socket_service/move_assign.html +/doc/html/boost_asio/reference/raw_socket_service/move_construct.html +/doc/html/boost_asio/reference/raw_socket_service/native_handle.html +/doc/html/boost_asio/reference/raw_socket_service/native_handle_type.html +/doc/html/boost_asio/reference/raw_socket_service/native.html +/doc/html/boost_asio/reference/raw_socket_service/native_non_blocking/ +/doc/html/boost_asio/reference/raw_socket_service/native_non_blocking.html +/doc/html/boost_asio/reference/raw_socket_service/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/raw_socket_service/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/raw_socket_service/native_type.html +/doc/html/boost_asio/reference/raw_socket_service/non_blocking/ +/doc/html/boost_asio/reference/raw_socket_service/non_blocking.html +/doc/html/boost_asio/reference/raw_socket_service/non_blocking/overload1.html +/doc/html/boost_asio/reference/raw_socket_service/non_blocking/overload2.html +/doc/html/boost_asio/reference/raw_socket_service/open.html +/doc/html/boost_asio/reference/raw_socket_service/protocol_type.html +/doc/html/boost_asio/reference/raw_socket_service/raw_socket_service.html +/doc/html/boost_asio/reference/raw_socket_service/receive_from.html +/doc/html/boost_asio/reference/raw_socket_service/receive.html +/doc/html/boost_asio/reference/raw_socket_service/remote_endpoint.html +/doc/html/boost_asio/reference/raw_socket_service/send.html +/doc/html/boost_asio/reference/raw_socket_service/send_to.html +/doc/html/boost_asio/reference/raw_socket_service/set_option.html +/doc/html/boost_asio/reference/raw_socket_service/shutdown.html +/doc/html/boost_asio/reference/read/ +/doc/html/boost_asio/reference/read_at/ +/doc/html/boost_asio/reference/read_at.html +/doc/html/boost_asio/reference/read_at/overload1.html +/doc/html/boost_asio/reference/read_at/overload2.html +/doc/html/boost_asio/reference/read_at/overload3.html +/doc/html/boost_asio/reference/read_at/overload4.html +/doc/html/boost_asio/reference/read_at/overload5.html +/doc/html/boost_asio/reference/read_at/overload6.html +/doc/html/boost_asio/reference/read_at/overload7.html +/doc/html/boost_asio/reference/read_at/overload8.html +/doc/html/boost_asio/reference/ReadHandler.html +/doc/html/boost_asio/reference/read.html +/doc/html/boost_asio/reference/read/overload1.html +/doc/html/boost_asio/reference/read/overload2.html +/doc/html/boost_asio/reference/read/overload3.html +/doc/html/boost_asio/reference/read/overload4.html +/doc/html/boost_asio/reference/read/overload5.html +/doc/html/boost_asio/reference/read/overload6.html +/doc/html/boost_asio/reference/read/overload7.html +/doc/html/boost_asio/reference/read/overload8.html +/doc/html/boost_asio/reference/read_until/ +/doc/html/boost_asio/reference/read_until.html +/doc/html/boost_asio/reference/read_until/overload1.html +/doc/html/boost_asio/reference/read_until/overload2.html +/doc/html/boost_asio/reference/read_until/overload3.html +/doc/html/boost_asio/reference/read_until/overload4.html +/doc/html/boost_asio/reference/read_until/overload5.html +/doc/html/boost_asio/reference/read_until/overload6.html +/doc/html/boost_asio/reference/read_until/overload7.html +/doc/html/boost_asio/reference/read_until/overload8.html +/doc/html/boost_asio/reference/ResolveHandler.html +/doc/html/boost_asio/reference/ResolverService.html +/doc/html/boost_asio/reference/seq_packet_socket_service/ +/doc/html/boost_asio/reference/seq_packet_socket_service/assign.html +/doc/html/boost_asio/reference/seq_packet_socket_service/async_connect.html +/doc/html/boost_asio/reference/seq_packet_socket_service/async_receive.html +/doc/html/boost_asio/reference/seq_packet_socket_service/async_send.html +/doc/html/boost_asio/reference/seq_packet_socket_service/at_mark.html +/doc/html/boost_asio/reference/seq_packet_socket_service/available.html +/doc/html/boost_asio/reference/seq_packet_socket_service/bind.html +/doc/html/boost_asio/reference/seq_packet_socket_service/cancel.html +/doc/html/boost_asio/reference/seq_packet_socket_service/close.html +/doc/html/boost_asio/reference/seq_packet_socket_service/connect.html +/doc/html/boost_asio/reference/seq_packet_socket_service/construct.html +/doc/html/boost_asio/reference/seq_packet_socket_service/converting_move_construct.html +/doc/html/boost_asio/reference/seq_packet_socket_service/destroy.html +/doc/html/boost_asio/reference/seq_packet_socket_service/endpoint_type.html +/doc/html/boost_asio/reference/seq_packet_socket_service/get_io_service.html +/doc/html/boost_asio/reference/seq_packet_socket_service/get_option.html +/doc/html/boost_asio/reference/seq_packet_socket_service.html +/doc/html/boost_asio/reference/SeqPacketSocketService.html +/doc/html/boost_asio/reference/seq_packet_socket_service/id.html +/doc/html/boost_asio/reference/seq_packet_socket_service/implementation_type.html +/doc/html/boost_asio/reference/seq_packet_socket_service/io_control.html +/doc/html/boost_asio/reference/seq_packet_socket_service/is_open.html +/doc/html/boost_asio/reference/seq_packet_socket_service/local_endpoint.html +/doc/html/boost_asio/reference/seq_packet_socket_service/move_assign.html +/doc/html/boost_asio/reference/seq_packet_socket_service/move_construct.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native_handle.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native_handle_type.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native_non_blocking/ +/doc/html/boost_asio/reference/seq_packet_socket_service/native_non_blocking.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/seq_packet_socket_service/native_type.html +/doc/html/boost_asio/reference/seq_packet_socket_service/non_blocking/ +/doc/html/boost_asio/reference/seq_packet_socket_service/non_blocking.html +/doc/html/boost_asio/reference/seq_packet_socket_service/non_blocking/overload1.html +/doc/html/boost_asio/reference/seq_packet_socket_service/non_blocking/overload2.html +/doc/html/boost_asio/reference/seq_packet_socket_service/open.html +/doc/html/boost_asio/reference/seq_packet_socket_service/protocol_type.html +/doc/html/boost_asio/reference/seq_packet_socket_service/receive.html +/doc/html/boost_asio/reference/seq_packet_socket_service/remote_endpoint.html +/doc/html/boost_asio/reference/seq_packet_socket_service/send.html +/doc/html/boost_asio/reference/seq_packet_socket_service/seq_packet_socket_service.html +/doc/html/boost_asio/reference/seq_packet_socket_service/set_option.html +/doc/html/boost_asio/reference/seq_packet_socket_service/shutdown.html +/doc/html/boost_asio/reference/serial_port_base/ +/doc/html/boost_asio/reference/serial_port_base__baud_rate/ +/doc/html/boost_asio/reference/serial_port_base__baud_rate/baud_rate.html +/doc/html/boost_asio/reference/serial_port_base__baud_rate.html +/doc/html/boost_asio/reference/serial_port_base__baud_rate/load.html +/doc/html/boost_asio/reference/serial_port_base__baud_rate/store.html +/doc/html/boost_asio/reference/serial_port_base__baud_rate/value.html +/doc/html/boost_asio/reference/serial_port_base__character_size/ +/doc/html/boost_asio/reference/serial_port_base__character_size/character_size.html +/doc/html/boost_asio/reference/serial_port_base__character_size.html +/doc/html/boost_asio/reference/serial_port_base__character_size/load.html +/doc/html/boost_asio/reference/serial_port_base__character_size/store.html +/doc/html/boost_asio/reference/serial_port_base__character_size/value.html +/doc/html/boost_asio/reference/serial_port_base__flow_control/ +/doc/html/boost_asio/reference/serial_port_base__flow_control/flow_control.html +/doc/html/boost_asio/reference/serial_port_base__flow_control.html +/doc/html/boost_asio/reference/serial_port_base__flow_control/load.html +/doc/html/boost_asio/reference/serial_port_base__flow_control/store.html +/doc/html/boost_asio/reference/serial_port_base__flow_control/type.html +/doc/html/boost_asio/reference/serial_port_base__flow_control/value.html +/doc/html/boost_asio/reference/serial_port_base.html +/doc/html/boost_asio/reference/serial_port_base__parity/ +/doc/html/boost_asio/reference/serial_port_base__parity.html +/doc/html/boost_asio/reference/serial_port_base__parity/load.html +/doc/html/boost_asio/reference/serial_port_base__parity/parity.html +/doc/html/boost_asio/reference/serial_port_base__parity/store.html +/doc/html/boost_asio/reference/serial_port_base__parity/type.html +/doc/html/boost_asio/reference/serial_port_base__parity/value.html +/doc/html/boost_asio/reference/serial_port_base/_serial_port_base.html +/doc/html/boost_asio/reference/serial_port_base__stop_bits/ +/doc/html/boost_asio/reference/serial_port_base__stop_bits.html +/doc/html/boost_asio/reference/serial_port_base__stop_bits/load.html +/doc/html/boost_asio/reference/serial_port_base__stop_bits/stop_bits.html +/doc/html/boost_asio/reference/serial_port_base__stop_bits/store.html +/doc/html/boost_asio/reference/serial_port_base__stop_bits/type.html +/doc/html/boost_asio/reference/serial_port_base__stop_bits/value.html +/doc/html/boost_asio/reference/serial_port.html +/doc/html/boost_asio/reference/serial_port_service/ +/doc/html/boost_asio/reference/serial_port_service/assign.html +/doc/html/boost_asio/reference/serial_port_service/async_read_some.html +/doc/html/boost_asio/reference/serial_port_service/async_write_some.html +/doc/html/boost_asio/reference/serial_port_service/cancel.html +/doc/html/boost_asio/reference/serial_port_service/close.html +/doc/html/boost_asio/reference/serial_port_service/construct.html +/doc/html/boost_asio/reference/serial_port_service/destroy.html +/doc/html/boost_asio/reference/serial_port_service/get_io_service.html +/doc/html/boost_asio/reference/serial_port_service/get_option.html +/doc/html/boost_asio/reference/serial_port_service.html +/doc/html/boost_asio/reference/SerialPortService.html +/doc/html/boost_asio/reference/serial_port_service/id.html +/doc/html/boost_asio/reference/serial_port_service/implementation_type.html +/doc/html/boost_asio/reference/serial_port_service/is_open.html +/doc/html/boost_asio/reference/serial_port_service/move_assign.html +/doc/html/boost_asio/reference/serial_port_service/move_construct.html +/doc/html/boost_asio/reference/serial_port_service/native_handle.html +/doc/html/boost_asio/reference/serial_port_service/native_handle_type.html +/doc/html/boost_asio/reference/serial_port_service/native.html +/doc/html/boost_asio/reference/serial_port_service/native_type.html +/doc/html/boost_asio/reference/serial_port_service/open.html +/doc/html/boost_asio/reference/serial_port_service/read_some.html +/doc/html/boost_asio/reference/serial_port_service/send_break.html +/doc/html/boost_asio/reference/serial_port_service/serial_port_service.html +/doc/html/boost_asio/reference/serial_port_service/set_option.html +/doc/html/boost_asio/reference/serial_port_service/write_some.html +/doc/html/boost_asio/reference/service_already_exists/ +/doc/html/boost_asio/reference/service_already_exists.html +/doc/html/boost_asio/reference/service_already_exists/service_already_exists.html +/doc/html/boost_asio/reference/Service.html +/doc/html/boost_asio/reference/SettableSerialPortOption.html +/doc/html/boost_asio/reference/SettableSocketOption.html +/doc/html/boost_asio/reference/ShutdownHandler.html +/doc/html/boost_asio/reference/SignalHandler.html +/doc/html/boost_asio/reference/signal_set.html +/doc/html/boost_asio/reference/signal_set_service/ +/doc/html/boost_asio/reference/signal_set_service/add.html +/doc/html/boost_asio/reference/signal_set_service/async_wait.html +/doc/html/boost_asio/reference/signal_set_service/cancel.html +/doc/html/boost_asio/reference/signal_set_service/clear.html +/doc/html/boost_asio/reference/signal_set_service/construct.html +/doc/html/boost_asio/reference/signal_set_service/destroy.html +/doc/html/boost_asio/reference/signal_set_service/get_io_service.html +/doc/html/boost_asio/reference/signal_set_service.html +/doc/html/boost_asio/reference/SignalSetService.html +/doc/html/boost_asio/reference/signal_set_service/id.html +/doc/html/boost_asio/reference/signal_set_service/implementation_type.html +/doc/html/boost_asio/reference/signal_set_service/remove.html +/doc/html/boost_asio/reference/signal_set_service/signal_set_service.html +/doc/html/boost_asio/reference/socket_acceptor_service/ +/doc/html/boost_asio/reference/socket_acceptor_service/accept.html +/doc/html/boost_asio/reference/socket_acceptor_service/assign.html +/doc/html/boost_asio/reference/socket_acceptor_service/async_accept.html +/doc/html/boost_asio/reference/socket_acceptor_service/bind.html +/doc/html/boost_asio/reference/socket_acceptor_service/cancel.html +/doc/html/boost_asio/reference/socket_acceptor_service/close.html +/doc/html/boost_asio/reference/socket_acceptor_service/construct.html +/doc/html/boost_asio/reference/socket_acceptor_service/converting_move_construct.html +/doc/html/boost_asio/reference/socket_acceptor_service/destroy.html +/doc/html/boost_asio/reference/socket_acceptor_service/endpoint_type.html +/doc/html/boost_asio/reference/socket_acceptor_service/get_io_service.html +/doc/html/boost_asio/reference/socket_acceptor_service/get_option.html +/doc/html/boost_asio/reference/socket_acceptor_service.html +/doc/html/boost_asio/reference/SocketAcceptorService.html +/doc/html/boost_asio/reference/socket_acceptor_service/id.html +/doc/html/boost_asio/reference/socket_acceptor_service/implementation_type.html +/doc/html/boost_asio/reference/socket_acceptor_service/io_control.html +/doc/html/boost_asio/reference/socket_acceptor_service/is_open.html +/doc/html/boost_asio/reference/socket_acceptor_service/listen.html +/doc/html/boost_asio/reference/socket_acceptor_service/local_endpoint.html +/doc/html/boost_asio/reference/socket_acceptor_service/move_assign.html +/doc/html/boost_asio/reference/socket_acceptor_service/move_construct.html +/doc/html/boost_asio/reference/socket_acceptor_service/native_handle.html +/doc/html/boost_asio/reference/socket_acceptor_service/native_handle_type.html +/doc/html/boost_asio/reference/socket_acceptor_service/native.html +/doc/html/boost_asio/reference/socket_acceptor_service/native_non_blocking/ +/doc/html/boost_asio/reference/socket_acceptor_service/native_non_blocking.html +/doc/html/boost_asio/reference/socket_acceptor_service/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/socket_acceptor_service/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/socket_acceptor_service/native_type.html +/doc/html/boost_asio/reference/socket_acceptor_service/non_blocking/ +/doc/html/boost_asio/reference/socket_acceptor_service/non_blocking.html +/doc/html/boost_asio/reference/socket_acceptor_service/non_blocking/overload1.html +/doc/html/boost_asio/reference/socket_acceptor_service/non_blocking/overload2.html +/doc/html/boost_asio/reference/socket_acceptor_service/open.html +/doc/html/boost_asio/reference/socket_acceptor_service/protocol_type.html +/doc/html/boost_asio/reference/socket_acceptor_service/set_option.html +/doc/html/boost_asio/reference/socket_acceptor_service/socket_acceptor_service.html +/doc/html/boost_asio/reference/socket_base/ +/doc/html/boost_asio/reference/socket_base/broadcast.html +/doc/html/boost_asio/reference/socket_base/bytes_readable.html +/doc/html/boost_asio/reference/socket_base/debug.html +/doc/html/boost_asio/reference/socket_base/do_not_route.html +/doc/html/boost_asio/reference/socket_base/enable_connection_aborted.html +/doc/html/boost_asio/reference/socket_base.html +/doc/html/boost_asio/reference/socket_base/keep_alive.html +/doc/html/boost_asio/reference/socket_base/linger.html +/doc/html/boost_asio/reference/socket_base/max_connections.html +/doc/html/boost_asio/reference/socket_base/message_do_not_route.html +/doc/html/boost_asio/reference/socket_base/message_end_of_record.html +/doc/html/boost_asio/reference/socket_base/message_flags.html +/doc/html/boost_asio/reference/socket_base/message_out_of_band.html +/doc/html/boost_asio/reference/socket_base/message_peek.html +/doc/html/boost_asio/reference/socket_base/non_blocking_io.html +/doc/html/boost_asio/reference/socket_base/receive_buffer_size.html +/doc/html/boost_asio/reference/socket_base/receive_low_watermark.html +/doc/html/boost_asio/reference/socket_base/reuse_address.html +/doc/html/boost_asio/reference/socket_base/send_buffer_size.html +/doc/html/boost_asio/reference/socket_base/send_low_watermark.html +/doc/html/boost_asio/reference/socket_base/shutdown_type.html +/doc/html/boost_asio/reference/socket_base/_socket_base.html +/doc/html/boost_asio/reference/SocketService.html +/doc/html/boost_asio/reference/spawn/ +/doc/html/boost_asio/reference/spawn.html +/doc/html/boost_asio/reference/spawn/overload1.html +/doc/html/boost_asio/reference/spawn/overload2.html +/doc/html/boost_asio/reference/spawn/overload3.html +/doc/html/boost_asio/reference/spawn/overload4.html +/doc/html/boost_asio/reference/ssl__context/ +/doc/html/boost_asio/reference/ssl__context/add_certificate_authority/ +/doc/html/boost_asio/reference/ssl__context/add_certificate_authority.html +/doc/html/boost_asio/reference/ssl__context/add_certificate_authority/overload1.html +/doc/html/boost_asio/reference/ssl__context/add_certificate_authority/overload2.html +/doc/html/boost_asio/reference/ssl__context/add_verify_path/ +/doc/html/boost_asio/reference/ssl__context/add_verify_path.html +/doc/html/boost_asio/reference/ssl__context/add_verify_path/overload1.html +/doc/html/boost_asio/reference/ssl__context/add_verify_path/overload2.html +/doc/html/boost_asio/reference/ssl__context_base/ +/doc/html/boost_asio/reference/ssl__context_base/_context_base.html +/doc/html/boost_asio/reference/ssl__context_base/default_workarounds.html +/doc/html/boost_asio/reference/ssl__context_base/file_format.html +/doc/html/boost_asio/reference/ssl__context_base.html +/doc/html/boost_asio/reference/ssl__context_base/method.html +/doc/html/boost_asio/reference/ssl__context_base/no_compression.html +/doc/html/boost_asio/reference/ssl__context_base/no_sslv2.html +/doc/html/boost_asio/reference/ssl__context_base/no_sslv3.html +/doc/html/boost_asio/reference/ssl__context_base/no_tlsv1_1.html +/doc/html/boost_asio/reference/ssl__context_base/no_tlsv1_2.html +/doc/html/boost_asio/reference/ssl__context_base/no_tlsv1.html +/doc/html/boost_asio/reference/ssl__context_base/options.html +/doc/html/boost_asio/reference/ssl__context_base/password_purpose.html +/doc/html/boost_asio/reference/ssl__context_base/single_dh_use.html +/doc/html/boost_asio/reference/ssl__context/clear_options/ +/doc/html/boost_asio/reference/ssl__context/clear_options.html +/doc/html/boost_asio/reference/ssl__context/clear_options/overload1.html +/doc/html/boost_asio/reference/ssl__context/clear_options/overload2.html +/doc/html/boost_asio/reference/ssl__context/context/ +/doc/html/boost_asio/reference/ssl__context/_context.html +/doc/html/boost_asio/reference/ssl__context/context.html +/doc/html/boost_asio/reference/ssl__context/context/overload1.html +/doc/html/boost_asio/reference/ssl__context/context/overload2.html +/doc/html/boost_asio/reference/ssl__context/context/overload3.html +/doc/html/boost_asio/reference/ssl__context/default_workarounds.html +/doc/html/boost_asio/reference/ssl__context/file_format.html +/doc/html/boost_asio/reference/ssl__context.html +/doc/html/boost_asio/reference/ssl__context/impl.html +/doc/html/boost_asio/reference/ssl__context/impl_type.html +/doc/html/boost_asio/reference/ssl__context/load_verify_file/ +/doc/html/boost_asio/reference/ssl__context/load_verify_file.html +/doc/html/boost_asio/reference/ssl__context/load_verify_file/overload1.html +/doc/html/boost_asio/reference/ssl__context/load_verify_file/overload2.html +/doc/html/boost_asio/reference/ssl__context/method.html +/doc/html/boost_asio/reference/ssl__context/native_handle.html +/doc/html/boost_asio/reference/ssl__context/native_handle_type.html +/doc/html/boost_asio/reference/ssl__context/no_compression.html +/doc/html/boost_asio/reference/ssl__context/no_sslv2.html +/doc/html/boost_asio/reference/ssl__context/no_sslv3.html +/doc/html/boost_asio/reference/ssl__context/no_tlsv1_1.html +/doc/html/boost_asio/reference/ssl__context/no_tlsv1_2.html +/doc/html/boost_asio/reference/ssl__context/no_tlsv1.html +/doc/html/boost_asio/reference/ssl__context/operator_eq_.html +/doc/html/boost_asio/reference/ssl__context/options.html +/doc/html/boost_asio/reference/ssl__context/password_purpose.html +/doc/html/boost_asio/reference/ssl__context/set_default_verify_paths/ +/doc/html/boost_asio/reference/ssl__context/set_default_verify_paths.html +/doc/html/boost_asio/reference/ssl__context/set_default_verify_paths/overload1.html +/doc/html/boost_asio/reference/ssl__context/set_default_verify_paths/overload2.html +/doc/html/boost_asio/reference/ssl__context/set_options/ +/doc/html/boost_asio/reference/ssl__context/set_options.html +/doc/html/boost_asio/reference/ssl__context/set_options/overload1.html +/doc/html/boost_asio/reference/ssl__context/set_options/overload2.html +/doc/html/boost_asio/reference/ssl__context/set_password_callback/ +/doc/html/boost_asio/reference/ssl__context/set_password_callback.html +/doc/html/boost_asio/reference/ssl__context/set_password_callback/overload1.html +/doc/html/boost_asio/reference/ssl__context/set_password_callback/overload2.html +/doc/html/boost_asio/reference/ssl__context/set_verify_callback/ +/doc/html/boost_asio/reference/ssl__context/set_verify_callback.html +/doc/html/boost_asio/reference/ssl__context/set_verify_callback/overload1.html +/doc/html/boost_asio/reference/ssl__context/set_verify_callback/overload2.html +/doc/html/boost_asio/reference/ssl__context/set_verify_depth/ +/doc/html/boost_asio/reference/ssl__context/set_verify_depth.html +/doc/html/boost_asio/reference/ssl__context/set_verify_depth/overload1.html +/doc/html/boost_asio/reference/ssl__context/set_verify_depth/overload2.html +/doc/html/boost_asio/reference/ssl__context/set_verify_mode/ +/doc/html/boost_asio/reference/ssl__context/set_verify_mode.html +/doc/html/boost_asio/reference/ssl__context/set_verify_mode/overload1.html +/doc/html/boost_asio/reference/ssl__context/set_verify_mode/overload2.html +/doc/html/boost_asio/reference/ssl__context/single_dh_use.html +/doc/html/boost_asio/reference/ssl__context/use_certificate/ +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain/ +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain_file/ +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain_file.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain_file/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain_file/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_chain/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_file/ +/doc/html/boost_asio/reference/ssl__context/use_certificate_file.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_file/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_certificate_file/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_certificate.html +/doc/html/boost_asio/reference/ssl__context/use_certificate/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_certificate/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_private_key/ +/doc/html/boost_asio/reference/ssl__context/use_private_key_file/ +/doc/html/boost_asio/reference/ssl__context/use_private_key_file.html +/doc/html/boost_asio/reference/ssl__context/use_private_key_file/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_private_key_file/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_private_key.html +/doc/html/boost_asio/reference/ssl__context/use_private_key/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_private_key/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key/ +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key_file/ +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key_file.html +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key_file/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key_file/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key.html +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_rsa_private_key/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh/ +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh_file/ +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh_file.html +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh_file/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh_file/overload2.html +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh.html +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh/overload1.html +/doc/html/boost_asio/reference/ssl__context/use_tmp_dh/overload2.html +/doc/html/boost_asio/reference/ssl__error__get_stream_category.html +/doc/html/boost_asio/reference/ssl__error__make_error_code.html +/doc/html/boost_asio/reference/ssl__error__stream_category.html +/doc/html/boost_asio/reference/ssl__error__stream_errors.html +/doc/html/boost_asio/reference/ssl__rfc2818_verification/ +/doc/html/boost_asio/reference/ssl__rfc2818_verification.html +/doc/html/boost_asio/reference/ssl__rfc2818_verification/operator_lp__rp_.html +/doc/html/boost_asio/reference/ssl__rfc2818_verification/result_type.html +/doc/html/boost_asio/reference/ssl__rfc2818_verification/rfc2818_verification.html +/doc/html/boost_asio/reference/ssl__stream/ +/doc/html/boost_asio/reference/ssl__stream/async_handshake/ +/doc/html/boost_asio/reference/ssl__stream/async_handshake.html +/doc/html/boost_asio/reference/ssl__stream/async_handshake/overload1.html +/doc/html/boost_asio/reference/ssl__stream/async_handshake/overload2.html +/doc/html/boost_asio/reference/ssl__stream/async_read_some.html +/doc/html/boost_asio/reference/ssl__stream/async_shutdown.html +/doc/html/boost_asio/reference/ssl__stream/async_write_some.html +/doc/html/boost_asio/reference/ssl__stream_base/ +/doc/html/boost_asio/reference/ssl__stream_base/handshake_type.html +/doc/html/boost_asio/reference/ssl__stream_base.html +/doc/html/boost_asio/reference/ssl__stream_base/_stream_base.html +/doc/html/boost_asio/reference/ssl__stream/get_io_service.html +/doc/html/boost_asio/reference/ssl__stream/handshake/ +/doc/html/boost_asio/reference/ssl__stream/handshake.html +/doc/html/boost_asio/reference/ssl__stream/handshake/overload1.html +/doc/html/boost_asio/reference/ssl__stream/handshake/overload2.html +/doc/html/boost_asio/reference/ssl__stream/handshake/overload3.html +/doc/html/boost_asio/reference/ssl__stream/handshake/overload4.html +/doc/html/boost_asio/reference/ssl__stream/handshake_type.html +/doc/html/boost_asio/reference/ssl__stream.html +/doc/html/boost_asio/reference/ssl__stream/impl.html +/doc/html/boost_asio/reference/ssl__stream__impl_struct/ +/doc/html/boost_asio/reference/ssl__stream__impl_struct.html +/doc/html/boost_asio/reference/ssl__stream__impl_struct/ssl.html +/doc/html/boost_asio/reference/ssl__stream/impl_type.html +/doc/html/boost_asio/reference/ssl__stream/lowest_layer/ +/doc/html/boost_asio/reference/ssl__stream/lowest_layer.html +/doc/html/boost_asio/reference/ssl__stream/lowest_layer/overload1.html +/doc/html/boost_asio/reference/ssl__stream/lowest_layer/overload2.html +/doc/html/boost_asio/reference/ssl__stream/lowest_layer_type.html +/doc/html/boost_asio/reference/ssl__stream/native_handle.html +/doc/html/boost_asio/reference/ssl__stream/native_handle_type.html +/doc/html/boost_asio/reference/ssl__stream/next_layer/ +/doc/html/boost_asio/reference/ssl__stream/next_layer.html +/doc/html/boost_asio/reference/ssl__stream/next_layer/overload1.html +/doc/html/boost_asio/reference/ssl__stream/next_layer/overload2.html +/doc/html/boost_asio/reference/ssl__stream/next_layer_type.html +/doc/html/boost_asio/reference/ssl__stream/read_some/ +/doc/html/boost_asio/reference/ssl__stream/read_some.html +/doc/html/boost_asio/reference/ssl__stream/read_some/overload1.html +/doc/html/boost_asio/reference/ssl__stream/read_some/overload2.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_callback/ +/doc/html/boost_asio/reference/ssl__stream/set_verify_callback.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_callback/overload1.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_callback/overload2.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_depth/ +/doc/html/boost_asio/reference/ssl__stream/set_verify_depth.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_depth/overload1.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_depth/overload2.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_mode/ +/doc/html/boost_asio/reference/ssl__stream/set_verify_mode.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_mode/overload1.html +/doc/html/boost_asio/reference/ssl__stream/set_verify_mode/overload2.html +/doc/html/boost_asio/reference/ssl__stream/shutdown/ +/doc/html/boost_asio/reference/ssl__stream/shutdown.html +/doc/html/boost_asio/reference/ssl__stream/shutdown/overload1.html +/doc/html/boost_asio/reference/ssl__stream/shutdown/overload2.html +/doc/html/boost_asio/reference/ssl__stream/_stream.html +/doc/html/boost_asio/reference/ssl__stream/stream.html +/doc/html/boost_asio/reference/ssl__stream/write_some/ +/doc/html/boost_asio/reference/ssl__stream/write_some.html +/doc/html/boost_asio/reference/ssl__stream/write_some/overload1.html +/doc/html/boost_asio/reference/ssl__stream/write_some/overload2.html +/doc/html/boost_asio/reference/ssl__verify_client_once.html +/doc/html/boost_asio/reference/ssl__verify_context/ +/doc/html/boost_asio/reference/ssl__verify_context.html +/doc/html/boost_asio/reference/ssl__verify_context/native_handle.html +/doc/html/boost_asio/reference/ssl__verify_context/native_handle_type.html +/doc/html/boost_asio/reference/ssl__verify_context/verify_context.html +/doc/html/boost_asio/reference/ssl__verify_fail_if_no_peer_cert.html +/doc/html/boost_asio/reference/ssl__verify_mode.html +/doc/html/boost_asio/reference/ssl__verify_none.html +/doc/html/boost_asio/reference/ssl__verify_peer.html +/doc/html/boost_asio/reference/steady_timer.html +/doc/html/boost_asio/reference/strand.html +/doc/html/boost_asio/reference/streambuf.html +/doc/html/boost_asio/reference/StreamDescriptorService.html +/doc/html/boost_asio/reference/StreamHandleService.html +/doc/html/boost_asio/reference/stream_socket_service/ +/doc/html/boost_asio/reference/stream_socket_service/assign.html +/doc/html/boost_asio/reference/stream_socket_service/async_connect.html +/doc/html/boost_asio/reference/stream_socket_service/async_receive.html +/doc/html/boost_asio/reference/stream_socket_service/async_send.html +/doc/html/boost_asio/reference/stream_socket_service/at_mark.html +/doc/html/boost_asio/reference/stream_socket_service/available.html +/doc/html/boost_asio/reference/stream_socket_service/bind.html +/doc/html/boost_asio/reference/stream_socket_service/cancel.html +/doc/html/boost_asio/reference/stream_socket_service/close.html +/doc/html/boost_asio/reference/stream_socket_service/connect.html +/doc/html/boost_asio/reference/stream_socket_service/construct.html +/doc/html/boost_asio/reference/stream_socket_service/converting_move_construct.html +/doc/html/boost_asio/reference/stream_socket_service/destroy.html +/doc/html/boost_asio/reference/stream_socket_service/endpoint_type.html +/doc/html/boost_asio/reference/stream_socket_service/get_io_service.html +/doc/html/boost_asio/reference/stream_socket_service/get_option.html +/doc/html/boost_asio/reference/stream_socket_service.html +/doc/html/boost_asio/reference/StreamSocketService.html +/doc/html/boost_asio/reference/stream_socket_service/id.html +/doc/html/boost_asio/reference/stream_socket_service/implementation_type.html +/doc/html/boost_asio/reference/stream_socket_service/io_control.html +/doc/html/boost_asio/reference/stream_socket_service/is_open.html +/doc/html/boost_asio/reference/stream_socket_service/local_endpoint.html +/doc/html/boost_asio/reference/stream_socket_service/move_assign.html +/doc/html/boost_asio/reference/stream_socket_service/move_construct.html +/doc/html/boost_asio/reference/stream_socket_service/native_handle.html +/doc/html/boost_asio/reference/stream_socket_service/native_handle_type.html +/doc/html/boost_asio/reference/stream_socket_service/native.html +/doc/html/boost_asio/reference/stream_socket_service/native_non_blocking/ +/doc/html/boost_asio/reference/stream_socket_service/native_non_blocking.html +/doc/html/boost_asio/reference/stream_socket_service/native_non_blocking/overload1.html +/doc/html/boost_asio/reference/stream_socket_service/native_non_blocking/overload2.html +/doc/html/boost_asio/reference/stream_socket_service/native_type.html +/doc/html/boost_asio/reference/stream_socket_service/non_blocking/ +/doc/html/boost_asio/reference/stream_socket_service/non_blocking.html +/doc/html/boost_asio/reference/stream_socket_service/non_blocking/overload1.html +/doc/html/boost_asio/reference/stream_socket_service/non_blocking/overload2.html +/doc/html/boost_asio/reference/stream_socket_service/open.html +/doc/html/boost_asio/reference/stream_socket_service/protocol_type.html +/doc/html/boost_asio/reference/stream_socket_service/receive.html +/doc/html/boost_asio/reference/stream_socket_service/remote_endpoint.html +/doc/html/boost_asio/reference/stream_socket_service/send.html +/doc/html/boost_asio/reference/stream_socket_service/set_option.html +/doc/html/boost_asio/reference/stream_socket_service/shutdown.html +/doc/html/boost_asio/reference/stream_socket_service/stream_socket_service.html +/doc/html/boost_asio/reference/SyncRandomAccessReadDevice.html +/doc/html/boost_asio/reference/SyncRandomAccessWriteDevice.html +/doc/html/boost_asio/reference/SyncReadStream.html +/doc/html/boost_asio/reference/SyncWriteStream.html +/doc/html/boost_asio/reference/system_timer.html +/doc/html/boost_asio/reference/TimerService.html +/doc/html/boost_asio/reference/TimeTraits.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/ +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/add.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/duration_type.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/less_than.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/now.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/subtract.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/time_type.html +/doc/html/boost_asio/reference/time_traits_lt__ptime__gt_/to_posix_duration.html +/doc/html/boost_asio/reference/transfer_all.html +/doc/html/boost_asio/reference/transfer_at_least.html +/doc/html/boost_asio/reference/transfer_exactly.html +/doc/html/boost_asio/reference/use_future.html +/doc/html/boost_asio/reference/use_future_t/ +/doc/html/boost_asio/reference/use_future_t/allocator_type.html +/doc/html/boost_asio/reference/use_future_t/get_allocator.html +/doc/html/boost_asio/reference/use_future_t.html +/doc/html/boost_asio/reference/use_future_t/operator_lb__rb_.html +/doc/html/boost_asio/reference/use_future_t/use_future_t/ +/doc/html/boost_asio/reference/use_future_t/use_future_t.html +/doc/html/boost_asio/reference/use_future_t/use_future_t/overload1.html +/doc/html/boost_asio/reference/use_future_t/use_future_t/overload2.html +/doc/html/boost_asio/reference/use_service.html +/doc/html/boost_asio/reference/waitable_timer_service/ +/doc/html/boost_asio/reference/waitable_timer_service/async_wait.html +/doc/html/boost_asio/reference/waitable_timer_service/cancel.html +/doc/html/boost_asio/reference/waitable_timer_service/cancel_one.html +/doc/html/boost_asio/reference/waitable_timer_service/clock_type.html +/doc/html/boost_asio/reference/waitable_timer_service/construct.html +/doc/html/boost_asio/reference/waitable_timer_service/destroy.html +/doc/html/boost_asio/reference/waitable_timer_service/duration.html +/doc/html/boost_asio/reference/waitable_timer_service/expires_at/ +/doc/html/boost_asio/reference/waitable_timer_service/expires_at.html +/doc/html/boost_asio/reference/waitable_timer_service/expires_at/overload1.html +/doc/html/boost_asio/reference/waitable_timer_service/expires_at/overload2.html +/doc/html/boost_asio/reference/waitable_timer_service/expires_from_now/ +/doc/html/boost_asio/reference/waitable_timer_service/expires_from_now.html +/doc/html/boost_asio/reference/waitable_timer_service/expires_from_now/overload1.html +/doc/html/boost_asio/reference/waitable_timer_service/expires_from_now/overload2.html +/doc/html/boost_asio/reference/waitable_timer_service/get_io_service.html +/doc/html/boost_asio/reference/waitable_timer_service.html +/doc/html/boost_asio/reference/WaitableTimerService.html +/doc/html/boost_asio/reference/waitable_timer_service/id.html +/doc/html/boost_asio/reference/waitable_timer_service/implementation_type.html +/doc/html/boost_asio/reference/waitable_timer_service/time_point.html +/doc/html/boost_asio/reference/waitable_timer_service/traits_type.html +/doc/html/boost_asio/reference/waitable_timer_service/waitable_timer_service.html +/doc/html/boost_asio/reference/waitable_timer_service/wait.html +/doc/html/boost_asio/reference/WaitHandler.html +/doc/html/boost_asio/reference/wait_traits/ +/doc/html/boost_asio/reference/wait_traits.html +/doc/html/boost_asio/reference/WaitTraits.html +/doc/html/boost_asio/reference/wait_traits/to_wait_duration.html +/doc/html/boost_asio/reference/windows__basic_handle/ +/doc/html/boost_asio/reference/windows__basic_handle/assign/ +/doc/html/boost_asio/reference/windows__basic_handle/assign.html +/doc/html/boost_asio/reference/windows__basic_handle/assign/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/assign/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle/basic_handle/ +/doc/html/boost_asio/reference/windows__basic_handle/_basic_handle.html +/doc/html/boost_asio/reference/windows__basic_handle/basic_handle.html +/doc/html/boost_asio/reference/windows__basic_handle/basic_handle/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/basic_handle/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle/basic_handle/overload3.html +/doc/html/boost_asio/reference/windows__basic_handle/cancel/ +/doc/html/boost_asio/reference/windows__basic_handle/cancel.html +/doc/html/boost_asio/reference/windows__basic_handle/cancel/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/cancel/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle/close/ +/doc/html/boost_asio/reference/windows__basic_handle/close.html +/doc/html/boost_asio/reference/windows__basic_handle/close/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/close/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle/get_implementation/ +/doc/html/boost_asio/reference/windows__basic_handle/get_implementation.html +/doc/html/boost_asio/reference/windows__basic_handle/get_implementation/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/get_implementation/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle/get_io_service.html +/doc/html/boost_asio/reference/windows__basic_handle/get_service/ +/doc/html/boost_asio/reference/windows__basic_handle/get_service.html +/doc/html/boost_asio/reference/windows__basic_handle/get_service/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/get_service/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle.html +/doc/html/boost_asio/reference/windows__basic_handle/implementation.html +/doc/html/boost_asio/reference/windows__basic_handle/implementation_type.html +/doc/html/boost_asio/reference/windows__basic_handle/is_open.html +/doc/html/boost_asio/reference/windows__basic_handle/lowest_layer/ +/doc/html/boost_asio/reference/windows__basic_handle/lowest_layer.html +/doc/html/boost_asio/reference/windows__basic_handle/lowest_layer/overload1.html +/doc/html/boost_asio/reference/windows__basic_handle/lowest_layer/overload2.html +/doc/html/boost_asio/reference/windows__basic_handle/lowest_layer_type.html +/doc/html/boost_asio/reference/windows__basic_handle/native_handle.html +/doc/html/boost_asio/reference/windows__basic_handle/native_handle_type.html +/doc/html/boost_asio/reference/windows__basic_handle/native.html +/doc/html/boost_asio/reference/windows__basic_handle/native_type.html +/doc/html/boost_asio/reference/windows__basic_handle/operator_eq_.html +/doc/html/boost_asio/reference/windows__basic_handle/service.html +/doc/html/boost_asio/reference/windows__basic_handle/service_type.html +/doc/html/boost_asio/reference/windows__basic_object_handle/ +/doc/html/boost_asio/reference/windows__basic_object_handle/assign/ +/doc/html/boost_asio/reference/windows__basic_object_handle/assign.html +/doc/html/boost_asio/reference/windows__basic_object_handle/assign/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/assign/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle/async_wait.html +/doc/html/boost_asio/reference/windows__basic_object_handle/basic_object_handle/ +/doc/html/boost_asio/reference/windows__basic_object_handle/basic_object_handle.html +/doc/html/boost_asio/reference/windows__basic_object_handle/basic_object_handle/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/basic_object_handle/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle/basic_object_handle/overload3.html +/doc/html/boost_asio/reference/windows__basic_object_handle/cancel/ +/doc/html/boost_asio/reference/windows__basic_object_handle/cancel.html +/doc/html/boost_asio/reference/windows__basic_object_handle/cancel/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/cancel/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle/close/ +/doc/html/boost_asio/reference/windows__basic_object_handle/close.html +/doc/html/boost_asio/reference/windows__basic_object_handle/close/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/close/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_implementation/ +/doc/html/boost_asio/reference/windows__basic_object_handle/get_implementation.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_implementation/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_implementation/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_io_service.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_service/ +/doc/html/boost_asio/reference/windows__basic_object_handle/get_service.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_service/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/get_service/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle.html +/doc/html/boost_asio/reference/windows__basic_object_handle/implementation.html +/doc/html/boost_asio/reference/windows__basic_object_handle/implementation_type.html +/doc/html/boost_asio/reference/windows__basic_object_handle/is_open.html +/doc/html/boost_asio/reference/windows__basic_object_handle/lowest_layer/ +/doc/html/boost_asio/reference/windows__basic_object_handle/lowest_layer.html +/doc/html/boost_asio/reference/windows__basic_object_handle/lowest_layer/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/lowest_layer/overload2.html +/doc/html/boost_asio/reference/windows__basic_object_handle/lowest_layer_type.html +/doc/html/boost_asio/reference/windows__basic_object_handle/native_handle.html +/doc/html/boost_asio/reference/windows__basic_object_handle/native_handle_type.html +/doc/html/boost_asio/reference/windows__basic_object_handle/native.html +/doc/html/boost_asio/reference/windows__basic_object_handle/native_type.html +/doc/html/boost_asio/reference/windows__basic_object_handle/operator_eq_.html +/doc/html/boost_asio/reference/windows__basic_object_handle/service.html +/doc/html/boost_asio/reference/windows__basic_object_handle/service_type.html +/doc/html/boost_asio/reference/windows__basic_object_handle/wait/ +/doc/html/boost_asio/reference/windows__basic_object_handle/wait.html +/doc/html/boost_asio/reference/windows__basic_object_handle/wait/overload1.html +/doc/html/boost_asio/reference/windows__basic_object_handle/wait/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/assign/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/assign.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/assign/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/assign/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/async_read_some_at.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/async_write_some_at.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/basic_random_access_handle/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/basic_random_access_handle.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/basic_random_access_handle/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/basic_random_access_handle/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/basic_random_access_handle/overload3.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/cancel/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/cancel.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/cancel/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/cancel/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/close/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/close.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/close/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/close/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_implementation/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_implementation.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_implementation/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_implementation/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_io_service.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_service/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_service.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_service/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/get_service/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/implementation.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/implementation_type.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/is_open.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/lowest_layer/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/lowest_layer.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/lowest_layer/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/lowest_layer/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/lowest_layer_type.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/native_handle.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/native_handle_type.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/native.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/native_type.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/operator_eq_.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/read_some_at/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/read_some_at.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/read_some_at/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/read_some_at/overload2.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/service.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/service_type.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/write_some_at/ +/doc/html/boost_asio/reference/windows__basic_random_access_handle/write_some_at.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/write_some_at/overload1.html +/doc/html/boost_asio/reference/windows__basic_random_access_handle/write_some_at/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/assign/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/assign.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/assign/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/assign/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/async_read_some.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/async_write_some.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/basic_stream_handle/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/basic_stream_handle.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/basic_stream_handle/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/basic_stream_handle/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/basic_stream_handle/overload3.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/cancel/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/cancel.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/cancel/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/cancel/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/close/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/close.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/close/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/close/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_implementation/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_implementation.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_implementation/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_implementation/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_io_service.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_service/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_service.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_service/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/get_service/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/implementation.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/implementation_type.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/is_open.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/lowest_layer/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/lowest_layer.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/lowest_layer/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/lowest_layer/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/lowest_layer_type.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/native_handle.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/native_handle_type.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/native.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/native_type.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/operator_eq_.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/read_some/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/read_some.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/read_some/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/read_some/overload2.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/service.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/service_type.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/write_some/ +/doc/html/boost_asio/reference/windows__basic_stream_handle/write_some.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/write_some/overload1.html +/doc/html/boost_asio/reference/windows__basic_stream_handle/write_some/overload2.html +/doc/html/boost_asio/reference/windows__object_handle.html +/doc/html/boost_asio/reference/windows__object_handle_service/ +/doc/html/boost_asio/reference/windows__object_handle_service/assign.html +/doc/html/boost_asio/reference/windows__object_handle_service/async_wait.html +/doc/html/boost_asio/reference/windows__object_handle_service/cancel.html +/doc/html/boost_asio/reference/windows__object_handle_service/close.html +/doc/html/boost_asio/reference/windows__object_handle_service/construct.html +/doc/html/boost_asio/reference/windows__object_handle_service/destroy.html +/doc/html/boost_asio/reference/windows__object_handle_service/get_io_service.html +/doc/html/boost_asio/reference/windows__object_handle_service.html +/doc/html/boost_asio/reference/windows__object_handle_service/id.html +/doc/html/boost_asio/reference/windows__object_handle_service/implementation_type.html +/doc/html/boost_asio/reference/windows__object_handle_service/is_open.html +/doc/html/boost_asio/reference/windows__object_handle_service/move_assign.html +/doc/html/boost_asio/reference/windows__object_handle_service/move_construct.html +/doc/html/boost_asio/reference/windows__object_handle_service/native_handle.html +/doc/html/boost_asio/reference/windows__object_handle_service/native_handle_type.html +/doc/html/boost_asio/reference/windows__object_handle_service/object_handle_service.html +/doc/html/boost_asio/reference/windows__object_handle_service/wait.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/ +/doc/html/boost_asio/reference/windows__overlapped_ptr/complete.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/get/ +/doc/html/boost_asio/reference/windows__overlapped_ptr/get.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/get/overload1.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/get/overload2.html +/doc/html/boost_asio/reference/windows__overlapped_ptr.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/overlapped_ptr/ +/doc/html/boost_asio/reference/windows__overlapped_ptr/_overlapped_ptr.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/overlapped_ptr.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/overlapped_ptr/overload1.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/overlapped_ptr/overload2.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/release.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/reset/ +/doc/html/boost_asio/reference/windows__overlapped_ptr/reset.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/reset/overload1.html +/doc/html/boost_asio/reference/windows__overlapped_ptr/reset/overload2.html +/doc/html/boost_asio/reference/windows__random_access_handle.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/ +/doc/html/boost_asio/reference/windows__random_access_handle_service/assign.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/async_read_some_at.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/async_write_some_at.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/cancel.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/close.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/construct.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/destroy.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/get_io_service.html +/doc/html/boost_asio/reference/windows__random_access_handle_service.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/id.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/implementation_type.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/is_open.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/move_assign.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/move_construct.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/native_handle.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/native_handle_type.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/native.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/native_type.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/random_access_handle_service.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/read_some_at.html +/doc/html/boost_asio/reference/windows__random_access_handle_service/write_some_at.html +/doc/html/boost_asio/reference/windows__stream_handle.html +/doc/html/boost_asio/reference/windows__stream_handle_service/ +/doc/html/boost_asio/reference/windows__stream_handle_service/assign.html +/doc/html/boost_asio/reference/windows__stream_handle_service/async_read_some.html +/doc/html/boost_asio/reference/windows__stream_handle_service/async_write_some.html +/doc/html/boost_asio/reference/windows__stream_handle_service/cancel.html +/doc/html/boost_asio/reference/windows__stream_handle_service/close.html +/doc/html/boost_asio/reference/windows__stream_handle_service/construct.html +/doc/html/boost_asio/reference/windows__stream_handle_service/destroy.html +/doc/html/boost_asio/reference/windows__stream_handle_service/get_io_service.html +/doc/html/boost_asio/reference/windows__stream_handle_service.html +/doc/html/boost_asio/reference/windows__stream_handle_service/id.html +/doc/html/boost_asio/reference/windows__stream_handle_service/implementation_type.html +/doc/html/boost_asio/reference/windows__stream_handle_service/is_open.html +/doc/html/boost_asio/reference/windows__stream_handle_service/move_assign.html +/doc/html/boost_asio/reference/windows__stream_handle_service/move_construct.html +/doc/html/boost_asio/reference/windows__stream_handle_service/native_handle.html +/doc/html/boost_asio/reference/windows__stream_handle_service/native_handle_type.html +/doc/html/boost_asio/reference/windows__stream_handle_service/native.html +/doc/html/boost_asio/reference/windows__stream_handle_service/native_type.html +/doc/html/boost_asio/reference/windows__stream_handle_service/read_some.html +/doc/html/boost_asio/reference/windows__stream_handle_service/stream_handle_service.html +/doc/html/boost_asio/reference/windows__stream_handle_service/write_some.html +/doc/html/boost_asio/reference/write/ +/doc/html/boost_asio/reference/write_at/ +/doc/html/boost_asio/reference/write_at.html +/doc/html/boost_asio/reference/write_at/overload1.html +/doc/html/boost_asio/reference/write_at/overload2.html +/doc/html/boost_asio/reference/write_at/overload3.html +/doc/html/boost_asio/reference/write_at/overload4.html +/doc/html/boost_asio/reference/write_at/overload5.html +/doc/html/boost_asio/reference/write_at/overload6.html +/doc/html/boost_asio/reference/write_at/overload7.html +/doc/html/boost_asio/reference/write_at/overload8.html +/doc/html/boost_asio/reference/WriteHandler.html +/doc/html/boost_asio/reference/write.html +/doc/html/boost_asio/reference/write/overload1.html +/doc/html/boost_asio/reference/write/overload2.html +/doc/html/boost_asio/reference/write/overload3.html +/doc/html/boost_asio/reference/write/overload4.html +/doc/html/boost_asio/reference/write/overload5.html +/doc/html/boost_asio/reference/write/overload6.html +/doc/html/boost_asio/reference/write/overload7.html +/doc/html/boost_asio/reference/write/overload8.html +/doc/html/boost_asio/reference/yield_context.html +/doc/html/boost_asio/sync_op.png +/doc/html/boost_asio/tutorial/ +/doc/html/boost_asio/tutorial.html +/doc/html/boost_asio/tutorial/tutdaytime1/ +/doc/html/boost_asio/tutorial/tutdaytime1.html +/doc/html/boost_asio/tutorial/tutdaytime1/src.html +/doc/html/boost_asio/tutorial/tutdaytime2/ +/doc/html/boost_asio/tutorial/tutdaytime2.html +/doc/html/boost_asio/tutorial/tutdaytime2/src.html +/doc/html/boost_asio/tutorial/tutdaytime3/ +/doc/html/boost_asio/tutorial/tutdaytime3.html +/doc/html/boost_asio/tutorial/tutdaytime3/src.html +/doc/html/boost_asio/tutorial/tutdaytime4/ +/doc/html/boost_asio/tutorial/tutdaytime4.html +/doc/html/boost_asio/tutorial/tutdaytime4/src.html +/doc/html/boost_asio/tutorial/tutdaytime5/ +/doc/html/boost_asio/tutorial/tutdaytime5.html +/doc/html/boost_asio/tutorial/tutdaytime5/src.html +/doc/html/boost_asio/tutorial/tutdaytime6/ +/doc/html/boost_asio/tutorial/tutdaytime6.html +/doc/html/boost_asio/tutorial/tutdaytime6/src.html +/doc/html/boost_asio/tutorial/tutdaytime7/ +/doc/html/boost_asio/tutorial/tutdaytime7.html +/doc/html/boost_asio/tutorial/tutdaytime7/src.html +/doc/html/boost_asio/tutorial/tuttimer1/ +/doc/html/boost_asio/tutorial/tuttimer1.html +/doc/html/boost_asio/tutorial/tuttimer1/src.html +/doc/html/boost_asio/tutorial/tuttimer2/ +/doc/html/boost_asio/tutorial/tuttimer2.html +/doc/html/boost_asio/tutorial/tuttimer2/src.html +/doc/html/boost_asio/tutorial/tuttimer3/ +/doc/html/boost_asio/tutorial/tuttimer3.html +/doc/html/boost_asio/tutorial/tuttimer3/src.html +/doc/html/boost_asio/tutorial/tuttimer4/ +/doc/html/boost_asio/tutorial/tuttimer4.html +/doc/html/boost_asio/tutorial/tuttimer4/src.html +/doc/html/boost_asio/tutorial/tuttimer5/ +/doc/html/boost_asio/tutorial/tuttimer5.html +/doc/html/boost_asio/tutorial/tuttimer5/src.html +/doc/html/boost_asio/using.html +/libs/ +/libs/asio/ +/libs/asio/doc/ +/libs/asio/doc/asio.qbk +/libs/asio/doc/doxy2qbk.pl +/libs/asio/doc/examples.qbk +/libs/asio/doc/history.qbk +/libs/asio/doc/index.xml +/libs/asio/doc/Jamfile.v2 +/libs/asio/doc/noncopyable_dox.txt +/libs/asio/doc/overview/ +/libs/asio/doc/overview/allocation.qbk +/libs/asio/doc/overview/async_op1.dot +/libs/asio/doc/overview/async_op1.png +/libs/asio/doc/overview/async_op2.dot +/libs/asio/doc/overview/async_op2.png +/libs/asio/doc/overview/async.qbk +/libs/asio/doc/overview/basics.qbk +/libs/asio/doc/overview/bsd_sockets.qbk +/libs/asio/doc/overview/buffers.qbk +/libs/asio/doc/overview/coroutine.qbk +/libs/asio/doc/overview/cpp2011.qbk +/libs/asio/doc/overview/handler_tracking.qbk +/libs/asio/doc/overview/implementation.qbk +/libs/asio/doc/overview/iostreams.qbk +/libs/asio/doc/overview/line_based.qbk +/libs/asio/doc/overview/other_protocols.qbk +/libs/asio/doc/overview/posix.qbk +/libs/asio/doc/overview/proactor.dot +/libs/asio/doc/overview/proactor.png +/libs/asio/doc/overview/protocols.qbk +/libs/asio/doc/overview.qbk +/libs/asio/doc/overview/rationale.qbk +/libs/asio/doc/overview/reactor.qbk +/libs/asio/doc/overview/serial_ports.qbk +/libs/asio/doc/overview/signals.qbk +/libs/asio/doc/overview/spawn.qbk +/libs/asio/doc/overview/ssl.qbk +/libs/asio/doc/overview/strands.qbk +/libs/asio/doc/overview/streams.qbk +/libs/asio/doc/overview/sync_op.dot +/libs/asio/doc/overview/sync_op.png +/libs/asio/doc/overview/threads.qbk +/libs/asio/doc/overview/timers.qbk +/libs/asio/doc/overview/windows.qbk +/libs/asio/doc/quickref.xml +/libs/asio/doc/reference.dox +/libs/asio/doc/reference.qbk +/libs/asio/doc/reference.xsl +/libs/asio/doc/requirements/ +/libs/asio/doc/requirements/AcceptHandler.qbk +/libs/asio/doc/requirements/asynchronous_operations.qbk +/libs/asio/doc/requirements/AsyncRandomAccessReadDevice.qbk +/libs/asio/doc/requirements/AsyncRandomAccessWriteDevice.qbk +/libs/asio/doc/requirements/AsyncReadStream.qbk +/libs/asio/doc/requirements/AsyncWriteStream.qbk +/libs/asio/doc/requirements/BufferedHandshakeHandler.qbk +/libs/asio/doc/requirements/CompletionHandler.qbk +/libs/asio/doc/requirements/ComposedConnectHandler.qbk +/libs/asio/doc/requirements/ConnectHandler.qbk +/libs/asio/doc/requirements/ConstBufferSequence.qbk +/libs/asio/doc/requirements/ConvertibleToConstBuffer.qbk +/libs/asio/doc/requirements/ConvertibleToMutableBuffer.qbk +/libs/asio/doc/requirements/DatagramSocketService.qbk +/libs/asio/doc/requirements/DescriptorService.qbk +/libs/asio/doc/requirements/Endpoint.qbk +/libs/asio/doc/requirements/GettableSerialPortOption.qbk +/libs/asio/doc/requirements/GettableSocketOption.qbk +/libs/asio/doc/requirements/Handler.qbk +/libs/asio/doc/requirements/HandleService.qbk +/libs/asio/doc/requirements/HandshakeHandler.qbk +/libs/asio/doc/requirements/InternetProtocol.qbk +/libs/asio/doc/requirements/IoControlCommand.qbk +/libs/asio/doc/requirements/IoObjectService.qbk +/libs/asio/doc/requirements/MutableBufferSequence.qbk +/libs/asio/doc/requirements/ObjectHandleService.qbk +/libs/asio/doc/requirements/Protocol.qbk +/libs/asio/doc/requirements.qbk +/libs/asio/doc/requirements/RandomAccessHandleService.qbk +/libs/asio/doc/requirements/RawSocketService.qbk +/libs/asio/doc/requirements/ReadHandler.qbk +/libs/asio/doc/requirements/ResolveHandler.qbk +/libs/asio/doc/requirements/ResolverService.qbk +/libs/asio/doc/requirements/SeqPacketSocketService.qbk +/libs/asio/doc/requirements/SerialPortService.qbk +/libs/asio/doc/requirements/Service.qbk +/libs/asio/doc/requirements/SettableSerialPortOption.qbk +/libs/asio/doc/requirements/SettableSocketOption.qbk +/libs/asio/doc/requirements/ShutdownHandler.qbk +/libs/asio/doc/requirements/SignalHandler.qbk +/libs/asio/doc/requirements/SignalSetService.qbk +/libs/asio/doc/requirements/SocketAcceptorService.qbk +/libs/asio/doc/requirements/SocketService.qbk +/libs/asio/doc/requirements/StreamDescriptorService.qbk +/libs/asio/doc/requirements/StreamHandleService.qbk +/libs/asio/doc/requirements/StreamSocketService.qbk +/libs/asio/doc/requirements/SyncRandomAccessReadDevice.qbk +/libs/asio/doc/requirements/SyncRandomAccessWriteDevice.qbk +/libs/asio/doc/requirements/SyncReadStream.qbk +/libs/asio/doc/requirements/SyncWriteStream.qbk +/libs/asio/doc/requirements/TimerService.qbk +/libs/asio/doc/requirements/TimeTraits.qbk +/libs/asio/doc/requirements/WaitableTimerService.qbk +/libs/asio/doc/requirements/WaitHandler.qbk +/libs/asio/doc/requirements/WaitTraits.qbk +/libs/asio/doc/requirements/WriteHandler.qbk +/libs/asio/doc/std_exception_dox.txt +/libs/asio/doc/tutorial.dox +/libs/asio/doc/tutorial.qbk +/libs/asio/doc/tutorial.xsl +/libs/asio/doc/using.qbk +/libs/asio/example/ +/libs/asio/example/cpp03/ +/libs/asio/example/cpp03/allocation/ +/libs/asio/example/cpp03/allocation/Jamfile +/libs/asio/example/cpp03/allocation/Jamfile.v2 +/libs/asio/example/cpp03/allocation/server.cpp +/libs/asio/example/cpp03/buffers/ +/libs/asio/example/cpp03/buffers/Jamfile +/libs/asio/example/cpp03/buffers/Jamfile.v2 +/libs/asio/example/cpp03/buffers/reference_counted.cpp +/libs/asio/example/cpp03/chat/ +/libs/asio/example/cpp03/chat/chat_client.cpp +/libs/asio/example/cpp03/chat/chat_message.hpp +/libs/asio/example/cpp03/chat/chat_server.cpp +/libs/asio/example/cpp03/chat/Jamfile +/libs/asio/example/cpp03/chat/Jamfile.v2 +/libs/asio/example/cpp03/chat/posix_chat_client.cpp +/libs/asio/example/cpp03/echo/ +/libs/asio/example/cpp03/echo/async_tcp_echo_server.cpp +/libs/asio/example/cpp03/echo/async_udp_echo_server.cpp +/libs/asio/example/cpp03/echo/blocking_tcp_echo_client.cpp +/libs/asio/example/cpp03/echo/blocking_tcp_echo_server.cpp +/libs/asio/example/cpp03/echo/blocking_udp_echo_client.cpp +/libs/asio/example/cpp03/echo/blocking_udp_echo_server.cpp +/libs/asio/example/cpp03/echo/Jamfile +/libs/asio/example/cpp03/echo/Jamfile.v2 +/libs/asio/example/cpp03/fork/ +/libs/asio/example/cpp03/fork/daemon.cpp +/libs/asio/example/cpp03/fork/Jamfile +/libs/asio/example/cpp03/fork/Jamfile.v2 +/libs/asio/example/cpp03/fork/process_per_connection.cpp +/libs/asio/example/cpp03/http/ +/libs/asio/example/cpp03/http/client/ +/libs/asio/example/cpp03/http/client/async_client.cpp +/libs/asio/example/cpp03/http/client/Jamfile +/libs/asio/example/cpp03/http/client/Jamfile.v2 +/libs/asio/example/cpp03/http/client/sync_client.cpp +/libs/asio/example/cpp03/http/doc_root/ +/libs/asio/example/cpp03/http/doc_root/data_1K.html +/libs/asio/example/cpp03/http/doc_root/data_2K.html +/libs/asio/example/cpp03/http/doc_root/data_4K.html +/libs/asio/example/cpp03/http/doc_root/data_8K.html +/libs/asio/example/cpp03/http/server/ +/libs/asio/example/cpp03/http/server2/ +/libs/asio/example/cpp03/http/server2/connection.cpp +/libs/asio/example/cpp03/http/server2/connection.hpp +/libs/asio/example/cpp03/http/server2/header.hpp +/libs/asio/example/cpp03/http/server2/io_service_pool.cpp +/libs/asio/example/cpp03/http/server2/io_service_pool.hpp +/libs/asio/example/cpp03/http/server2/Jamfile +/libs/asio/example/cpp03/http/server2/Jamfile.v2 +/libs/asio/example/cpp03/http/server2/main.cpp +/libs/asio/example/cpp03/http/server2/mime_types.cpp +/libs/asio/example/cpp03/http/server2/mime_types.hpp +/libs/asio/example/cpp03/http/server2/reply.cpp +/libs/asio/example/cpp03/http/server2/reply.hpp +/libs/asio/example/cpp03/http/server2/request_handler.cpp +/libs/asio/example/cpp03/http/server2/request_handler.hpp +/libs/asio/example/cpp03/http/server2/request.hpp +/libs/asio/example/cpp03/http/server2/request_parser.cpp +/libs/asio/example/cpp03/http/server2/request_parser.hpp +/libs/asio/example/cpp03/http/server2/server.cpp +/libs/asio/example/cpp03/http/server2/server.hpp +/libs/asio/example/cpp03/http/server3/ +/libs/asio/example/cpp03/http/server3/connection.cpp +/libs/asio/example/cpp03/http/server3/connection.hpp +/libs/asio/example/cpp03/http/server3/header.hpp +/libs/asio/example/cpp03/http/server3/Jamfile +/libs/asio/example/cpp03/http/server3/Jamfile.v2 +/libs/asio/example/cpp03/http/server3/main.cpp +/libs/asio/example/cpp03/http/server3/mime_types.cpp +/libs/asio/example/cpp03/http/server3/mime_types.hpp +/libs/asio/example/cpp03/http/server3/reply.cpp +/libs/asio/example/cpp03/http/server3/reply.hpp +/libs/asio/example/cpp03/http/server3/request_handler.cpp +/libs/asio/example/cpp03/http/server3/request_handler.hpp +/libs/asio/example/cpp03/http/server3/request.hpp +/libs/asio/example/cpp03/http/server3/request_parser.cpp +/libs/asio/example/cpp03/http/server3/request_parser.hpp +/libs/asio/example/cpp03/http/server3/server.cpp +/libs/asio/example/cpp03/http/server3/server.hpp +/libs/asio/example/cpp03/http/server4/ +/libs/asio/example/cpp03/http/server4/file_handler.cpp +/libs/asio/example/cpp03/http/server4/file_handler.hpp +/libs/asio/example/cpp03/http/server4/header.hpp +/libs/asio/example/cpp03/http/server4/Jamfile +/libs/asio/example/cpp03/http/server4/Jamfile.v2 +/libs/asio/example/cpp03/http/server4/main.cpp +/libs/asio/example/cpp03/http/server4/mime_types.cpp +/libs/asio/example/cpp03/http/server4/mime_types.hpp +/libs/asio/example/cpp03/http/server4/reply.cpp +/libs/asio/example/cpp03/http/server4/reply.hpp +/libs/asio/example/cpp03/http/server4/request.hpp +/libs/asio/example/cpp03/http/server4/request_parser.cpp +/libs/asio/example/cpp03/http/server4/request_parser.hpp +/libs/asio/example/cpp03/http/server4/server.cpp +/libs/asio/example/cpp03/http/server4/server.hpp +/libs/asio/example/cpp03/http/server/connection.cpp +/libs/asio/example/cpp03/http/server/connection.hpp +/libs/asio/example/cpp03/http/server/connection_manager.cpp +/libs/asio/example/cpp03/http/server/connection_manager.hpp +/libs/asio/example/cpp03/http/server/header.hpp +/libs/asio/example/cpp03/http/server/Jamfile +/libs/asio/example/cpp03/http/server/Jamfile.v2 +/libs/asio/example/cpp03/http/server/main.cpp +/libs/asio/example/cpp03/http/server/mime_types.cpp +/libs/asio/example/cpp03/http/server/mime_types.hpp +/libs/asio/example/cpp03/http/server/reply.cpp +/libs/asio/example/cpp03/http/server/reply.hpp +/libs/asio/example/cpp03/http/server/request_handler.cpp +/libs/asio/example/cpp03/http/server/request_handler.hpp +/libs/asio/example/cpp03/http/server/request.hpp +/libs/asio/example/cpp03/http/server/request_parser.cpp +/libs/asio/example/cpp03/http/server/request_parser.hpp +/libs/asio/example/cpp03/http/server/server.cpp +/libs/asio/example/cpp03/http/server/server.hpp +/libs/asio/example/cpp03/icmp/ +/libs/asio/example/cpp03/icmp/icmp_header.hpp +/libs/asio/example/cpp03/icmp/ipv4_header.hpp +/libs/asio/example/cpp03/icmp/Jamfile +/libs/asio/example/cpp03/icmp/Jamfile.v2 +/libs/asio/example/cpp03/icmp/ping.cpp +/libs/asio/example/cpp03/invocation/ +/libs/asio/example/cpp03/invocation/Jamfile +/libs/asio/example/cpp03/invocation/Jamfile.v2 +/libs/asio/example/cpp03/invocation/prioritised_handlers.cpp +/libs/asio/example/cpp03/iostreams/ +/libs/asio/example/cpp03/iostreams/daytime_client.cpp +/libs/asio/example/cpp03/iostreams/daytime_server.cpp +/libs/asio/example/cpp03/iostreams/http_client.cpp +/libs/asio/example/cpp03/iostreams/Jamfile +/libs/asio/example/cpp03/iostreams/Jamfile.v2 +/libs/asio/example/cpp03/local/ +/libs/asio/example/cpp03/local/connect_pair.cpp +/libs/asio/example/cpp03/local/iostream_client.cpp +/libs/asio/example/cpp03/local/Jamfile +/libs/asio/example/cpp03/local/Jamfile.v2 +/libs/asio/example/cpp03/local/stream_client.cpp +/libs/asio/example/cpp03/local/stream_server.cpp +/libs/asio/example/cpp03/multicast/ +/libs/asio/example/cpp03/multicast/Jamfile +/libs/asio/example/cpp03/multicast/Jamfile.v2 +/libs/asio/example/cpp03/multicast/receiver.cpp +/libs/asio/example/cpp03/multicast/sender.cpp +/libs/asio/example/cpp03/nonblocking/ +/libs/asio/example/cpp03/nonblocking/Jamfile +/libs/asio/example/cpp03/nonblocking/Jamfile.v2 +/libs/asio/example/cpp03/nonblocking/third_party_lib.cpp +/libs/asio/example/cpp03/porthopper/ +/libs/asio/example/cpp03/porthopper/client.cpp +/libs/asio/example/cpp03/porthopper/Jamfile +/libs/asio/example/cpp03/porthopper/Jamfile.v2 +/libs/asio/example/cpp03/porthopper/protocol.hpp +/libs/asio/example/cpp03/porthopper/server.cpp +/libs/asio/example/cpp03/serialization/ +/libs/asio/example/cpp03/serialization/client.cpp +/libs/asio/example/cpp03/serialization/connection.hpp +/libs/asio/example/cpp03/serialization/Jamfile +/libs/asio/example/cpp03/serialization/Jamfile.v2 +/libs/asio/example/cpp03/serialization/server.cpp +/libs/asio/example/cpp03/serialization/stock.hpp +/libs/asio/example/cpp03/services/ +/libs/asio/example/cpp03/services/basic_logger.hpp +/libs/asio/example/cpp03/services/daytime_client.cpp +/libs/asio/example/cpp03/services/Jamfile +/libs/asio/example/cpp03/services/Jamfile.v2 +/libs/asio/example/cpp03/services/logger.hpp +/libs/asio/example/cpp03/services/logger_service.cpp +/libs/asio/example/cpp03/services/logger_service.hpp +/libs/asio/example/cpp03/services/stream_socket_service.hpp +/libs/asio/example/cpp03/socks4/ +/libs/asio/example/cpp03/socks4/Jamfile +/libs/asio/example/cpp03/socks4/Jamfile.v2 +/libs/asio/example/cpp03/socks4/socks4.hpp +/libs/asio/example/cpp03/socks4/sync_client.cpp +/libs/asio/example/cpp03/spawn/ +/libs/asio/example/cpp03/spawn/echo_server.cpp +/libs/asio/example/cpp03/spawn/Jamfile.v2 +/libs/asio/example/cpp03/ssl/ +/libs/asio/example/cpp03/ssl/ca.pem +/libs/asio/example/cpp03/ssl/client.cpp +/libs/asio/example/cpp03/ssl/dh2048.pem +/libs/asio/example/cpp03/ssl/Jamfile +/libs/asio/example/cpp03/ssl/Jamfile.v2 +/libs/asio/example/cpp03/ssl/README +/libs/asio/example/cpp03/ssl/server.cpp +/libs/asio/example/cpp03/ssl/server.pem +/libs/asio/example/cpp03/timeouts/ +/libs/asio/example/cpp03/timeouts/async_tcp_client.cpp +/libs/asio/example/cpp03/timeouts/blocking_tcp_client.cpp +/libs/asio/example/cpp03/timeouts/blocking_udp_client.cpp +/libs/asio/example/cpp03/timeouts/Jamfile +/libs/asio/example/cpp03/timeouts/Jamfile.v2 +/libs/asio/example/cpp03/timeouts/server.cpp +/libs/asio/example/cpp03/timers/ +/libs/asio/example/cpp03/timers/Jamfile +/libs/asio/example/cpp03/timers/Jamfile.v2 +/libs/asio/example/cpp03/timers/tick_count_timer.cpp +/libs/asio/example/cpp03/timers/time_t_timer.cpp +/libs/asio/example/cpp03/tutorial/ +/libs/asio/example/cpp03/tutorial/daytime1/ +/libs/asio/example/cpp03/tutorial/daytime1/client.cpp +/libs/asio/example/cpp03/tutorial/daytime2/ +/libs/asio/example/cpp03/tutorial/daytime2/server.cpp +/libs/asio/example/cpp03/tutorial/daytime3/ +/libs/asio/example/cpp03/tutorial/daytime3/server.cpp +/libs/asio/example/cpp03/tutorial/daytime4/ +/libs/asio/example/cpp03/tutorial/daytime4/client.cpp +/libs/asio/example/cpp03/tutorial/daytime5/ +/libs/asio/example/cpp03/tutorial/daytime5/server.cpp +/libs/asio/example/cpp03/tutorial/daytime6/ +/libs/asio/example/cpp03/tutorial/daytime6/server.cpp +/libs/asio/example/cpp03/tutorial/daytime7/ +/libs/asio/example/cpp03/tutorial/daytime7/server.cpp +/libs/asio/example/cpp03/tutorial/daytime_dox.txt +/libs/asio/example/cpp03/tutorial/index_dox.txt +/libs/asio/example/cpp03/tutorial/Jamfile +/libs/asio/example/cpp03/tutorial/Jamfile.v2 +/libs/asio/example/cpp03/tutorial/timer1/ +/libs/asio/example/cpp03/tutorial/timer1/timer.cpp +/libs/asio/example/cpp03/tutorial/timer2/ +/libs/asio/example/cpp03/tutorial/timer2/timer.cpp +/libs/asio/example/cpp03/tutorial/timer3/ +/libs/asio/example/cpp03/tutorial/timer3/timer.cpp +/libs/asio/example/cpp03/tutorial/timer4/ +/libs/asio/example/cpp03/tutorial/timer4/timer.cpp +/libs/asio/example/cpp03/tutorial/timer5/ +/libs/asio/example/cpp03/tutorial/timer5/timer.cpp +/libs/asio/example/cpp03/tutorial/timer_dox.txt +/libs/asio/example/cpp03/windows/ +/libs/asio/example/cpp03/windows/Jamfile +/libs/asio/example/cpp03/windows/Jamfile.v2 +/libs/asio/example/cpp03/windows/transmit_file.cpp +/libs/asio/example/cpp11/ +/libs/asio/example/cpp11/allocation/ +/libs/asio/example/cpp11/allocation/Jamfile +/libs/asio/example/cpp11/allocation/Jamfile.v2 +/libs/asio/example/cpp11/allocation/server.cpp +/libs/asio/example/cpp11/buffers/ +/libs/asio/example/cpp11/buffers/Jamfile +/libs/asio/example/cpp11/buffers/Jamfile.v2 +/libs/asio/example/cpp11/buffers/reference_counted.cpp +/libs/asio/example/cpp11/chat/ +/libs/asio/example/cpp11/chat/chat_client.cpp +/libs/asio/example/cpp11/chat/chat_message.hpp +/libs/asio/example/cpp11/chat/chat_server.cpp +/libs/asio/example/cpp11/chat/Jamfile +/libs/asio/example/cpp11/chat/Jamfile.v2 +/libs/asio/example/cpp11/echo/ +/libs/asio/example/cpp11/echo/async_tcp_echo_server.cpp +/libs/asio/example/cpp11/echo/async_udp_echo_server.cpp +/libs/asio/example/cpp11/echo/blocking_tcp_echo_client.cpp +/libs/asio/example/cpp11/echo/blocking_tcp_echo_server.cpp +/libs/asio/example/cpp11/echo/blocking_udp_echo_client.cpp +/libs/asio/example/cpp11/echo/blocking_udp_echo_server.cpp +/libs/asio/example/cpp11/echo/Jamfile +/libs/asio/example/cpp11/echo/Jamfile.v2 +/libs/asio/example/cpp11/executors/ +/libs/asio/example/cpp11/futures/ +/libs/asio/example/cpp11/futures/daytime_client.cpp +/libs/asio/example/cpp11/futures/Jamfile +/libs/asio/example/cpp11/futures/Jamfile.v2 +/libs/asio/example/cpp11/http/ +/libs/asio/example/cpp11/http/server/ +/libs/asio/example/cpp11/http/server/connection.cpp +/libs/asio/example/cpp11/http/server/connection.hpp +/libs/asio/example/cpp11/http/server/connection_manager.cpp +/libs/asio/example/cpp11/http/server/connection_manager.hpp +/libs/asio/example/cpp11/http/server/header.hpp +/libs/asio/example/cpp11/http/server/Jamfile +/libs/asio/example/cpp11/http/server/Jamfile.v2 +/libs/asio/example/cpp11/http/server/main.cpp +/libs/asio/example/cpp11/http/server/mime_types.cpp +/libs/asio/example/cpp11/http/server/mime_types.hpp +/libs/asio/example/cpp11/http/server/reply.cpp +/libs/asio/example/cpp11/http/server/reply.hpp +/libs/asio/example/cpp11/http/server/request_handler.cpp +/libs/asio/example/cpp11/http/server/request_handler.hpp +/libs/asio/example/cpp11/http/server/request.hpp +/libs/asio/example/cpp11/http/server/request_parser.cpp +/libs/asio/example/cpp11/http/server/request_parser.hpp +/libs/asio/example/cpp11/http/server/server.cpp +/libs/asio/example/cpp11/http/server/server.hpp +/libs/asio/example/cpp11/spawn/ +/libs/asio/example/cpp11/spawn/echo_server.cpp +/libs/asio/example/cpp11/spawn/Jamfile.v2 +/libs/asio/example/cpp14/ +/libs/asio/example/cpp14/executors/ +/libs/asio/index.html +/libs/asio/meta/ +/libs/asio/meta/libraries.json +/libs/asio/test/ +/libs/asio/test/archetypes/ +/libs/asio/test/archetypes/async_result.hpp +/libs/asio/test/archetypes/gettable_socket_option.hpp +/libs/asio/test/archetypes/io_control_command.hpp +/libs/asio/test/archetypes/settable_socket_option.hpp +/libs/asio/test/basic_datagram_socket.cpp +/libs/asio/test/basic_deadline_timer.cpp +/libs/asio/test/basic_raw_socket.cpp +/libs/asio/test/basic_seq_packet_socket.cpp +/libs/asio/test/basic_serial_port.cpp +/libs/asio/test/basic_signal_set.cpp +/libs/asio/test/basic_socket_acceptor.cpp +/libs/asio/test/basic_streambuf.cpp +/libs/asio/test/basic_stream_socket.cpp +/libs/asio/test/basic_waitable_timer.cpp +/libs/asio/test/buffer.cpp +/libs/asio/test/buffered_read_stream.cpp +/libs/asio/test/buffered_stream.cpp +/libs/asio/test/buffered_write_stream.cpp +/libs/asio/test/buffers_iterator.cpp +/libs/asio/test/completion_condition.cpp +/libs/asio/test/connect.cpp +/libs/asio/test/coroutine.cpp +/libs/asio/test/datagram_socket_service.cpp +/libs/asio/test/deadline_timer.cpp +/libs/asio/test/deadline_timer_service.cpp +/libs/asio/test/error.cpp +/libs/asio/test/generic/ +/libs/asio/test/generic/basic_endpoint.cpp +/libs/asio/test/generic/datagram_protocol.cpp +/libs/asio/test/generic/raw_protocol.cpp +/libs/asio/test/generic/seq_packet_protocol.cpp +/libs/asio/test/generic/stream_protocol.cpp +/libs/asio/test/high_resolution_timer.cpp +/libs/asio/test/io_service.cpp +/libs/asio/test/ip/ +/libs/asio/test/ip/address.cpp +/libs/asio/test/ip/address_v4.cpp +/libs/asio/test/ip/address_v6.cpp +/libs/asio/test/ip/basic_endpoint.cpp +/libs/asio/test/ip/basic_resolver.cpp +/libs/asio/test/ip/basic_resolver_entry.cpp +/libs/asio/test/ip/basic_resolver_iterator.cpp +/libs/asio/test/ip/basic_resolver_query.cpp +/libs/asio/test/ip/host_name.cpp +/libs/asio/test/ip/icmp.cpp +/libs/asio/test/ip/multicast.cpp +/libs/asio/test/ip/resolver_query_base.cpp +/libs/asio/test/ip/resolver_service.cpp +/libs/asio/test/ip/tcp.cpp +/libs/asio/test/ip/udp.cpp +/libs/asio/test/ip/unicast.cpp +/libs/asio/test/ip/v6_only.cpp +/libs/asio/test/is_read_buffered.cpp +/libs/asio/test/is_write_buffered.cpp +/libs/asio/test/Jamfile +/libs/asio/test/Jamfile.v2 +/libs/asio/test/latency/ +/libs/asio/test/latency/allocator.hpp +/libs/asio/test/latency/coroutine.hpp +/libs/asio/test/latency/high_res_clock.hpp +/libs/asio/test/latency/Jamfile.v2 +/libs/asio/test/latency/tcp_client.cpp +/libs/asio/test/latency/tcp_server.cpp +/libs/asio/test/latency/udp_client.cpp +/libs/asio/test/latency/udp_server.cpp +/libs/asio/test/latency/unyield.hpp +/libs/asio/test/latency/yield.hpp +/libs/asio/test/local/ +/libs/asio/test/local/basic_endpoint.cpp +/libs/asio/test/local/connect_pair.cpp +/libs/asio/test/local/datagram_protocol.cpp +/libs/asio/test/local/stream_protocol.cpp +/libs/asio/test/placeholders.cpp +/libs/asio/test/posix/ +/libs/asio/test/posix/basic_descriptor.cpp +/libs/asio/test/posix/basic_stream_descriptor.cpp +/libs/asio/test/posix/descriptor_base.cpp +/libs/asio/test/posix/stream_descriptor.cpp +/libs/asio/test/posix/stream_descriptor_service.cpp +/libs/asio/test/raw_socket_service.cpp +/libs/asio/test/read_at.cpp +/libs/asio/test/read.cpp +/libs/asio/test/read_until.cpp +/libs/asio/test/seq_packet_socket_service.cpp +/libs/asio/test/serial_port_base.cpp +/libs/asio/test/serial_port.cpp +/libs/asio/test/serial_port_service.cpp +/libs/asio/test/signal_set.cpp +/libs/asio/test/signal_set_service.cpp +/libs/asio/test/socket_acceptor_service.cpp +/libs/asio/test/socket_base.cpp +/libs/asio/test/ssl/ +/libs/asio/test/ssl/basic_context.cpp +/libs/asio/test/ssl/context_base.cpp +/libs/asio/test/ssl/context.cpp +/libs/asio/test/ssl/context_service.cpp +/libs/asio/test/ssl/Jamfile +/libs/asio/test/ssl/Jamfile.v2 +/libs/asio/test/ssl/rfc2818_verification.cpp +/libs/asio/test/ssl/stream_base.cpp +/libs/asio/test/ssl/stream.cpp +/libs/asio/test/ssl/stream_service.cpp +/libs/asio/test/steady_timer.cpp +/libs/asio/test/strand.cpp +/libs/asio/test/streambuf.cpp +/libs/asio/test/stream_socket_service.cpp +/libs/asio/test/system_timer.cpp +/libs/asio/test/time_traits.cpp +/libs/asio/test/unit_test.hpp +/libs/asio/test/waitable_timer_service.cpp +/libs/asio/test/wait_traits.cpp +/libs/asio/test/windows/ +/libs/asio/test/windows/basic_handle.cpp +/libs/asio/test/windows/basic_object_handle.cpp +/libs/asio/test/windows/basic_random_access_handle.cpp +/libs/asio/test/windows/basic_stream_handle.cpp +/libs/asio/test/windows/object_handle.cpp +/libs/asio/test/windows/object_handle_service.cpp +/libs/asio/test/windows/overlapped_ptr.cpp +/libs/asio/test/windows/random_access_handle.cpp +/libs/asio/test/windows/random_access_handle_service.cpp +/libs/asio/test/windows/stream_handle.cpp +/libs/asio/test/windows/stream_handle_service.cpp +/libs/asio/test/write_at.cpp +/libs/asio/test/write.cpp +/libs/asio/tools/ +/libs/asio/tools/handlerviz.pl +/libs/system/ +/libs/system/build/ +/libs/system/build/Jamfile +/libs/system/build/Jamfile.v2 +/libs/system/doc/ +/libs/system/doc/index.html +/libs/system/doc/reference.html +/libs/system/index.html +/libs/system/meta/ +/libs/system/meta/libraries.json +/libs/system/src/ +/libs/system/src/error_code.cpp +/libs/system/test/ +/libs/system/test/config_test.cpp +/libs/system/test/dynamic_link_test.cpp +/libs/system/test/error_code_test.cpp +/libs/system/test/error_code_user_test.cpp +/libs/system/test/header_only_test.cpp +/libs/system/test/initialization_test.cpp +/libs/system/test/Jamfile.v2 +/libs/system/test/system/ +/libs/system/test/system/common.props +/libs/system/test/system/config_test/ +/libs/system/test/system/config_test/config_test.vcxproj +/libs/system/test/system/error_code_test/ +/libs/system/test/system/error_code_test/error_code_test.vcxproj +/libs/system/test/system_error_test.cpp +/libs/system/test/system/header_only_test/ +/libs/system/test/system/header_only_test/header_only_test.vcxproj +/libs/system/test/system/system-dll/ +/libs/system/test/system/system-dll/system-dll.vcxproj +/libs/system/test/system/system.sln +/libs/system/test/throw_test.cpp +/README.txt diff --git a/utils/dnp3_src/deps/asio/asio/boostify.pl b/utils/dnp3_src/deps/asio/asio/boostify.pl new file mode 100755 index 0000000..d6ce848 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/boostify.pl @@ -0,0 +1,580 @@ +#!/usr/bin/perl -w + +use strict; +use File::Path; + +our $boost_dir = "boostified"; + +sub print_line +{ + my ($output, $line, $from, $lineno) = @_; + + # Warn if the resulting line is >80 characters wide. + if (length($line) > 80) + { + if ($from =~ /\.[chi]pp$/) + { + print("Warning: $from:$lineno: output >80 characters wide.\n"); + } + } + + # Write the output. + print($output $line . "\n"); +} + +sub source_contains_asio_thread_usage +{ + my ($from) = @_; + + # Open the input file. + open(my $input, "<$from") or die("Can't open $from for reading"); + + # Check file for use of asio::thread. + while (my $line = <$input>) + { + chomp($line); + if ($line =~ /asio::thread/) + { + close($input); + return 1; + } + elsif ($line =~ /^ *thread /) + { + close($input); + return 1; + } + } + + close($input); + return 0; +} + +sub source_contains_asio_include +{ + my ($from) = @_; + + # Open the input file. + open(my $input, "<$from") or die("Can't open $from for reading"); + + # Check file for inclusion of asio.hpp. + while (my $line = <$input>) + { + chomp($line); + if ($line =~ /# *include [<"]asio\.hpp[>"]/) + { + close($input); + return 1; + } + } + + close($input); + return 0; +} + +sub copy_source_file +{ + my ($from, $to) = @_; + + # Ensure the output directory exists. + my $dir = $to; + $dir =~ s/[^\/]*$//; + mkpath($dir); + + # First determine whether the file makes any use of asio::thread. + my $uses_asio_thread = source_contains_asio_thread_usage($from); + + my $includes_asio = source_contains_asio_include($from); + + my $is_asio_hpp = 0; + $is_asio_hpp = 1 if ($from =~ /asio\.hpp/); + + my $needs_doc_link = 0; + $needs_doc_link = 1 if ($is_asio_hpp); + + my $is_error_hpp = 0; + $is_error_hpp = 1 if ($from =~ /asio\/error\.hpp/); + + my $is_qbk = 0; + $is_qbk = 1 if ($from =~ /.qbk$/); + + my $is_xsl = 0; + $is_xsl = 1 if ($from =~ /.xsl$/); + + my $is_test = 0; + $is_test = 1 if ($from =~ /tests\/unit/); + + # Open the files. + open(my $input, "<$from") or die("Can't open $from for reading"); + open(my $output, ">$to") or die("Can't open $to for writing"); + + # Copy the content. + my $lineno = 1; + while (my $line = <$input>) + { + chomp($line); + + # Unconditional replacements. + $line =~ s/[\\@]ref boost_bind/boost::bind()/g; + if ($from =~ /.*\.txt$/) + { + $line =~ s/[\\@]ref async_read/boost::asio::async_read()/g; + $line =~ s/[\\@]ref async_write/boost::asio::async_write()/g; + } + if ($line =~ /asio_detail_posix_thread_function/) + { + $line =~ s/asio_detail_posix_thread_function/boost_asio_detail_posix_thread_function/g; + } + if ($line =~ /asio_signal_handler/) + { + $line =~ s/asio_signal_handler/boost_asio_signal_handler/g; + } + if ($line =~ /ASIO_/ && !($line =~ /BOOST_ASIO_/)) + { + $line =~ s/ASIO_/BOOST_ASIO_/g; + } + + # Extra replacements for quickbook and XSL source only. + if ($is_qbk || $is_xsl) + { + $line =~ s/asio\.examples/boost_asio.examples/g; + $line =~ s/asio\.history/boost_asio.history/g; + $line =~ s/asio\.index/boost_asio.index/g; + $line =~ s/asio\.overview/boost_asio.overview/g; + $line =~ s/asio\.reference/boost_asio.reference/g; + $line =~ s/asio\.tutorial/boost_asio.tutorial/g; + $line =~ s/asio\.using/boost_asio.using/g; + $line =~ s/Asio/Boost.Asio/g; + $line =~ s/changes made in each release/changes made in each Boost release/g; + $line =~ s/\[\$/[\$boost_asio\//g; + $line =~ s/\[@\.\.\/src\/examples/[\@boost_asio\/example/g; + $line =~ s/include\/asio/boost\/asio/g; + $line =~ s/\^asio/^boost\/asio/g; + $line =~ s/namespaceasio/namespaceboost_1_1asio/g; + $line =~ s/ \(\[\@examples\/diffs.*$//; + } + + # Conditional replacements. + if ($line =~ /^( *)namespace asio {/) + { + if ($is_qbk) + { + print_line($output, $1 . "namespace boost { namespace asio {", $from, $lineno); + } + else + { + print_line($output, $1 . "namespace boost {", $from, $lineno); + print_line($output, $line, $from, $lineno); + } + } + elsif ($line =~ /^( *)} \/\/ namespace asio$/) + { + if ($is_qbk) + { + print_line($output, $1 . "} } // namespace boost::asio", $from, $lineno); + } + else + { + print_line($output, $line, $from, $lineno); + print_line($output, $1 . "} // namespace boost", $from, $lineno); + } + } + elsif ($line =~ /^(# *include )[<"](asio\.hpp)[>"]$/) + { + print_line($output, $1 . "", $from, $lineno); + if ($uses_asio_thread) + { + print_line($output, $1 . "", $from, $lineno) if (!$is_test); + $uses_asio_thread = 0; + } + } + elsif ($line =~ /^(# *include )[<"]boost\/.*[>"].*$/) + { + if (!$includes_asio && $uses_asio_thread) + { + print_line($output, $1 . "", $from, $lineno) if (!$is_test); + $uses_asio_thread = 0; + } + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /^(# *include )[<"]asio\/thread\.hpp[>"]/) + { + if ($is_test) + { + print_line($output, $1 . "", $from, $lineno); + } + else + { + # Line is removed. + } + } + elsif ($line =~ /(# *include )[<"]asio\/error_code\.hpp[>"]/) + { + if ($is_asio_hpp) + { + # Line is removed. + } + else + { + print_line($output, $1 . "", $from, $lineno) if ($is_error_hpp); + print_line($output, $1 . "", $from, $lineno); + } + } + elsif ($line =~ /# *include [<"]asio\/impl\/error_code\.[hi]pp[>"]/) + { + # Line is removed. + } + elsif ($line =~ /(# *include )[<"]asio\/system_error\.hpp[>"]/) + { + if ($is_asio_hpp) + { + # Line is removed. + } + else + { + print_line($output, $1 . "", $from, $lineno); + } + } + elsif ($line =~ /(^.*# *include )[<"](asio\/[^>"]*)[>"](.*)$/) + { + print_line($output, $1 . "" . $3, $from, $lineno); + } + elsif ($line =~ /#.*defined\(.*ASIO_HAS_STD_SYSTEM_ERROR\)$/) + { + # Line is removed. + } + elsif ($line =~ /asio::thread/) + { + if ($is_test) + { + $line =~ s/asio::thread/asio::detail::thread/g; + } + else + { + $line =~ s/asio::thread/boost::thread/g; + } + if (!($line =~ /boost::asio::/)) + { + $line =~ s/asio::/boost::asio::/g; + } + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /^( *)thread( .*)$/ && !$is_qbk) + { + if ($is_test) + { + print_line($output, $1 . "boost::asio::detail::thread" . $2, $from, $lineno); + } + else + { + print_line($output, $1 . "boost::thread" . $2, $from, $lineno); + } + } + elsif ($line =~ /namespace std {/) + { + print_line($output, "namespace boost {", $from, $lineno); + print_line($output, "namespace system {", $from, $lineno); + } + elsif ($line =~ /std::error_code/) + { + $line =~ s/std::error_code/boost::system::error_code/g; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /} \/\/ namespace std/) + { + print_line($output, "} // namespace system", $from, $lineno); + print_line($output, "} // namespace boost", $from, $lineno); + } + elsif ($line =~ /asio::/ && !($line =~ /boost::asio::/)) + { + $line =~ s/asio::error_code/boost::system::error_code/g; + $line =~ s/asio::error_category/boost::system::error_category/g; + $line =~ s/asio::system_category/boost::system::system_category/g; + $line =~ s/asio::system_error/boost::system::system_error/g; + $line =~ s/asio::/boost::asio::/g if !$is_xsl; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /using namespace asio/) + { + $line =~ s/using namespace asio/using namespace boost::asio/g; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /asio_handler_alloc_helpers/) + { + $line =~ s/asio_handler_alloc_helpers/boost_asio_handler_alloc_helpers/g; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /asio_handler_cont_helpers/) + { + $line =~ s/asio_handler_cont_helpers/boost_asio_handler_cont_helpers/g; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /asio_handler_invoke_helpers/) + { + $line =~ s/asio_handler_invoke_helpers/boost_asio_handler_invoke_helpers/g; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /[\\@]ref boost_bind/) + { + $line =~ s/[\\@]ref boost_bind/boost::bind()/g; + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /( *)\[category template\]/) + { + print_line($output, $1 . "[authors [Kohlhoff, Christopher]]", $from, $lineno); + print_line($output, $line, $from, $lineno); + } + elsif ($line =~ /boostify: non-boost docs start here/) + { + while ($line = <$input>) + { + last if $line =~ /boostify: non-boost docs end here/; + } + } + elsif ($line =~ /boostify: non-boost code starts here/) + { + while ($line = <$input>) + { + last if $line =~ /boostify: non-boost code ends here/; + } + } + elsif ($line =~ /^$/ && $needs_doc_link) + { + $needs_doc_link = 0; + print_line($output, "// See www.boost.org/libs/asio for documentation.", $from, $lineno); + print_line($output, "//", $from, $lineno); + print_line($output, $line, $from, $lineno); + } + else + { + print_line($output, $line, $from, $lineno); + } + ++$lineno; + } + + # Ok, we're done. + close($input); + close($output); +} + +sub copy_include_files +{ + my @dirs = ( + "include", + "include/asio", + "include/asio/detail", + "include/asio/detail/impl", + "include/asio/generic", + "include/asio/generic/detail", + "include/asio/generic/detail/impl", + "include/asio/impl", + "include/asio/ip", + "include/asio/ip/impl", + "include/asio/ip/detail", + "include/asio/ip/detail/impl", + "include/asio/local", + "include/asio/local/detail", + "include/asio/local/detail/impl", + "include/asio/posix", + "include/asio/ssl", + "include/asio/ssl/detail", + "include/asio/ssl/detail/impl", + "include/asio/ssl/impl", + "include/asio/ssl/old", + "include/asio/ssl/old/detail", + "include/asio/windows"); + + foreach my $dir (@dirs) + { + our $boost_dir; + my @files = ( glob("$dir/*.hpp"), glob("$dir/*.ipp"), glob("$dir/*cpp") ); + foreach my $file (@files) + { + if ($file ne "include/asio/thread.hpp" + and $file ne "include/asio/error_code.hpp" + and $file ne "include/asio/system_error.hpp" + and $file ne "include/asio/impl/error_code.hpp" + and $file ne "include/asio/impl/error_code.ipp") + { + my $from = $file; + my $to = $file; + $to =~ s/^include\//$boost_dir\/libs\/asio\/include\/boost\//; + copy_source_file($from, $to); + } + } + } +} + +sub create_lib_directory +{ + my @dirs = ( + "doc", + "example", + "test"); + + our $boost_dir; + foreach my $dir (@dirs) + { + mkpath("$boost_dir/libs/asio/$dir"); + } +} + +sub copy_unit_tests +{ + my @dirs = ( + "src/tests/unit", + "src/tests/unit/archetypes", + "src/tests/unit/generic", + "src/tests/unit/ip", + "src/tests/unit/local", + "src/tests/unit/posix", + "src/tests/unit/ssl", + "src/tests/unit/windows"); + + our $boost_dir; + foreach my $dir (@dirs) + { + my @files = ( glob("$dir/*.*pp"), glob("$dir/Jamfile*") ); + foreach my $file (@files) + { + if ($file ne "src/tests/unit/thread.cpp" + and $file ne "src/tests/unit/error_handler.cpp" + and $file ne "src/tests/unit/unit_test.cpp") + { + my $from = $file; + my $to = $file; + $to =~ s/^src\/tests\/unit\//$boost_dir\/libs\/asio\/test\//; + copy_source_file($from, $to); + } + } + } +} + +sub copy_latency_tests +{ + my @dirs = ( + "src/tests/latency"); + + our $boost_dir; + foreach my $dir (@dirs) + { + my @files = ( glob("$dir/*.*pp"), glob("$dir/Jamfile*") ); + foreach my $file (@files) + { + my $from = $file; + my $to = $file; + $to =~ s/^src\/tests\/latency\//$boost_dir\/libs\/asio\/test\/latency\//; + copy_source_file($from, $to); + } + } +} + +sub copy_examples +{ + my @dirs = ( + "src/examples/cpp03/allocation", + "src/examples/cpp03/buffers", + "src/examples/cpp03/chat", + "src/examples/cpp03/echo", + "src/examples/cpp03/fork", + "src/examples/cpp03/http/client", + "src/examples/cpp03/http/doc_root", + "src/examples/cpp03/http/server", + "src/examples/cpp03/http/server2", + "src/examples/cpp03/http/server3", + "src/examples/cpp03/http/server4", + "src/examples/cpp03/icmp", + "src/examples/cpp03/invocation", + "src/examples/cpp03/iostreams", + "src/examples/cpp03/local", + "src/examples/cpp03/multicast", + "src/examples/cpp03/nonblocking", + "src/examples/cpp03/porthopper", + "src/examples/cpp03/serialization", + "src/examples/cpp03/services", + "src/examples/cpp03/socks4", + "src/examples/cpp03/spawn", + "src/examples/cpp03/ssl", + "src/examples/cpp03/timeouts", + "src/examples/cpp03/timers", + "src/examples/cpp03/tutorial", + "src/examples/cpp03/tutorial/daytime1", + "src/examples/cpp03/tutorial/daytime2", + "src/examples/cpp03/tutorial/daytime3", + "src/examples/cpp03/tutorial/daytime4", + "src/examples/cpp03/tutorial/daytime5", + "src/examples/cpp03/tutorial/daytime6", + "src/examples/cpp03/tutorial/daytime7", + "src/examples/cpp03/tutorial/timer1", + "src/examples/cpp03/tutorial/timer2", + "src/examples/cpp03/tutorial/timer3", + "src/examples/cpp03/tutorial/timer4", + "src/examples/cpp03/tutorial/timer5", + "src/examples/cpp03/windows", + "src/examples/cpp11/allocation", + "src/examples/cpp11/buffers", + "src/examples/cpp11/chat", + "src/examples/cpp11/echo", + "src/examples/cpp11/futures", + "src/examples/cpp11/http/server", + "src/examples/cpp11/spawn"); + + our $boost_dir; + foreach my $dir (@dirs) + { + my @files = ( + glob("$dir/*.*pp"), + glob("$dir/*.html"), + glob("$dir/Jamfile*"), + glob("$dir/*.pem"), + glob("$dir/README*"), + glob("$dir/*.txt")); + foreach my $file (@files) + { + my $from = $file; + my $to = $file; + $to =~ s/^src\/examples\//$boost_dir\/libs\/asio\/example\//; + copy_source_file($from, $to); + } + } +} + +sub copy_doc +{ + our $boost_dir; + my @files = ( + "src/doc/asio.qbk", + "src/doc/examples.qbk", + "src/doc/reference.xsl", + "src/doc/tutorial.xsl", + glob("src/doc/overview/*.qbk"), + glob("src/doc/requirements/*.qbk")); + foreach my $file (@files) + { + my $from = $file; + my $to = $file; + $to =~ s/^src\/doc\//$boost_dir\/libs\/asio\/doc\//; + copy_source_file($from, $to); + } +} + +sub copy_tools +{ + our $boost_dir; + my @files = ( + glob("src/tools/*.pl")); + foreach my $file (@files) + { + my $from = $file; + my $to = $file; + $to =~ s/^src\/tools\//$boost_dir\/libs\/asio\/tools\//; + copy_source_file($from, $to); + } +} + +copy_include_files(); +create_lib_directory(); +copy_unit_tests(); +copy_latency_tests(); +copy_examples(); +copy_doc(); +copy_tools(); diff --git a/utils/dnp3_src/deps/asio/asio/configure.ac b/utils/dnp3_src/deps/asio/asio/configure.ac new file mode 100644 index 0000000..d453602 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/configure.ac @@ -0,0 +1,265 @@ +AC_INIT(asio, [1.10.8]) +AC_CONFIG_SRCDIR(include/asio.hpp) +AM_MAINTAINER_MODE +AM_INIT_AUTOMAKE([tar-ustar]) + +AC_CANONICAL_HOST +AM_PROG_CC_C_O +AC_PROG_CXX +AC_LANG(C++) +AC_PROG_RANLIB + +AC_DEFINE(_REENTRANT, [1], [Define this]) + +AC_ARG_WITH(boost, + AC_HELP_STRING([--with-boost=DIR],[location of boost distribution]), +[ + if test "${withval}" = no; then + STANDALONE="yes" + else + CPPFLAGS="$CPPFLAGS -I${withval}" + LIBS="$LIBS -L${withval}/stage/lib" + fi +], +[ + BOOSTDIR="`pwd`/../boost_1_55_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + LIBS="$LIBS -L${BOOSTDIR}/stage/lib" + else + BOOSTDIR="`pwd`/../boost_1_54_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + LIBS="$LIBS -L${BOOSTDIR}/stage/lib" + else + BOOSTDIR="`pwd`/../boost_1_53_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_52_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_51_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_50_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_49_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_48_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_47_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_46_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_46_1" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_45_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_44_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_43_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_42_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_41_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_40_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_39_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_38_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_37_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_36_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_35_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_34_1" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_34_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_33_1" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + else + BOOSTDIR="`pwd`/../boost_1_33_0" + if test -d "${BOOSTDIR}"; then + CPPFLAGS="$CPPFLAGS -I${BOOSTDIR}" + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi + fi +]) + +AC_ARG_ENABLE(separate-compilation, +[ --enable-separate-compilation separate compilation of asio source], +[ + SEPARATE_COMPILATION=yes +]) + +AC_ARG_ENABLE(boost-coroutine, +[ --enable-boost-coroutine use Boost.Coroutine to implement stackful coroutines], +[ + HAVE_BOOST_COROUTINE=yes +]) + +if test "$STANDALONE" != yes; then + AC_CHECK_HEADER([boost/noncopyable.hpp],, + [ + echo "Can't find boost headers. Please check the location of the boost" + echo "distribution and rerun configure using the --with-boost=DIR option." + exit 1 + ],[]) +fi + +AC_ARG_WITH(openssl, + AC_HELP_STRING([--with-openssl=DIR],[location of openssl]), +[ + CPPFLAGS="$CPPFLAGS -I${withval}" +],[]) + +AC_CHECK_HEADER([openssl/ssl.h],, +[ + OPENSSL_FOUND=no +],[]) + +if test x$OPENSSL_FOUND != xno; then + LIBS="$LIBS -lssl -lcrypto" +fi + +AM_CONDITIONAL(HAVE_OPENSSL,test x$OPENSSL_FOUND != xno) + +WINDOWS=no +case $host in + *-*-linux*) + CXXFLAGS="$CXXFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ;; + *-*-solaris*) + if test "$GXX" = yes; then + CXXFLAGS="$CXXFLAGS -D_PTHREADS" + else + # We'll assume Sun's CC. + CXXFLAGS="$CXXFLAGS -mt" + fi + LIBS="$LIBS -lsocket -lnsl -lpthread" + ;; + *-*-mingw32*) + CXXFLAGS="$CXXFLAGS -mthreads" + LDFLAGS="$LDFLAGS -mthreads" + LIBS="$LIBS -lws2_32 -lmswsock" + WINDOWS=yes + ;; + *-pc-cygwin*) + CXXFLAGS="$CXXFLAGS -D__USE_W32_SOCKETS -D_WIN32_WINNT=0x0501" + LIBS="$LIBS -lws2_32 -lmswsock" + WINDOWS=yes + ;; + *-apple-darwin*) + CXXFLAGS="$CXXFLAGS" + LDFLAGS="$LDFLAGS" + ;; + *-*-freebsd*) + CXXFLAGS="$CXXFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ;; + *-*-netbsd*) + CXXFLAGS="$CXXFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ;; +esac + +if test "$GXX" = yes; then + CXXFLAGS="$CXXFLAGS -ftemplate-depth-256" + if test "$STANDALONE" = yes; then + CPPFLAGS="-std=c++0x $CPPFLAGS" + fi +fi + +if test "$STANDALONE" = yes; then + CPPFLAGS="$CPPFLAGS -DASIO_STANDALONE" +fi + +if test "$SEPARATE_COMPILATION" = yes; then + CPPFLAGS="$CPPFLAGS -DASIO_SEPARATE_COMPILATION" +fi + +AM_CONDITIONAL(STANDALONE,test x$STANDALONE = xyes) + +AM_CONDITIONAL(SEPARATE_COMPILATION,test x$SEPARATE_COMPILATION = xyes) + +AM_CONDITIONAL(HAVE_BOOST_COROUTINE,test x$HAVE_BOOST_COROUTINE = xyes) + +AM_CONDITIONAL(WINDOWS_TARGET,test x$WINDOWS != xno) + +AC_OUTPUT([ + Makefile + include/Makefile + src/Makefile + src/tests/Makefile + src/examples/cpp03/Makefile + src/examples/cpp11/Makefile]) diff --git a/utils/dnp3_src/deps/asio/asio/include/Makefile.am b/utils/dnp3_src/deps/asio/asio/include/Makefile.am new file mode 100644 index 0000000..13f94ac --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/Makefile.am @@ -0,0 +1,411 @@ +# find . -name "*.*pp" | sed -e 's/^\.\///' | sed -e 's/^.*$/ & \\/' | sort +nobase_include_HEADERS = \ + asio/async_result.hpp \ + asio/basic_datagram_socket.hpp \ + asio/basic_deadline_timer.hpp \ + asio/basic_io_object.hpp \ + asio/basic_raw_socket.hpp \ + asio/basic_seq_packet_socket.hpp \ + asio/basic_serial_port.hpp \ + asio/basic_signal_set.hpp \ + asio/basic_socket_acceptor.hpp \ + asio/basic_socket.hpp \ + asio/basic_socket_iostream.hpp \ + asio/basic_socket_streambuf.hpp \ + asio/basic_streambuf_fwd.hpp \ + asio/basic_streambuf.hpp \ + asio/basic_stream_socket.hpp \ + asio/basic_waitable_timer.hpp \ + asio/buffered_read_stream_fwd.hpp \ + asio/buffered_read_stream.hpp \ + asio/buffered_stream_fwd.hpp \ + asio/buffered_stream.hpp \ + asio/buffered_write_stream_fwd.hpp \ + asio/buffered_write_stream.hpp \ + asio/buffer.hpp \ + asio/buffers_iterator.hpp \ + asio/completion_condition.hpp \ + asio/connect.hpp \ + asio/coroutine.hpp \ + asio/datagram_socket_service.hpp \ + asio/deadline_timer.hpp \ + asio/deadline_timer_service.hpp \ + asio/detail/addressof.hpp \ + asio/detail/array_fwd.hpp \ + asio/detail/array.hpp \ + asio/detail/assert.hpp \ + asio/detail/atomic_count.hpp \ + asio/detail/base_from_completion_cond.hpp \ + asio/detail/bind_handler.hpp \ + asio/detail/buffered_stream_storage.hpp \ + asio/detail/buffer_resize_guard.hpp \ + asio/detail/buffer_sequence_adapter.hpp \ + asio/detail/call_stack.hpp \ + asio/detail/chrono_time_traits.hpp \ + asio/detail/completion_handler.hpp \ + asio/detail/config.hpp \ + asio/detail/consuming_buffers.hpp \ + asio/detail/cstdint.hpp \ + asio/detail/date_time_fwd.hpp \ + asio/detail/deadline_timer_service.hpp \ + asio/detail/dependent_type.hpp \ + asio/detail/descriptor_ops.hpp \ + asio/detail/descriptor_read_op.hpp \ + asio/detail/descriptor_write_op.hpp \ + asio/detail/dev_poll_reactor.hpp \ + asio/detail/epoll_reactor.hpp \ + asio/detail/eventfd_select_interrupter.hpp \ + asio/detail/event.hpp \ + asio/detail/fd_set_adapter.hpp \ + asio/detail/fenced_block.hpp \ + asio/detail/function.hpp \ + asio/detail/gcc_arm_fenced_block.hpp \ + asio/detail/gcc_hppa_fenced_block.hpp \ + asio/detail/gcc_sync_fenced_block.hpp \ + asio/detail/gcc_x86_fenced_block.hpp \ + asio/detail/handler_alloc_helpers.hpp \ + asio/detail/handler_cont_helpers.hpp \ + asio/detail/handler_invoke_helpers.hpp \ + asio/detail/handler_tracking.hpp \ + asio/detail/handler_type_requirements.hpp \ + asio/detail/hash_map.hpp \ + asio/detail/impl/buffer_sequence_adapter.ipp \ + asio/detail/impl/descriptor_ops.ipp \ + asio/detail/impl/dev_poll_reactor.hpp \ + asio/detail/impl/dev_poll_reactor.ipp \ + asio/detail/impl/epoll_reactor.hpp \ + asio/detail/impl/epoll_reactor.ipp \ + asio/detail/impl/eventfd_select_interrupter.ipp \ + asio/detail/impl/handler_tracking.ipp \ + asio/detail/impl/kqueue_reactor.hpp \ + asio/detail/impl/kqueue_reactor.ipp \ + asio/detail/impl/pipe_select_interrupter.ipp \ + asio/detail/impl/posix_event.ipp \ + asio/detail/impl/posix_mutex.ipp \ + asio/detail/impl/posix_thread.ipp \ + asio/detail/impl/posix_tss_ptr.ipp \ + asio/detail/impl/reactive_descriptor_service.ipp \ + asio/detail/impl/reactive_serial_port_service.ipp \ + asio/detail/impl/reactive_socket_service_base.ipp \ + asio/detail/impl/resolver_service_base.ipp \ + asio/detail/impl/select_reactor.hpp \ + asio/detail/impl/select_reactor.ipp \ + asio/detail/impl/service_registry.hpp \ + asio/detail/impl/service_registry.ipp \ + asio/detail/impl/signal_set_service.ipp \ + asio/detail/impl/socket_ops.ipp \ + asio/detail/impl/socket_select_interrupter.ipp \ + asio/detail/impl/strand_service.hpp \ + asio/detail/impl/strand_service.ipp \ + asio/detail/impl/task_io_service.hpp \ + asio/detail/impl/task_io_service.ipp \ + asio/detail/impl/throw_error.ipp \ + asio/detail/impl/timer_queue_ptime.ipp \ + asio/detail/impl/timer_queue_set.ipp \ + asio/detail/impl/win_event.ipp \ + asio/detail/impl/win_iocp_handle_service.ipp \ + asio/detail/impl/win_iocp_io_service.hpp \ + asio/detail/impl/win_iocp_io_service.ipp \ + asio/detail/impl/win_iocp_serial_port_service.ipp \ + asio/detail/impl/win_iocp_socket_service_base.ipp \ + asio/detail/impl/win_mutex.ipp \ + asio/detail/impl/win_object_handle_service.ipp \ + asio/detail/impl/winrt_ssocket_service_base.ipp \ + asio/detail/impl/winrt_timer_scheduler.hpp \ + asio/detail/impl/winrt_timer_scheduler.ipp \ + asio/detail/impl/winsock_init.ipp \ + asio/detail/impl/win_static_mutex.ipp \ + asio/detail/impl/win_thread.ipp \ + asio/detail/impl/win_tss_ptr.ipp \ + asio/detail/io_control.hpp \ + asio/detail/keyword_tss_ptr.hpp \ + asio/detail/kqueue_reactor.hpp \ + asio/detail/limits.hpp \ + asio/detail/local_free_on_block_exit.hpp \ + asio/detail/macos_fenced_block.hpp \ + asio/detail/mutex.hpp \ + asio/detail/noncopyable.hpp \ + asio/detail/null_event.hpp \ + asio/detail/null_fenced_block.hpp \ + asio/detail/null_mutex.hpp \ + asio/detail/null_reactor.hpp \ + asio/detail/null_signal_blocker.hpp \ + asio/detail/null_socket_service.hpp \ + asio/detail/null_static_mutex.hpp \ + asio/detail/null_thread.hpp \ + asio/detail/null_tss_ptr.hpp \ + asio/detail/object_pool.hpp \ + asio/detail/old_win_sdk_compat.hpp \ + asio/detail/operation.hpp \ + asio/detail/op_queue.hpp \ + asio/detail/pipe_select_interrupter.hpp \ + asio/detail/pop_options.hpp \ + asio/detail/posix_event.hpp \ + asio/detail/posix_fd_set_adapter.hpp \ + asio/detail/posix_mutex.hpp \ + asio/detail/posix_signal_blocker.hpp \ + asio/detail/posix_static_mutex.hpp \ + asio/detail/posix_thread.hpp \ + asio/detail/posix_tss_ptr.hpp \ + asio/detail/push_options.hpp \ + asio/detail/reactive_descriptor_service.hpp \ + asio/detail/reactive_null_buffers_op.hpp \ + asio/detail/reactive_serial_port_service.hpp \ + asio/detail/reactive_socket_accept_op.hpp \ + asio/detail/reactive_socket_connect_op.hpp \ + asio/detail/reactive_socket_recvfrom_op.hpp \ + asio/detail/reactive_socket_recvmsg_op.hpp \ + asio/detail/reactive_socket_recv_op.hpp \ + asio/detail/reactive_socket_send_op.hpp \ + asio/detail/reactive_socket_sendto_op.hpp \ + asio/detail/reactive_socket_service_base.hpp \ + asio/detail/reactive_socket_service.hpp \ + asio/detail/reactor_fwd.hpp \ + asio/detail/reactor.hpp \ + asio/detail/reactor_op.hpp \ + asio/detail/reactor_op_queue.hpp \ + asio/detail/regex_fwd.hpp \ + asio/detail/resolve_endpoint_op.hpp \ + asio/detail/resolve_op.hpp \ + asio/detail/resolver_service_base.hpp \ + asio/detail/resolver_service.hpp \ + asio/detail/scoped_lock.hpp \ + asio/detail/scoped_ptr.hpp \ + asio/detail/select_interrupter.hpp \ + asio/detail/select_reactor.hpp \ + asio/detail/service_registry.hpp \ + asio/detail/shared_ptr.hpp \ + asio/detail/signal_blocker.hpp \ + asio/detail/signal_handler.hpp \ + asio/detail/signal_init.hpp \ + asio/detail/signal_op.hpp \ + asio/detail/signal_set_service.hpp \ + asio/detail/socket_holder.hpp \ + asio/detail/socket_ops.hpp \ + asio/detail/socket_option.hpp \ + asio/detail/socket_select_interrupter.hpp \ + asio/detail/socket_types.hpp \ + asio/detail/solaris_fenced_block.hpp \ + asio/detail/static_mutex.hpp \ + asio/detail/std_event.hpp \ + asio/detail/std_mutex.hpp \ + asio/detail/std_static_mutex.hpp \ + asio/detail/std_thread.hpp \ + asio/detail/strand_service.hpp \ + asio/detail/task_io_service.hpp \ + asio/detail/task_io_service_operation.hpp \ + asio/detail/task_io_service_thread_info.hpp \ + asio/detail/thread.hpp \ + asio/detail/thread_info_base.hpp \ + asio/detail/throw_error.hpp \ + asio/detail/throw_exception.hpp \ + asio/detail/timer_queue_base.hpp \ + asio/detail/timer_queue.hpp \ + asio/detail/timer_queue_ptime.hpp \ + asio/detail/timer_queue_set.hpp \ + asio/detail/timer_scheduler_fwd.hpp \ + asio/detail/timer_scheduler.hpp \ + asio/detail/tss_ptr.hpp \ + asio/detail/type_traits.hpp \ + asio/detail/variadic_templates.hpp \ + asio/detail/wait_handler.hpp \ + asio/detail/wait_op.hpp \ + asio/detail/weak_ptr.hpp \ + asio/detail/winapi_thread.hpp \ + asio/detail/win_event.hpp \ + asio/detail/win_fd_set_adapter.hpp \ + asio/detail/win_fenced_block.hpp \ + asio/detail/win_iocp_handle_read_op.hpp \ + asio/detail/win_iocp_handle_service.hpp \ + asio/detail/win_iocp_handle_write_op.hpp \ + asio/detail/win_iocp_io_service.hpp \ + asio/detail/win_iocp_null_buffers_op.hpp \ + asio/detail/win_iocp_operation.hpp \ + asio/detail/win_iocp_overlapped_op.hpp \ + asio/detail/win_iocp_overlapped_ptr.hpp \ + asio/detail/win_iocp_serial_port_service.hpp \ + asio/detail/win_iocp_socket_accept_op.hpp \ + asio/detail/win_iocp_socket_connect_op.hpp \ + asio/detail/win_iocp_socket_recvfrom_op.hpp \ + asio/detail/win_iocp_socket_recvmsg_op.hpp \ + asio/detail/win_iocp_socket_recv_op.hpp \ + asio/detail/win_iocp_socket_send_op.hpp \ + asio/detail/win_iocp_socket_service_base.hpp \ + asio/detail/win_iocp_socket_service.hpp \ + asio/detail/win_iocp_thread_info.hpp \ + asio/detail/win_mutex.hpp \ + asio/detail/win_object_handle_service.hpp \ + asio/detail/winrt_async_manager.hpp \ + asio/detail/winrt_async_op.hpp \ + asio/detail/winrt_resolve_op.hpp \ + asio/detail/winrt_resolver_service.hpp \ + asio/detail/winrt_socket_connect_op.hpp \ + asio/detail/winrt_socket_recv_op.hpp \ + asio/detail/winrt_socket_send_op.hpp \ + asio/detail/winrt_ssocket_service_base.hpp \ + asio/detail/winrt_ssocket_service.hpp \ + asio/detail/winrt_timer_scheduler.hpp \ + asio/detail/winrt_utils.hpp \ + asio/detail/winsock_init.hpp \ + asio/detail/win_static_mutex.hpp \ + asio/detail/win_thread.hpp \ + asio/detail/win_tss_ptr.hpp \ + asio/detail/wrapped_handler.hpp \ + asio/error_code.hpp \ + asio/error.hpp \ + asio/generic/basic_endpoint.hpp \ + asio/generic/datagram_protocol.hpp \ + asio/generic/detail/endpoint.hpp \ + asio/generic/detail/impl/endpoint.ipp \ + asio/generic/raw_protocol.hpp \ + asio/generic/seq_packet_protocol.hpp \ + asio/generic/stream_protocol.hpp \ + asio/handler_alloc_hook.hpp \ + asio/handler_continuation_hook.hpp \ + asio/handler_invoke_hook.hpp \ + asio/handler_type.hpp \ + asio/high_resolution_timer.hpp \ + asio.hpp \ + asio/impl/buffered_read_stream.hpp \ + asio/impl/buffered_write_stream.hpp \ + asio/impl/connect.hpp \ + asio/impl/error_code.ipp \ + asio/impl/error.ipp \ + asio/impl/handler_alloc_hook.ipp \ + asio/impl/io_service.hpp \ + asio/impl/io_service.ipp \ + asio/impl/read_at.hpp \ + asio/impl/read.hpp \ + asio/impl/read_until.hpp \ + asio/impl/serial_port_base.hpp \ + asio/impl/serial_port_base.ipp \ + asio/impl/spawn.hpp \ + asio/impl/src.cpp \ + asio/impl/src.hpp \ + asio/impl/use_future.hpp \ + asio/impl/write_at.hpp \ + asio/impl/write.hpp \ + asio/io_service.hpp \ + asio/ip/address.hpp \ + asio/ip/address_v4.hpp \ + asio/ip/address_v6.hpp \ + asio/ip/basic_endpoint.hpp \ + asio/ip/basic_resolver_entry.hpp \ + asio/ip/basic_resolver.hpp \ + asio/ip/basic_resolver_iterator.hpp \ + asio/ip/basic_resolver_query.hpp \ + asio/ip/detail/endpoint.hpp \ + asio/ip/detail/impl/endpoint.ipp \ + asio/ip/detail/socket_option.hpp \ + asio/ip/host_name.hpp \ + asio/ip/icmp.hpp \ + asio/ip/impl/address.hpp \ + asio/ip/impl/address.ipp \ + asio/ip/impl/address_v4.hpp \ + asio/ip/impl/address_v4.ipp \ + asio/ip/impl/address_v6.hpp \ + asio/ip/impl/address_v6.ipp \ + asio/ip/impl/basic_endpoint.hpp \ + asio/ip/impl/host_name.ipp \ + asio/ip/multicast.hpp \ + asio/ip/resolver_query_base.hpp \ + asio/ip/resolver_service.hpp \ + asio/ip/tcp.hpp \ + asio/ip/udp.hpp \ + asio/ip/unicast.hpp \ + asio/ip/v6_only.hpp \ + asio/is_read_buffered.hpp \ + asio/is_write_buffered.hpp \ + asio/local/basic_endpoint.hpp \ + asio/local/connect_pair.hpp \ + asio/local/datagram_protocol.hpp \ + asio/local/detail/endpoint.hpp \ + asio/local/detail/impl/endpoint.ipp \ + asio/local/stream_protocol.hpp \ + asio/placeholders.hpp \ + asio/posix/basic_descriptor.hpp \ + asio/posix/basic_stream_descriptor.hpp \ + asio/posix/descriptor_base.hpp \ + asio/posix/stream_descriptor.hpp \ + asio/posix/stream_descriptor_service.hpp \ + asio/raw_socket_service.hpp \ + asio/read_at.hpp \ + asio/read.hpp \ + asio/read_until.hpp \ + asio/seq_packet_socket_service.hpp \ + asio/serial_port_base.hpp \ + asio/serial_port.hpp \ + asio/serial_port_service.hpp \ + asio/signal_set.hpp \ + asio/signal_set_service.hpp \ + asio/socket_acceptor_service.hpp \ + asio/socket_base.hpp \ + asio/spawn.hpp \ + asio/ssl/basic_context.hpp \ + asio/ssl/context_base.hpp \ + asio/ssl/context.hpp \ + asio/ssl/context_service.hpp \ + asio/ssl/detail/buffered_handshake_op.hpp \ + asio/ssl/detail/engine.hpp \ + asio/ssl/detail/handshake_op.hpp \ + asio/ssl/detail/impl/engine.ipp \ + asio/ssl/detail/impl/openssl_init.ipp \ + asio/ssl/detail/io.hpp \ + asio/ssl/detail/openssl_init.hpp \ + asio/ssl/detail/openssl_types.hpp \ + asio/ssl/detail/password_callback.hpp \ + asio/ssl/detail/read_op.hpp \ + asio/ssl/detail/shutdown_op.hpp \ + asio/ssl/detail/stream_core.hpp \ + asio/ssl/detail/verify_callback.hpp \ + asio/ssl/detail/write_op.hpp \ + asio/ssl/error.hpp \ + asio/ssl.hpp \ + asio/ssl/impl/context.hpp \ + asio/ssl/impl/context.ipp \ + asio/ssl/impl/error.ipp \ + asio/ssl/impl/rfc2818_verification.ipp \ + asio/ssl/impl/src.hpp \ + asio/ssl/old/basic_context.hpp \ + asio/ssl/old/context_service.hpp \ + asio/ssl/old/detail/openssl_context_service.hpp \ + asio/ssl/old/detail/openssl_operation.hpp \ + asio/ssl/old/detail/openssl_stream_service.hpp \ + asio/ssl/old/stream.hpp \ + asio/ssl/old/stream_service.hpp \ + asio/ssl/rfc2818_verification.hpp \ + asio/ssl/stream_base.hpp \ + asio/ssl/stream.hpp \ + asio/ssl/stream_service.hpp \ + asio/ssl/verify_context.hpp \ + asio/ssl/verify_mode.hpp \ + asio/steady_timer.hpp \ + asio/strand.hpp \ + asio/streambuf.hpp \ + asio/stream_socket_service.hpp \ + asio/system_error.hpp \ + asio/system_timer.hpp \ + asio/thread.hpp \ + asio/time_traits.hpp \ + asio/unyield.hpp \ + asio/use_future.hpp \ + asio/version.hpp \ + asio/waitable_timer_service.hpp \ + asio/wait_traits.hpp \ + asio/windows/basic_handle.hpp \ + asio/windows/basic_object_handle.hpp \ + asio/windows/basic_random_access_handle.hpp \ + asio/windows/basic_stream_handle.hpp \ + asio/windows/object_handle.hpp \ + asio/windows/object_handle_service.hpp \ + asio/windows/overlapped_ptr.hpp \ + asio/windows/random_access_handle.hpp \ + asio/windows/random_access_handle_service.hpp \ + asio/windows/stream_handle.hpp \ + asio/windows/stream_handle_service.hpp \ + asio/write_at.hpp \ + asio/write.hpp \ + asio/yield.hpp + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in diff --git a/utils/dnp3_src/deps/asio/asio/include/asio.hpp b/utils/dnp3_src/deps/asio/asio/include/asio.hpp new file mode 100644 index 0000000..307f0a2 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio.hpp @@ -0,0 +1,122 @@ +// +// asio.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_HPP +#define ASIO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/async_result.hpp" +#include "asio/basic_datagram_socket.hpp" +#include "asio/basic_deadline_timer.hpp" +#include "asio/basic_io_object.hpp" +#include "asio/basic_raw_socket.hpp" +#include "asio/basic_seq_packet_socket.hpp" +#include "asio/basic_serial_port.hpp" +#include "asio/basic_signal_set.hpp" +#include "asio/basic_socket_acceptor.hpp" +#include "asio/basic_socket_iostream.hpp" +#include "asio/basic_socket_streambuf.hpp" +#include "asio/basic_stream_socket.hpp" +#include "asio/basic_streambuf.hpp" +#include "asio/basic_waitable_timer.hpp" +#include "asio/buffer.hpp" +#include "asio/buffered_read_stream_fwd.hpp" +#include "asio/buffered_read_stream.hpp" +#include "asio/buffered_stream_fwd.hpp" +#include "asio/buffered_stream.hpp" +#include "asio/buffered_write_stream_fwd.hpp" +#include "asio/buffered_write_stream.hpp" +#include "asio/buffers_iterator.hpp" +#include "asio/completion_condition.hpp" +#include "asio/connect.hpp" +#include "asio/coroutine.hpp" +#include "asio/datagram_socket_service.hpp" +#include "asio/deadline_timer_service.hpp" +#include "asio/deadline_timer.hpp" +#include "asio/error.hpp" +#include "asio/error_code.hpp" +#include "asio/generic/basic_endpoint.hpp" +#include "asio/generic/datagram_protocol.hpp" +#include "asio/generic/raw_protocol.hpp" +#include "asio/generic/seq_packet_protocol.hpp" +#include "asio/generic/stream_protocol.hpp" +#include "asio/handler_alloc_hook.hpp" +#include "asio/handler_continuation_hook.hpp" +#include "asio/handler_invoke_hook.hpp" +#include "asio/handler_type.hpp" +#include "asio/io_service.hpp" +#include "asio/ip/address.hpp" +#include "asio/ip/address_v4.hpp" +#include "asio/ip/address_v6.hpp" +#include "asio/ip/basic_endpoint.hpp" +#include "asio/ip/basic_resolver.hpp" +#include "asio/ip/basic_resolver_entry.hpp" +#include "asio/ip/basic_resolver_iterator.hpp" +#include "asio/ip/basic_resolver_query.hpp" +#include "asio/ip/host_name.hpp" +#include "asio/ip/icmp.hpp" +#include "asio/ip/multicast.hpp" +#include "asio/ip/resolver_query_base.hpp" +#include "asio/ip/resolver_service.hpp" +#include "asio/ip/tcp.hpp" +#include "asio/ip/udp.hpp" +#include "asio/ip/unicast.hpp" +#include "asio/ip/v6_only.hpp" +#include "asio/is_read_buffered.hpp" +#include "asio/is_write_buffered.hpp" +#include "asio/local/basic_endpoint.hpp" +#include "asio/local/connect_pair.hpp" +#include "asio/local/datagram_protocol.hpp" +#include "asio/local/stream_protocol.hpp" +#include "asio/placeholders.hpp" +#include "asio/posix/basic_descriptor.hpp" +#include "asio/posix/basic_stream_descriptor.hpp" +#include "asio/posix/descriptor_base.hpp" +#include "asio/posix/stream_descriptor.hpp" +#include "asio/posix/stream_descriptor_service.hpp" +#include "asio/raw_socket_service.hpp" +#include "asio/read.hpp" +#include "asio/read_at.hpp" +#include "asio/read_until.hpp" +#include "asio/seq_packet_socket_service.hpp" +#include "asio/serial_port.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/serial_port_service.hpp" +#include "asio/signal_set.hpp" +#include "asio/signal_set_service.hpp" +#include "asio/socket_acceptor_service.hpp" +#include "asio/socket_base.hpp" +#include "asio/strand.hpp" +#include "asio/stream_socket_service.hpp" +#include "asio/streambuf.hpp" +#include "asio/system_error.hpp" +#include "asio/thread.hpp" +#include "asio/time_traits.hpp" +#include "asio/version.hpp" +#include "asio/wait_traits.hpp" +#include "asio/waitable_timer_service.hpp" +#include "asio/windows/basic_handle.hpp" +#include "asio/windows/basic_object_handle.hpp" +#include "asio/windows/basic_random_access_handle.hpp" +#include "asio/windows/basic_stream_handle.hpp" +#include "asio/windows/object_handle.hpp" +#include "asio/windows/object_handle_service.hpp" +#include "asio/windows/overlapped_ptr.hpp" +#include "asio/windows/random_access_handle.hpp" +#include "asio/windows/random_access_handle_service.hpp" +#include "asio/windows/stream_handle.hpp" +#include "asio/windows/stream_handle_service.hpp" +#include "asio/write.hpp" +#include "asio/write_at.hpp" + +#endif // ASIO_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/async_result.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/async_result.hpp new file mode 100644 index 0000000..39f9102 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/async_result.hpp @@ -0,0 +1,94 @@ +// +// async_result.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ASYNC_RESULT_HPP +#define ASIO_ASYNC_RESULT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/handler_type.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// An interface for customising the behaviour of an initiating function. +/** + * This template may be specialised for user-defined handler types. + */ +template +class async_result +{ +public: + /// The return type of the initiating function. + typedef void type; + + /// Construct an async result from a given handler. + /** + * When using a specalised async_result, the constructor has an opportunity + * to initialise some state associated with the handler, which is then + * returned from the initiating function. + */ + explicit async_result(Handler&) + { + } + + /// Obtain the value to be returned from the initiating function. + type get() + { + } +}; + +namespace detail { + +// Helper template to deduce the true type of a handler, capture a local copy +// of the handler, and then create an async_result for the handler. +template +struct async_result_init +{ + explicit async_result_init(ASIO_MOVE_ARG(Handler) orig_handler) + : handler(ASIO_MOVE_CAST(Handler)(orig_handler)), + result(handler) + { + } + + typename handler_type::type handler; + async_result::type> result; +}; + +template +struct async_result_type_helper +{ + typedef typename async_result< + typename handler_type::type + >::type type; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_INITFN_RESULT_TYPE(h, sig) \ + void_or_deduced +#elif defined(_MSC_VER) && (_MSC_VER < 1500) +# define ASIO_INITFN_RESULT_TYPE(h, sig) \ + typename ::asio::detail::async_result_type_helper::type +#else +# define ASIO_INITFN_RESULT_TYPE(h, sig) \ + typename ::asio::async_result< \ + typename ::asio::handler_type::type>::type +#endif + +#endif // ASIO_ASYNC_RESULT_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_datagram_socket.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_datagram_socket.hpp new file mode 100644 index 0000000..380f7a4 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_datagram_socket.hpp @@ -0,0 +1,949 @@ +// +// basic_datagram_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_DATAGRAM_SOCKET_HPP +#define ASIO_BASIC_DATAGRAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/basic_socket.hpp" +#include "asio/datagram_socket_service.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides datagram-oriented socket functionality. +/** + * The basic_datagram_socket class template provides asynchronous and blocking + * datagram-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template > +class basic_datagram_socket + : public basic_socket +{ +public: + /// (Deprecated: Use native_handle_type.) The native representation of a + /// socket. + typedef typename DatagramSocketService::native_handle_type native_type; + + /// The native representation of a socket. + typedef typename DatagramSocketService::native_handle_type native_handle_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param io_service The io_service object that the datagram socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + */ + explicit basic_datagram_socket(asio::io_service& io_service) + : basic_socket(io_service) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param io_service The io_service object that the datagram socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_datagram_socket(asio::io_service& io_service, + const protocol_type& protocol) + : basic_socket(io_service, protocol) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param io_service The io_service object that the datagram socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_datagram_socket(asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_socket(io_service, endpoint) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param io_service The io_service object that the datagram socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_datagram_socket(asio::io_service& io_service, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket( + io_service, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_datagram_socket from another. + /** + * This constructor moves a datagram socket from one object to another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(io_service&) constructor. + */ + basic_datagram_socket(basic_datagram_socket&& other) + : basic_socket( + ASIO_MOVE_CAST(basic_datagram_socket)(other)) + { + } + + /// Move-assign a basic_datagram_socket from another. + /** + * This assignment operator moves a datagram socket from one object to + * another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(io_service&) constructor. + */ + basic_datagram_socket& operator=(basic_datagram_socket&& other) + { + basic_socket::operator=( + ASIO_MOVE_CAST(basic_datagram_socket)(other)); + return *this; + } + + /// Move-construct a basic_datagram_socket from a socket of another protocol + /// type. + /** + * This constructor moves a datagram socket from one object to another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(io_service&) constructor. + */ + template + basic_datagram_socket( + basic_datagram_socket&& other, + typename enable_if::value>::type* = 0) + : basic_socket( + ASIO_MOVE_CAST2(basic_datagram_socket< + Protocol1, DatagramSocketService1>)(other)) + { + } + + /// Move-assign a basic_datagram_socket from a socket of another protocol + /// type. + /** + * This assignment operator moves a datagram socket from one object to + * another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(io_service&) constructor. + */ + template + typename enable_if::value, + basic_datagram_socket>::type& operator=( + basic_datagram_socket&& other) + { + basic_socket::operator=( + ASIO_MOVE_CAST2(basic_datagram_socket< + Protocol1, DatagramSocketService1>)(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->get_service().send( + this->get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().send( + this->get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->get_service().send( + this->get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to asynchronously send data on the datagram socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send(this->get_implementation(), + buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to asynchronously send data on the datagram socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send(this->get_implementation(), + buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(asio::buffer(data, size), destination); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + asio::error_code ec; + std::size_t s = this->get_service().send_to( + this->get_implementation(), buffers, destination, 0, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().send_to( + this->get_implementation(), buffers, destination, flags, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->get_service().send_to(this->get_implementation(), + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * asio::buffer(data, size), destination, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send_to( + this->get_implementation(), buffers, destination, 0, + ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send_to( + this->get_implementation(), buffers, destination, flags, + ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->get_service().receive( + this->get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().receive( + this->get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->get_service().receive( + this->get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive(this->get_implementation(), + buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive(this->get_implementation(), + buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * asio::buffer(data, size), sender_endpoint); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + asio::error_code ec; + std::size_t s = this->get_service().receive_from( + this->get_implementation(), buffers, sender_endpoint, 0, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().receive_from( + this->get_implementation(), buffers, sender_endpoint, flags, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->get_service().receive_from(this->get_implementation(), + buffers, sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * asio::buffer(data, size), sender_endpoint, handler); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, 0, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, flags, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_deadline_timer.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_deadline_timer.hpp new file mode 100644 index 0000000..89bc1dd --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_deadline_timer.hpp @@ -0,0 +1,518 @@ +// +// basic_deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_DEADLINE_TIMER_HPP +#define ASIO_BASIC_DEADLINE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include "asio/basic_io_object.hpp" +#include "asio/deadline_timer_service.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides waitable timer functionality. +/** + * The basic_deadline_timer class template provides the ability to perform a + * blocking or asynchronous wait for a timer to expire. + * + * A deadline timer is always in one of two states: "expired" or "not expired". + * If the wait() or async_wait() function is called on an expired timer, the + * wait operation will complete immediately. + * + * Most applications will use the asio::deadline_timer typedef. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Examples + * Performing a blocking wait: + * @code + * // Construct a timer without setting an expiry time. + * asio::deadline_timer timer(io_service); + * + * // Set an expiry time relative to now. + * timer.expires_from_now(boost::posix_time::seconds(5)); + * + * // Wait for the timer to expire. + * timer.wait(); + * @endcode + * + * @par + * Performing an asynchronous wait: + * @code + * void handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Timer expired. + * } + * } + * + * ... + * + * // Construct a timer with an absolute expiry time. + * asio::deadline_timer timer(io_service, + * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); + * + * // Start an asynchronous wait. + * timer.async_wait(handler); + * @endcode + * + * @par Changing an active deadline_timer's expiry time + * + * Changing the expiry time of a timer while there are pending asynchronous + * waits causes those wait operations to be cancelled. To ensure that the action + * associated with the timer is performed only once, use something like this: + * used: + * + * @code + * void on_some_event() + * { + * if (my_timer.expires_from_now(seconds(5)) > 0) + * { + * // We managed to cancel the timer. Start new asynchronous wait. + * my_timer.async_wait(on_timeout); + * } + * else + * { + * // Too late, timer has already expired! + * } + * } + * + * void on_timeout(const asio::error_code& e) + * { + * if (e != asio::error::operation_aborted) + * { + * // Timer was not cancelled, take necessary action. + * } + * } + * @endcode + * + * @li The asio::basic_deadline_timer::expires_from_now() function + * cancels any pending asynchronous waits, and returns the number of + * asynchronous waits that were cancelled. If it returns 0 then you were too + * late and the wait handler has already been executed, or will soon be + * executed. If it returns 1 then the wait handler was successfully cancelled. + * + * @li If a wait handler is cancelled, the asio::error_code passed to + * it contains the value asio::error::operation_aborted. + */ +template , + typename TimerService = deadline_timer_service > +class basic_deadline_timer + : public basic_io_object +{ +public: + /// The time traits type. + typedef TimeTraits traits_type; + + /// The time type. + typedef typename traits_type::time_type time_type; + + /// The duration type. + typedef typename traits_type::duration_type duration_type; + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_from_now() functions must be called to set an + * expiry time before the timer can be waited on. + * + * @param io_service The io_service object that the timer will use to dispatch + * handlers for any asynchronous operations performed on the timer. + */ + explicit basic_deadline_timer(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param io_service The io_service object that the timer will use to dispatch + * handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + basic_deadline_timer(asio::io_service& io_service, + const time_type& expiry_time) + : basic_io_object(io_service) + { + asio::error_code ec; + this->service.expires_at(this->implementation, expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param io_service The io_service object that the timer will use to dispatch + * handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + basic_deadline_timer(asio::io_service& io_service, + const duration_type& expiry_time) + : basic_io_object(io_service) + { + asio::error_code ec; + this->service.expires_from_now(this->implementation, expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel() + { + asio::error_code ec; + std::size_t s = this->service.cancel(this->implementation, ec); + asio::detail::throw_error(ec, "cancel"); + return s; + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel(asio::error_code& ec) + { + return this->service.cancel(this->implementation, ec); + } + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one() + { + asio::error_code ec; + std::size_t s = this->service.cancel_one(this->implementation, ec); + asio::detail::throw_error(ec, "cancel_one"); + return s; + } + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one(asio::error_code& ec) + { + return this->service.cancel_one(this->implementation, ec); + } + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_type expires_at() const + { + return this->service.expires_at(this->implementation); + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_type& expiry_time) + { + asio::error_code ec; + std::size_t s = this->service.expires_at( + this->implementation, expiry_time, ec); + asio::detail::throw_error(ec, "expires_at"); + return s; + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_type& expiry_time, + asio::error_code& ec) + { + return this->service.expires_at(this->implementation, expiry_time, ec); + } + + /// Get the timer's expiry time relative to now. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + duration_type expires_from_now() const + { + return this->service.expires_from_now(this->implementation); + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration_type& expiry_time) + { + asio::error_code ec; + std::size_t s = this->service.expires_from_now( + this->implementation, expiry_time, ec); + asio::detail::throw_error(ec, "expires_from_now"); + return s; + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration_type& expiry_time, + asio::error_code& ec) + { + return this->service.expires_from_now( + this->implementation, expiry_time, ec); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @throws asio::system_error Thrown on failure. + */ + void wait() + { + asio::error_code ec; + this->service.wait(this->implementation, ec); + asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(asio::error_code& ec) + { + this->service.wait(this->implementation, ec); + } + + /// Start an asynchronous wait on the timer. + /** + * This function may be used to initiate an asynchronous wait against the + * timer. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li The timer has expired. + * + * @li The timer was cancelled, in which case the handler is passed the error + * code asio::error::operation_aborted. + * + * @param handler The handler to be called when the timer expires. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (asio::error_code)) + async_wait(ASIO_MOVE_ARG(WaitHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + return this->service.async_wait(this->implementation, + ASIO_MOVE_CAST(WaitHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_BOOST_DATE_TIME) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_DEADLINE_TIMER_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_io_object.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_io_object.hpp new file mode 100644 index 0000000..ed0f938 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_io_object.hpp @@ -0,0 +1,241 @@ +// +// basic_io_object.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_IO_OBJECT_HPP +#define ASIO_BASIC_IO_OBJECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/io_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if defined(ASIO_HAS_MOVE) +namespace detail +{ + // Type trait used to determine whether a service supports move. + template + class service_has_move + { + private: + typedef IoObjectService service_type; + typedef typename service_type::implementation_type implementation_type; + + template + static auto asio_service_has_move_eval(T* t, U* u) + -> decltype(t->move_construct(*u, *u), char()); + static char (&asio_service_has_move_eval(...))[2]; + + public: + static const bool value = + sizeof(asio_service_has_move_eval( + static_cast(0), + static_cast(0))) == 1; + }; +} +#endif // defined(ASIO_HAS_MOVE) + +/// Base class for all I/O objects. +/** + * @note All I/O objects are non-copyable. However, when using C++0x, certain + * I/O objects do support move construction and move assignment. + */ +#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +template +#else +template ::value> +#endif +class basic_io_object +{ +public: + /// The type of the service that will be used to provide I/O operations. + typedef IoObjectService service_type; + + /// The underlying implementation type of I/O object. + typedef typename service_type::implementation_type implementation_type; + + /// Get the io_service associated with the object. + /** + * This function may be used to obtain the io_service object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_service& get_io_service() + { + return service.get_io_service(); + } + +protected: + /// Construct a basic_io_object. + /** + * Performs: + * @code get_service().construct(get_implementation()); @endcode + */ + explicit basic_io_object(asio::io_service& io_service) + : service(asio::use_service(io_service)) + { + service.construct(implementation); + } + +#if defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_io_object. + /** + * Performs: + * @code get_service().move_construct( + * get_implementation(), other.get_implementation()); @endcode + * + * @note Available only for services that support movability, + */ + basic_io_object(basic_io_object&& other); + + /// Move-assign a basic_io_object. + /** + * Performs: + * @code get_service().move_assign(get_implementation(), + * other.get_service(), other.get_implementation()); @endcode + * + * @note Available only for services that support movability, + */ + basic_io_object& operator=(basic_io_object&& other); +#endif // defined(GENERATING_DOCUMENTATION) + + /// Protected destructor to prevent deletion through this type. + /** + * Performs: + * @code get_service().destroy(get_implementation()); @endcode + */ + ~basic_io_object() + { + service.destroy(implementation); + } + + /// Get the service associated with the I/O object. + service_type& get_service() + { + return service; + } + + /// Get the service associated with the I/O object. + const service_type& get_service() const + { + return service; + } + + /// (Deprecated: Use get_service().) The service associated with the I/O + /// object. + /** + * @note Available only for services that do not support movability. + */ + service_type& service; + + /// Get the underlying implementation of the I/O object. + implementation_type& get_implementation() + { + return implementation; + } + + /// Get the underlying implementation of the I/O object. + const implementation_type& get_implementation() const + { + return implementation; + } + + /// (Deprecated: Use get_implementation().) The underlying implementation of + /// the I/O object. + implementation_type implementation; + +private: + basic_io_object(const basic_io_object&); + basic_io_object& operator=(const basic_io_object&); +}; + +#if defined(ASIO_HAS_MOVE) +// Specialisation for movable objects. +template +class basic_io_object +{ +public: + typedef IoObjectService service_type; + typedef typename service_type::implementation_type implementation_type; + + asio::io_service& get_io_service() + { + return service_->get_io_service(); + } + +protected: + explicit basic_io_object(asio::io_service& io_service) + : service_(&asio::use_service(io_service)) + { + service_->construct(implementation); + } + + basic_io_object(basic_io_object&& other) + : service_(&other.get_service()) + { + service_->move_construct(implementation, other.implementation); + } + + ~basic_io_object() + { + service_->destroy(implementation); + } + + basic_io_object& operator=(basic_io_object&& other) + { + service_->move_assign(implementation, + *other.service_, other.implementation); + service_ = other.service_; + return *this; + } + + service_type& get_service() + { + return *service_; + } + + const service_type& get_service() const + { + return *service_; + } + + implementation_type& get_implementation() + { + return implementation; + } + + const implementation_type& get_implementation() const + { + return implementation; + } + + implementation_type implementation; + +private: + basic_io_object(const basic_io_object&); + void operator=(const basic_io_object&); + + IoObjectService* service_; +}; +#endif // defined(ASIO_HAS_MOVE) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_IO_OBJECT_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_raw_socket.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_raw_socket.hpp new file mode 100644 index 0000000..e0787f4 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_raw_socket.hpp @@ -0,0 +1,940 @@ +// +// basic_raw_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_RAW_SOCKET_HPP +#define ASIO_BASIC_RAW_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/raw_socket_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides raw-oriented socket functionality. +/** + * The basic_raw_socket class template provides asynchronous and blocking + * raw-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template > +class basic_raw_socket + : public basic_socket +{ +public: + /// (Deprecated: Use native_handle_type.) The native representation of a + /// socket. + typedef typename RawSocketService::native_handle_type native_type; + + /// The native representation of a socket. + typedef typename RawSocketService::native_handle_type native_handle_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param io_service The io_service object that the raw socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + */ + explicit basic_raw_socket(asio::io_service& io_service) + : basic_socket(io_service) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param io_service The io_service object that the raw socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(asio::io_service& io_service, + const protocol_type& protocol) + : basic_socket(io_service, protocol) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param io_service The io_service object that the raw socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_socket(io_service, endpoint) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param io_service The io_service object that the raw socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_raw_socket(asio::io_service& io_service, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket( + io_service, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_raw_socket from another. + /** + * This constructor moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(io_service&) constructor. + */ + basic_raw_socket(basic_raw_socket&& other) + : basic_socket( + ASIO_MOVE_CAST(basic_raw_socket)(other)) + { + } + + /// Move-assign a basic_raw_socket from another. + /** + * This assignment operator moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(io_service&) constructor. + */ + basic_raw_socket& operator=(basic_raw_socket&& other) + { + basic_socket::operator=( + ASIO_MOVE_CAST(basic_raw_socket)(other)); + return *this; + } + + /// Move-construct a basic_raw_socket from a socket of another protocol type. + /** + * This constructor moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(io_service&) constructor. + */ + template + basic_raw_socket(basic_raw_socket&& other, + typename enable_if::value>::type* = 0) + : basic_socket( + ASIO_MOVE_CAST2(basic_raw_socket< + Protocol1, RawSocketService1>)(other)) + { + } + + /// Move-assign a basic_raw_socket from a socket of another protocol type. + /** + * This assignment operator moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(io_service&) constructor. + */ + template + typename enable_if::value, + basic_raw_socket>::type& operator=( + basic_raw_socket&& other) + { + basic_socket::operator=( + ASIO_MOVE_CAST2(basic_raw_socket< + Protocol1, RawSocketService1>)(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->get_service().send( + this->get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().send( + this->get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->get_service().send( + this->get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send(this->get_implementation(), + buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send(this->get_implementation(), + buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(asio::buffer(data, size), destination); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + asio::error_code ec; + std::size_t s = this->get_service().send_to( + this->get_implementation(), buffers, destination, 0, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().send_to( + this->get_implementation(), buffers, destination, flags, ec); + asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->get_service().send_to(this->get_implementation(), + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * asio::ip::udp::endpoint destination( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * asio::buffer(data, size), destination, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send_to(this->get_implementation(), + buffers, destination, 0, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send_to( + this->get_implementation(), buffers, destination, flags, + ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->get_service().receive( + this->get_implementation(), buffers, 0, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().receive( + this->get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->get_service().receive( + this->get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive(this->get_implementation(), + buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive(this->get_implementation(), + buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * asio::buffer(data, size), sender_endpoint); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + asio::error_code ec; + std::size_t s = this->get_service().receive_from( + this->get_implementation(), buffers, sender_endpoint, 0, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().receive_from( + this->get_implementation(), buffers, sender_endpoint, flags, ec); + asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + asio::error_code& ec) + { + return this->get_service().receive_from(this->get_implementation(), + buffers, sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * asio::buffer(data, size), 0, sender_endpoint, handler); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, 0, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, flags, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_RAW_SOCKET_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_seq_packet_socket.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_seq_packet_socket.hpp new file mode 100644 index 0000000..8881596 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_seq_packet_socket.hpp @@ -0,0 +1,565 @@ +// +// basic_seq_packet_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_SEQ_PACKET_SOCKET_HPP +#define ASIO_BASIC_SEQ_PACKET_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/seq_packet_socket_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides sequenced packet socket functionality. +/** + * The basic_seq_packet_socket class template provides asynchronous and blocking + * sequenced packet socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template > +class basic_seq_packet_socket + : public basic_socket +{ +public: + /// (Deprecated: Use native_handle_type.) The native representation of a + /// socket. + typedef typename SeqPacketSocketService::native_handle_type native_type; + + /// The native representation of a socket. + typedef typename SeqPacketSocketService::native_handle_type + native_handle_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_seq_packet_socket without opening it. + /** + * This constructor creates a sequenced packet socket without opening it. The + * socket needs to be opened and then connected or accepted before data can + * be sent or received on it. + * + * @param io_service The io_service object that the sequenced packet socket + * will use to dispatch handlers for any asynchronous operations performed on + * the socket. + */ + explicit basic_seq_packet_socket(asio::io_service& io_service) + : basic_socket(io_service) + { + } + + /// Construct and open a basic_seq_packet_socket. + /** + * This constructor creates and opens a sequenced_packet socket. The socket + * needs to be connected or accepted before data can be sent or received on + * it. + * + * @param io_service The io_service object that the sequenced packet socket + * will use to dispatch handlers for any asynchronous operations performed on + * the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_seq_packet_socket(asio::io_service& io_service, + const protocol_type& protocol) + : basic_socket(io_service, protocol) + { + } + + /// Construct a basic_seq_packet_socket, opening it and binding it to the + /// given local endpoint. + /** + * This constructor creates a sequenced packet socket and automatically opens + * it bound to the specified endpoint on the local machine. The protocol used + * is the protocol associated with the given endpoint. + * + * @param io_service The io_service object that the sequenced packet socket + * will use to dispatch handlers for any asynchronous operations performed on + * the socket. + * + * @param endpoint An endpoint on the local machine to which the sequenced + * packet socket will be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_seq_packet_socket(asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_socket(io_service, endpoint) + { + } + + /// Construct a basic_seq_packet_socket on an existing native socket. + /** + * This constructor creates a sequenced packet socket object to hold an + * existing native socket. + * + * @param io_service The io_service object that the sequenced packet socket + * will use to dispatch handlers for any asynchronous operations performed on + * the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_seq_packet_socket(asio::io_service& io_service, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket( + io_service, protocol, native_socket) + { + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_seq_packet_socket from another. + /** + * This constructor moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + */ + basic_seq_packet_socket(basic_seq_packet_socket&& other) + : basic_socket( + ASIO_MOVE_CAST(basic_seq_packet_socket)(other)) + { + } + + /// Move-assign a basic_seq_packet_socket from another. + /** + * This assignment operator moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + */ + basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other) + { + basic_socket::operator=( + ASIO_MOVE_CAST(basic_seq_packet_socket)(other)); + return *this; + } + + /// Move-construct a basic_seq_packet_socket from a socket of another protocol + /// type. + /** + * This constructor moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + */ + template + basic_seq_packet_socket( + basic_seq_packet_socket&& other, + typename enable_if::value>::type* = 0) + : basic_socket( + ASIO_MOVE_CAST2(basic_seq_packet_socket< + Protocol1, SeqPacketSocketService1>)(other)) + { + } + + /// Move-assign a basic_seq_packet_socket from a socket of another protocol + /// type. + /** + * This assignment operator moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + */ + template + typename enable_if::value, + basic_seq_packet_socket>::type& operator=( + basic_seq_packet_socket&& other) + { + basic_socket::operator=( + ASIO_MOVE_CAST2(basic_seq_packet_socket< + Protocol1, SeqPacketSocketService1>)(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Send some data on the socket. + /** + * This function is used to send data on the sequenced packet socket. The + * function call will block until the data has been sent successfully, or an + * until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + asio::error_code ec; + std::size_t s = this->get_service().send( + this->get_implementation(), buffers, flags, ec); + asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the sequenced packet socket. The + * function call will block the data has been sent successfully, or an until + * error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. Returns 0 if an error occurred. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) + { + return this->get_service().send( + this->get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the sequenced packet + * socket. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_send(this->get_implementation(), + buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(asio::buffer(data, size), out_flags); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags) + { + asio::error_code ec; + std::size_t s = this->get_service().receive( + this->get_implementation(), buffers, 0, out_flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @returns The number of bytes received. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(asio::buffer(data, size), 0, out_flags); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags) + { + asio::error_code ec; + std::size_t s = this->get_service().receive( + this->get_implementation(), buffers, in_flags, out_flags, ec); + asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. Returns 0 if an error occurred. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, asio::error_code& ec) + { + return this->get_service().receive(this->get_implementation(), + buffers, in_flags, out_flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the sequenced + * packet socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param out_flags Once the asynchronous operation completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. The caller must guarantee that the referenced + * variable remains valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(asio::buffer(data, size), out_flags, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive( + this->get_implementation(), buffers, 0, out_flags, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the sequenced + * data socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags Once the asynchronous operation completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. The caller must guarantee that the referenced + * variable remains valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive( + * asio::buffer(data, size), + * 0, out_flags, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_receive( + this->get_implementation(), buffers, in_flags, out_flags, + ASIO_MOVE_CAST(ReadHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SEQ_PACKET_SOCKET_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_serial_port.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_serial_port.hpp new file mode 100644 index 0000000..dc07b69 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_serial_port.hpp @@ -0,0 +1,695 @@ +// +// basic_serial_port.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_SERIAL_PORT_HPP +#define ASIO_BASIC_SERIAL_PORT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include "asio/basic_io_object.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/serial_port_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides serial port functionality. +/** + * The basic_serial_port class template provides functionality that is common + * to all serial ports. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_serial_port + : public basic_io_object, + public serial_port_base +{ +public: + /// (Deprecated: Use native_handle_type.) The native representation of a + /// serial port. + typedef typename SerialPortService::native_handle_type native_type; + + /// The native representation of a serial port. + typedef typename SerialPortService::native_handle_type native_handle_type; + + /// A basic_serial_port is always the lowest layer. + typedef basic_serial_port lowest_layer_type; + + /// Construct a basic_serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + */ + explicit basic_serial_port(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param device The platform-specific device name for this serial + * port. + */ + explicit basic_serial_port(asio::io_service& io_service, + const char* device) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param device The platform-specific device name for this serial + * port. + */ + explicit basic_serial_port(asio::io_service& io_service, + const std::string& device) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param native_serial_port A native serial port. + * + * @throws asio::system_error Thrown on failure. + */ + basic_serial_port(asio::io_service& io_service, + const native_handle_type& native_serial_port) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().assign(this->get_implementation(), + native_serial_port, ec); + asio::detail::throw_error(ec, "assign"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_serial_port from another. + /** + * This constructor moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(io_service&) constructor. + */ + basic_serial_port(basic_serial_port&& other) + : basic_io_object( + ASIO_MOVE_CAST(basic_serial_port)(other)) + { + } + + /// Move-assign a basic_serial_port from another. + /** + * This assignment operator moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(io_service&) constructor. + */ + basic_serial_port& operator=(basic_serial_port&& other) + { + basic_io_object::operator=( + ASIO_MOVE_CAST(basic_serial_port)(other)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port for the specified device name. + * + * @param device The platform-specific device name. + * + * @throws asio::system_error Thrown on failure. + */ + void open(const std::string& device) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), device, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port using the given platform-specific + * device name. + * + * @param device The platform-specific device name. + * + * @param ec Set the indicate what error occurred, if any. + */ + asio::error_code open(const std::string& device, + asio::error_code& ec) + { + return this->get_service().open(this->get_implementation(), device, ec); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_serial_port) + { + asio::error_code ec; + this->get_service().assign(this->get_implementation(), + native_serial_port, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code assign(const native_handle_type& native_serial_port, + asio::error_code& ec) + { + return this->get_service().assign(this->get_implementation(), + native_serial_port, ec); + } + + /// Determine whether the serial port is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + this->get_service().close(this->get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code close(asio::error_code& ec) + { + return this->get_service().close(this->get_implementation(), ec); + } + + /// (Deprecated: Use native_handle().) Get the native serial port + /// representation. + /** + * This function may be used to obtain the underlying representation of the + * serial port. This is intended to allow access to native serial port + * functionality that is not otherwise provided. + */ + native_type native() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Get the native serial port representation. + /** + * This function may be used to obtain the underlying representation of the + * serial port. This is intended to allow access to native serial port + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code cancel(asio::error_code& ec) + { + return this->get_service().cancel(this->get_implementation(), ec); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @throws asio::system_error Thrown on failure. + */ + void send_break() + { + asio::error_code ec; + this->get_service().send_break(this->get_implementation(), ec); + asio::detail::throw_error(ec, "send_break"); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code send_break(asio::error_code& ec) + { + return this->get_service().send_break(this->get_implementation(), ec); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @throws asio::system_error Thrown on failure. + * + * @sa SettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + void set_option(const SettableSerialPortOption& option) + { + asio::error_code ec; + this->get_service().set_option(this->get_implementation(), option, ec); + asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + asio::error_code set_option(const SettableSerialPortOption& option, + asio::error_code& ec) + { + return this->get_service().set_option( + this->get_implementation(), option, ec); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @throws asio::system_error Thrown on failure. + * + * @sa GettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + void get_option(GettableSerialPortOption& option) + { + asio::error_code ec; + this->get_service().get_option(this->get_implementation(), option, ec); + asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSerialPortOption @n + * asio::serial_port_base::baud_rate @n + * asio::serial_port_base::flow_control @n + * asio::serial_port_base::parity @n + * asio::serial_port_base::stop_bits @n + * asio::serial_port_base::character_size + */ + template + asio::error_code get_option(GettableSerialPortOption& option, + asio::error_code& ec) + { + return this->get_service().get_option( + this->get_implementation(), option, ec); + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @returns The number of bytes written. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.write_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->get_service().write_some( + this->get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return this->get_service().write_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the serial port. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the serial port. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.async_write_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + return this->get_service().async_write_some(this->get_implementation(), + buffers, ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws asio::system_error Thrown on failure. An error code of + * asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.read_some(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->get_service().read_some( + this->get_implementation(), buffers, ec); + asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return this->get_service().read_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the serial port. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.async_read_some(asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return this->get_service().async_read_some(this->get_implementation(), + buffers, ASIO_MOVE_CAST(ReadHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // defined(ASIO_HAS_SERIAL_PORT) + // || defined(GENERATING_DOCUMENTATION) + +#endif // ASIO_BASIC_SERIAL_PORT_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_signal_set.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_signal_set.hpp new file mode 100644 index 0000000..246a9c1 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_signal_set.hpp @@ -0,0 +1,384 @@ +// +// basic_signal_set.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_SIGNAL_SET_HPP +#define ASIO_BASIC_SIGNAL_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#include "asio/basic_io_object.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/signal_set_service.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides signal functionality. +/** + * The basic_signal_set class template provides the ability to perform an + * asynchronous wait for one or more signals to occur. + * + * Most applications will use the asio::signal_set typedef. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Performing an asynchronous wait: + * @code + * void handler( + * const asio::error_code& error, + * int signal_number) + * { + * if (!error) + * { + * // A signal occurred. + * } + * } + * + * ... + * + * // Construct a signal set registered for process termination. + * asio::signal_set signals(io_service, SIGINT, SIGTERM); + * + * // Start an asynchronous wait for one of the signals to occur. + * signals.async_wait(handler); + * @endcode + * + * @par Queueing of signal notifications + * + * If a signal is registered with a signal_set, and the signal occurs when + * there are no waiting handlers, then the signal notification is queued. The + * next async_wait operation on that signal_set will dequeue the notification. + * If multiple notifications are queued, subsequent async_wait operations + * dequeue them one at a time. Signal notifications are dequeued in order of + * ascending signal number. + * + * If a signal number is removed from a signal_set (using the @c remove or @c + * erase member functions) then any queued notifications for that signal are + * discarded. + * + * @par Multiple registration of signals + * + * The same signal number may be registered with different signal_set objects. + * When the signal occurs, one handler is called for each signal_set object. + * + * Note that multiple registration only works for signals that are registered + * using Asio. The application must not also register a signal handler using + * functions such as @c signal() or @c sigaction(). + * + * @par Signal masking on POSIX platforms + * + * POSIX allows signals to be blocked using functions such as @c sigprocmask() + * and @c pthread_sigmask(). For signals to be delivered, programs must ensure + * that any signals registered using signal_set objects are unblocked in at + * least one thread. + */ +template +class basic_signal_set + : public basic_io_object +{ +public: + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param io_service The io_service object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + */ + explicit basic_signal_set(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param io_service The io_service object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(io_service); + * signals.add(signal_number_1); @endcode + */ + basic_signal_set(asio::io_service& io_service, int signal_number_1) + : basic_io_object(io_service) + { + asio::error_code ec; + this->service.add(this->implementation, signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param io_service The io_service object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(io_service); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + basic_signal_set(asio::io_service& io_service, int signal_number_1, + int signal_number_2) + : basic_io_object(io_service) + { + asio::error_code ec; + this->service.add(this->implementation, signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + this->service.add(this->implementation, signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param io_service The io_service object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code asio::signal_set signals(io_service); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + basic_signal_set(asio::io_service& io_service, int signal_number_1, + int signal_number_2, int signal_number_3) + : basic_io_object(io_service) + { + asio::error_code ec; + this->service.add(this->implementation, signal_number_1, ec); + asio::detail::throw_error(ec, "add"); + this->service.add(this->implementation, signal_number_2, ec); + asio::detail::throw_error(ec, "add"); + this->service.add(this->implementation, signal_number_3, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @throws asio::system_error Thrown on failure. + */ + void add(int signal_number) + { + asio::error_code ec; + this->service.add(this->implementation, signal_number, ec); + asio::detail::throw_error(ec, "add"); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code add(int signal_number, + asio::error_code& ec) + { + return this->service.add(this->implementation, signal_number, ec); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @throws asio::system_error Thrown on failure. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + void remove(int signal_number) + { + asio::error_code ec; + this->service.remove(this->implementation, signal_number, ec); + asio::detail::throw_error(ec, "remove"); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + asio::error_code remove(int signal_number, + asio::error_code& ec) + { + return this->service.remove(this->implementation, signal_number, ec); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @throws asio::system_error Thrown on failure. + * + * @note Removes all queued notifications. + */ + void clear() + { + asio::error_code ec; + this->service.clear(this->implementation, ec); + asio::detail::throw_error(ec, "clear"); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes all queued notifications. + */ + asio::error_code clear(asio::error_code& ec) + { + return this->service.clear(this->implementation, ec); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @throws asio::system_error Thrown on failure. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + void cancel() + { + asio::error_code ec; + this->service.cancel(this->implementation, ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + asio::error_code cancel(asio::error_code& ec) + { + return this->service.cancel(this->implementation, ec); + } + + /// Start an asynchronous operation to wait for a signal to be delivered. + /** + * This function may be used to initiate an asynchronous wait against the + * signal set. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li One of the registered signals in the signal set occurs; or + * + * @li The signal set was cancelled, in which case the handler is passed the + * error code asio::error::operation_aborted. + * + * @param handler The handler to be called when the signal occurs. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * int signal_number // Indicates which signal occurred. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(SignalHandler, + void (asio::error_code, int)) + async_wait(ASIO_MOVE_ARG(SignalHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a SignalHandler. + ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; + + return this->service.async_wait(this->implementation, + ASIO_MOVE_CAST(SignalHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SIGNAL_SET_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket.hpp new file mode 100644 index 0000000..21c6545 --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket.hpp @@ -0,0 +1,1518 @@ +// +// basic_socket.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_SOCKET_HPP +#define ASIO_BASIC_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/async_result.hpp" +#include "asio/basic_io_object.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/socket_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides socket functionality. +/** + * The basic_socket class template provides functionality that is common to both + * stream-oriented and datagram-oriented sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_socket + : public basic_io_object, + public socket_base +{ +public: + /// (Deprecated: Use native_handle_type.) The native representation of a + /// socket. + typedef typename SocketService::native_handle_type native_type; + + /// The native representation of a socket. + typedef typename SocketService::native_handle_type native_handle_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// A basic_socket is always the lowest layer. + typedef basic_socket lowest_layer_type; + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_socket(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket(asio::io_service& io_service, + const protocol_type& protocol) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket(asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_io_object(io_service) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + this->get_service().open(this->get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + this->get_service().bind(this->get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket(asio::io_service& io_service, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().assign(this->get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket from another. + /** + * This constructor moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(io_service&) constructor. + */ + basic_socket(basic_socket&& other) + : basic_io_object( + ASIO_MOVE_CAST(basic_socket)(other)) + { + } + + /// Move-assign a basic_socket from another. + /** + * This assignment operator moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(io_service&) constructor. + */ + basic_socket& operator=(basic_socket&& other) + { + basic_io_object::operator=( + ASIO_MOVE_CAST(basic_socket)(other)); + return *this; + } + + // All sockets have access to each other's implementations. + template + friend class basic_socket; + + /// Move-construct a basic_socket from a socket of another protocol type. + /** + * This constructor moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(io_service&) constructor. + */ + template + basic_socket(basic_socket&& other, + typename enable_if::value>::type* = 0) + : basic_io_object(other.get_io_service()) + { + this->get_service().template converting_move_construct( + this->get_implementation(), other.get_implementation()); + } + + /// Move-assign a basic_socket from a socket of another protocol type. + /** + * This assignment operator moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(io_service&) constructor. + */ + template + typename enable_if::value, + basic_socket>::type& operator=( + basic_socket&& other) + { + basic_socket tmp(ASIO_MOVE_CAST2(basic_socket< + Protocol1, SocketService1>)(other)); + basic_io_object::operator=( + ASIO_MOVE_CAST(basic_socket)(tmp)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * socket.open(asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * asio::error_code ec; + * socket.open(asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code open(const protocol_type& protocol, + asio::error_code& ec) + { + return this->get_service().open(this->get_implementation(), protocol, ec); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, + const native_handle_type& native_socket) + { + asio::error_code ec; + this->get_service().assign(this->get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code assign(const protocol_type& protocol, + const native_handle_type& native_socket, asio::error_code& ec) + { + return this->get_service().assign(this->get_implementation(), + protocol, native_socket, ec); + } + + /// Determine whether the socket is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect operations will be cancelled immediately, and will complete + * with the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + void close() + { + asio::error_code ec; + this->get_service().close(this->get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect operations will be cancelled immediately, and will complete + * with the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::error_code ec; + * socket.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + asio::error_code close(asio::error_code& ec) + { + return this->get_service().close(this->get_implementation(), ec); + } + + /// (Deprecated: Use native_handle().) Get the native socket representation. + /** + * This function may be used to obtain the underlying representation of the + * socket. This is intended to allow access to native socket functionality + * that is not otherwise provided. + */ + native_type native() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Get the native socket representation. + /** + * This function may be used to obtain the underlying representation of the + * socket. This is intended to allow access to native socket functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + * + * @note Calls to cancel() will always fail with + * asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + void cancel() + { + asio::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls to cancel() will always fail with + * asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + asio::error_code cancel(asio::error_code& ec) + { + return this->get_service().cancel(this->get_implementation(), ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + * + * @throws asio::system_error Thrown on failure. + */ + bool at_mark() const + { + asio::error_code ec; + bool b = this->get_service().at_mark(this->get_implementation(), ec); + asio::detail::throw_error(ec, "at_mark"); + return b; + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + */ + bool at_mark(asio::error_code& ec) const + { + return this->get_service().at_mark(this->get_implementation(), ec); + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + * + * @throws asio::system_error Thrown on failure. + */ + std::size_t available() const + { + asio::error_code ec; + std::size_t s = this->get_service().available( + this->get_implementation(), ec); + asio::detail::throw_error(ec, "available"); + return s; + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + */ + std::size_t available(asio::error_code& ec) const + { + return this->get_service().available(this->get_implementation(), ec); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * socket.open(asio::ip::tcp::v4()); + * socket.bind(asio::ip::tcp::endpoint( + * asio::ip::tcp::v4(), 12345)); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + asio::error_code ec; + this->get_service().bind(this->get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * socket.open(asio::ip::tcp::v4()); + * asio::error_code ec; + * socket.bind(asio::ip::tcp::endpoint( + * asio::ip::tcp::v4(), 12345), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code bind(const endpoint_type& endpoint, + asio::error_code& ec) + { + return this->get_service().bind(this->get_implementation(), endpoint, ec); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * asio::ip::tcp::endpoint endpoint( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.connect(endpoint); + * @endcode + */ + void connect(const endpoint_type& peer_endpoint) + { + asio::error_code ec; + if (!is_open()) + { + this->get_service().open(this->get_implementation(), + peer_endpoint.protocol(), ec); + asio::detail::throw_error(ec, "connect"); + } + this->get_service().connect(this->get_implementation(), peer_endpoint, ec); + asio::detail::throw_error(ec, "connect"); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * asio::ip::tcp::endpoint endpoint( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * asio::error_code ec; + * socket.connect(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code connect(const endpoint_type& peer_endpoint, + asio::error_code& ec) + { + if (!is_open()) + { + if (this->get_service().open(this->get_implementation(), + peer_endpoint.protocol(), ec)) + { + return ec; + } + } + + return this->get_service().connect( + this->get_implementation(), peer_endpoint, ec); + } + + /// Start an asynchronous connect. + /** + * This function is used to asynchronously connect a socket to the specified + * remote endpoint. The function call always returns immediately. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. Copies will be made of the endpoint object as required. + * + * @param handler The handler to be called when the connection operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * @code + * void connect_handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Connect succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::socket socket(io_service); + * asio::ip::tcp::endpoint endpoint( + * asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_connect(endpoint, connect_handler); + * @endcode + */ + template + ASIO_INITFN_RESULT_TYPE(ConnectHandler, + void (asio::error_code)) + async_connect(const endpoint_type& peer_endpoint, + ASIO_MOVE_ARG(ConnectHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ConnectHandler. + ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; + + if (!is_open()) + { + asio::error_code ec; + const protocol_type protocol = peer_endpoint.protocol(); + if (this->get_service().open(this->get_implementation(), protocol, ec)) + { + detail::async_result_init< + ConnectHandler, void (asio::error_code)> init( + ASIO_MOVE_CAST(ConnectHandler)(handler)); + + this->get_io_service().post( + asio::detail::bind_handler( + ASIO_MOVE_CAST(ASIO_HANDLER_TYPE( + ConnectHandler, void (asio::error_code)))( + init.handler), ec)); + + return init.result.get(); + } + } + + return this->get_service().async_connect(this->get_implementation(), + peer_endpoint, ASIO_MOVE_CAST(ConnectHandler)(handler)); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::no_delay option(true); + * socket.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + asio::error_code ec; + this->get_service().set_option(this->get_implementation(), option, ec); + asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::no_delay option(true); + * asio::error_code ec; + * socket.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + asio::error_code set_option(const SettableSocketOption& option, + asio::error_code& ec) + { + return this->get_service().set_option( + this->get_implementation(), option, ec); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::socket::keep_alive option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) const + { + asio::error_code ec; + this->get_service().get_option(this->get_implementation(), option, ec); + asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * asio::socket_base::broadcast @n + * asio::socket_base::do_not_route @n + * asio::socket_base::keep_alive @n + * asio::socket_base::linger @n + * asio::socket_base::receive_buffer_size @n + * asio::socket_base::receive_low_watermark @n + * asio::socket_base::reuse_address @n + * asio::socket_base::send_buffer_size @n + * asio::socket_base::send_low_watermark @n + * asio::ip::multicast::join_group @n + * asio::ip::multicast::leave_group @n + * asio::ip::multicast::enable_loopback @n + * asio::ip::multicast::outbound_interface @n + * asio::ip::multicast::hops @n + * asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::socket::keep_alive option; + * asio::error_code ec; + * socket.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.value(); + * @endcode + */ + template + asio::error_code get_option(GettableSocketOption& option, + asio::error_code& ec) const + { + return this->get_service().get_option( + this->get_implementation(), option, ec); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * asio::socket_base::bytes_readable @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::socket::bytes_readable command; + * socket.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + asio::error_code ec; + this->get_service().io_control(this->get_implementation(), command, ec); + asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * asio::socket_base::bytes_readable @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::socket::bytes_readable command; + * asio::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + asio::error_code io_control(IoControlCommand& command, + asio::error_code& ec) + { + return this->get_service().io_control( + this->get_implementation(), command, ec); + } + + /// Gets the non-blocking mode of the socket. + /** + * @returns @c true if the socket's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + bool non_blocking() const + { + return this->get_service().non_blocking(this->get_implementation()); + } + + /// Sets the non-blocking mode of the socket. + /** + * @param mode If @c true, the socket's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @throws asio::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + void non_blocking(bool mode) + { + asio::error_code ec; + this->get_service().non_blocking(this->get_implementation(), mode, ec); + asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the socket. + /** + * @param mode If @c true, the socket's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + asio::error_code non_blocking( + bool mode, asio::error_code& ec) + { + return this->get_service().non_blocking( + this->get_implementation(), mode, ec); + } + + /// Gets the non-blocking mode of the native socket implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native socket. This mode has no effect on the behaviour of the socket + * object's synchronous operations. + * + * @returns @c true if the underlying socket is in non-blocking mode and + * direct system calls may fail with asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the socket object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native socket. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(asio::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = asio::error_code(n < 0 ? errno : 0, + * asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == asio::error::would_block + * || ec == asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_write_some(asio::null_buffers(), *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_write_some(asio::null_buffers(), op); + * } @endcode + */ + bool native_non_blocking() const + { + return this->get_service().native_non_blocking(this->get_implementation()); + } + + /// Sets the non-blocking mode of the native socket implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native socket. It has no effect on the behaviour of the socket object's + * synchronous operations. + * + * @param mode If @c true, the underlying socket is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @throws asio::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(asio::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = asio::error_code(n < 0 ? errno : 0, + * asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == asio::error::would_block + * || ec == asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_write_some(asio::null_buffers(), *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_write_some(asio::null_buffers(), op); + * } @endcode + */ + void native_non_blocking(bool mode) + { + asio::error_code ec; + this->get_service().native_non_blocking( + this->get_implementation(), mode, ec); + asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native socket implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native socket. It has no effect on the behaviour of the socket object's + * synchronous operations. + * + * @param mode If @c true, the underlying socket is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(asio::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = asio::error_code(n < 0 ? errno : 0, + * asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == asio::error::would_block + * || ec == asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_write_some(asio::null_buffers(), *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_write_some(asio::null_buffers(), op); + * } @endcode + */ + asio::error_code native_non_blocking( + bool mode, asio::error_code& ec) + { + return this->get_service().native_non_blocking( + this->get_implementation(), mode, ec); + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @returns An object that represents the local endpoint of the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + asio::error_code ec; + endpoint_type ep = this->get_service().local_endpoint( + this->get_implementation(), ec); + asio::detail::throw_error(ec, "local_endpoint"); + return ep; + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(asio::error_code& ec) const + { + return this->get_service().local_endpoint(this->get_implementation(), ec); + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @returns An object that represents the remote endpoint of the socket. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); + * @endcode + */ + endpoint_type remote_endpoint() const + { + asio::error_code ec; + endpoint_type ep = this->get_service().remote_endpoint( + this->get_implementation(), ec); + asio::detail::throw_error(ec, "remote_endpoint"); + return ep; + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the remote endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type remote_endpoint(asio::error_code& ec) const + { + return this->get_service().remote_endpoint(this->get_implementation(), ec); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * socket.shutdown(asio::ip::tcp::socket::shutdown_send); + * @endcode + */ + void shutdown(shutdown_type what) + { + asio::error_code ec; + this->get_service().shutdown(this->get_implementation(), what, ec); + asio::detail::throw_error(ec, "shutdown"); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::error_code ec; + * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code shutdown(shutdown_type what, + asio::error_code& ec) + { + return this->get_service().shutdown(this->get_implementation(), what, ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + ~basic_socket() + { + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SOCKET_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_acceptor.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_acceptor.hpp new file mode 100644 index 0000000..6c7238c --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_acceptor.hpp @@ -0,0 +1,1136 @@ +// +// basic_socket_acceptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_SOCKET_ACCEPTOR_HPP +#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/basic_io_object.hpp" +#include "asio/basic_socket.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/error.hpp" +#include "asio/socket_acceptor_service.hpp" +#include "asio/socket_base.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +/// Provides the ability to accept new connections. +/** + * The basic_socket_acceptor class template is used for accepting new socket + * connections. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Opening a socket acceptor with the SO_REUSEADDR option enabled: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port); + * acceptor.open(endpoint.protocol()); + * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ +template > +class basic_socket_acceptor + : public basic_io_object, + public socket_base +{ +public: + /// (Deprecated: Use native_handle_type.) The native representation of an + /// acceptor. + typedef typename SocketAcceptorService::native_handle_type native_type; + + /// The native representation of an acceptor. + typedef typename SocketAcceptorService::native_handle_type native_handle_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + */ + explicit basic_socket_acceptor(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket_acceptor(asio::io_service& io_service, + const protocol_type& protocol) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws asio::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor acceptor(io_service); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(listen_backlog); + * @endcode + */ + basic_socket_acceptor(asio::io_service& io_service, + const endpoint_type& endpoint, bool reuse_addr = true) + : basic_io_object(io_service) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + this->get_service().open(this->get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + if (reuse_addr) + { + this->get_service().set_option(this->get_implementation(), + socket_base::reuse_address(true), ec); + asio::detail::throw_error(ec, "set_option"); + } + this->get_service().bind(this->get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + this->get_service().listen(this->get_implementation(), + socket_base::max_connections, ec); + asio::detail::throw_error(ec, "listen"); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws asio::system_error Thrown on failure. + */ + basic_socket_acceptor(asio::io_service& io_service, + const protocol_type& protocol, const native_handle_type& native_acceptor) + : basic_io_object(io_service) + { + asio::error_code ec; + this->get_service().assign(this->get_implementation(), + protocol, native_acceptor, ec); + asio::detail::throw_error(ec, "assign"); + } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket_acceptor from another. + /** + * This constructor moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(io_service&) constructor. + */ + basic_socket_acceptor(basic_socket_acceptor&& other) + : basic_io_object( + ASIO_MOVE_CAST(basic_socket_acceptor)(other)) + { + } + + /// Move-assign a basic_socket_acceptor from another. + /** + * This assignment operator moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(io_service&) constructor. + */ + basic_socket_acceptor& operator=(basic_socket_acceptor&& other) + { + basic_io_object::operator=( + ASIO_MOVE_CAST(basic_socket_acceptor)(other)); + return *this; + } + + // All socket acceptors have access to each other's implementations. + template + friend class basic_socket_acceptor; + + /// Move-construct a basic_socket_acceptor from an acceptor of another + /// protocol type. + /** + * This constructor moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(io_service&) constructor. + */ + template + basic_socket_acceptor( + basic_socket_acceptor&& other, + typename enable_if::value>::type* = 0) + : basic_io_object(other.get_io_service()) + { + this->get_service().template converting_move_construct( + this->get_implementation(), other.get_implementation()); + } + + /// Move-assign a basic_socket_acceptor from an acceptor of another protocol + /// type. + /** + * This assignment operator moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(io_service&) constructor. + */ + template + typename enable_if::value, + basic_socket_acceptor>::type& operator=( + basic_socket_acceptor&& other) + { + basic_socket_acceptor tmp(ASIO_MOVE_CAST2(basic_socket_acceptor< + Protocol1, SocketAcceptorService1>)(other)); + basic_io_object::operator=( + ASIO_MOVE_CAST(basic_socket_acceptor)(tmp)); + return *this; + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * acceptor.open(asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + asio::error_code ec; + this->get_service().open(this->get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * asio::error_code ec; + * acceptor.open(asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code open(const protocol_type& protocol, + asio::error_code& ec) + { + return this->get_service().open(this->get_implementation(), protocol, ec); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws asio::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, + const native_handle_type& native_acceptor) + { + asio::error_code ec; + this->get_service().assign(this->get_implementation(), + protocol, native_acceptor, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code assign(const protocol_type& protocol, + const native_handle_type& native_acceptor, asio::error_code& ec) + { + return this->get_service().assign(this->get_implementation(), + protocol, native_acceptor, ec); + } + + /// Determine whether the acceptor is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345); + * acceptor.open(endpoint.protocol()); + * acceptor.bind(endpoint); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + asio::error_code ec; + this->get_service().bind(this->get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345); + * acceptor.open(endpoint.protocol()); + * asio::error_code ec; + * acceptor.bind(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code bind(const endpoint_type& endpoint, + asio::error_code& ec) + { + return this->get_service().bind(this->get_implementation(), endpoint, ec); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @throws asio::system_error Thrown on failure. + */ + void listen(int backlog = socket_base::max_connections) + { + asio::error_code ec; + this->get_service().listen(this->get_implementation(), backlog, ec); + asio::detail::throw_error(ec, "listen"); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::error_code ec; + * acceptor.listen(asio::socket_base::max_connections, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code listen(int backlog, asio::error_code& ec) + { + return this->get_service().listen(this->get_implementation(), backlog, ec); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + this->get_service().close(this->get_implementation(), ec); + asio::detail::throw_error(ec, "close"); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::error_code ec; + * acceptor.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + asio::error_code close(asio::error_code& ec) + { + return this->get_service().close(this->get_implementation(), ec); + } + + /// (Deprecated: Use native_handle().) Get the native acceptor representation. + /** + * This function may be used to obtain the underlying representation of the + * acceptor. This is intended to allow access to native acceptor functionality + * that is not otherwise provided. + */ + native_type native() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Get the native acceptor representation. + /** + * This function may be used to obtain the underlying representation of the + * acceptor. This is intended to allow access to native acceptor functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code cancel(asio::error_code& ec) + { + return this->get_service().cancel(this->get_implementation(), ec); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * asio::socket_base::reuse_address + * asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::acceptor::reuse_address option(true); + * acceptor.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + asio::error_code ec; + this->get_service().set_option(this->get_implementation(), option, ec); + asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * asio::socket_base::reuse_address + * asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::acceptor::reuse_address option(true); + * asio::error_code ec; + * acceptor.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + asio::error_code set_option(const SettableSocketOption& option, + asio::error_code& ec) + { + return this->get_service().set_option( + this->get_implementation(), option, ec); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::acceptor::reuse_address option; + * acceptor.get_option(option); + * bool is_set = option.get(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) + { + asio::error_code ec; + this->get_service().get_option(this->get_implementation(), option, ec); + asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::acceptor::reuse_address option; + * asio::error_code ec; + * acceptor.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.get(); + * @endcode + */ + template + asio::error_code get_option(GettableSocketOption& option, + asio::error_code& ec) + { + return this->get_service().get_option( + this->get_implementation(), option, ec); + } + + /// Perform an IO control command on the acceptor. + /** + * This function is used to execute an IO control command on the acceptor. + * + * @param command The IO control command to be performed on the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::acceptor::non_blocking_io command(true); + * socket.io_control(command); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + asio::error_code ec; + this->get_service().io_control(this->get_implementation(), command, ec); + asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the acceptor. + /** + * This function is used to execute an IO control command on the acceptor. + * + * @param command The IO control command to be performed on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::acceptor::non_blocking_io command(true); + * asio::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + asio::error_code io_control(IoControlCommand& command, + asio::error_code& ec) + { + return this->get_service().io_control( + this->get_implementation(), command, ec); + } + + /// Gets the non-blocking mode of the acceptor. + /** + * @returns @c true if the acceptor's synchronous operations will fail with + * asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + bool non_blocking() const + { + return this->get_service().non_blocking(this->get_implementation()); + } + + /// Sets the non-blocking mode of the acceptor. + /** + * @param mode If @c true, the acceptor's synchronous operations will fail + * with asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @throws asio::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + void non_blocking(bool mode) + { + asio::error_code ec; + this->get_service().non_blocking(this->get_implementation(), mode, ec); + asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the acceptor. + /** + * @param mode If @c true, the acceptor's synchronous operations will fail + * with asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * asio::error::would_block. + */ + asio::error_code non_blocking( + bool mode, asio::error_code& ec) + { + return this->get_service().non_blocking( + this->get_implementation(), mode, ec); + } + + /// Gets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native acceptor. This mode has no effect on the behaviour of the acceptor + * object's synchronous operations. + * + * @returns @c true if the underlying acceptor is in non-blocking mode and + * direct system calls may fail with asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the acceptor object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native acceptor. + */ + bool native_non_blocking() const + { + return this->get_service().native_non_blocking(this->get_implementation()); + } + + /// Sets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native acceptor. It has no effect on the behaviour of the acceptor object's + * synchronous operations. + * + * @param mode If @c true, the underlying acceptor is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @throws asio::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + */ + void native_non_blocking(bool mode) + { + asio::error_code ec; + this->get_service().native_non_blocking( + this->get_implementation(), mode, ec); + asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native acceptor. It has no effect on the behaviour of the acceptor object's + * synchronous operations. + * + * @param mode If @c true, the underlying acceptor is put into non-blocking + * mode and direct system calls may fail with asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with asio::error::invalid_argument, as the + * combination does not make sense. + */ + asio::error_code native_non_blocking( + bool mode, asio::error_code& ec) + { + return this->get_service().native_non_blocking( + this->get_implementation(), mode, ec); + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @returns An object that represents the local endpoint of the acceptor. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + asio::error_code ec; + endpoint_type ep = this->get_service().local_endpoint( + this->get_implementation(), ec); + asio::detail::throw_error(ec, "local_endpoint"); + return ep; + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the acceptor. + * Returns a default-constructed endpoint object if an error occurred and the + * error handler did not throw an exception. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(asio::error_code& ec) const + { + return this->get_service().local_endpoint(this->get_implementation(), ec); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(io_service); + * acceptor.accept(socket); + * @endcode + */ + template + void accept(basic_socket& peer, + typename enable_if::value>::type* = 0) + { + asio::error_code ec; + this->get_service().accept(this->get_implementation(), + peer, static_cast(0), ec); + asio::detail::throw_error(ec, "accept"); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::soocket socket(io_service); + * asio::error_code ec; + * acceptor.accept(socket, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + asio::error_code accept( + basic_socket& peer, + asio::error_code& ec, + typename enable_if::value>::type* = 0) + { + return this->get_service().accept(this->get_implementation(), + peer, static_cast(0), ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket. The function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(io_service); + * acceptor.async_accept(socket, accept_handler); + * @endcode + */ + template + ASIO_INITFN_RESULT_TYPE(AcceptHandler, + void (asio::error_code)) + async_accept(basic_socket& peer, + ASIO_MOVE_ARG(AcceptHandler) handler, + typename enable_if::value>::type* = 0) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a AcceptHandler. + ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; + + return this->get_service().async_accept(this->get_implementation(), + peer, static_cast(0), + ASIO_MOVE_CAST(AcceptHandler)(handler)); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(io_service); + * asio::ip::tcp::endpoint endpoint; + * acceptor.accept(socket, endpoint); + * @endcode + */ + template + void accept(basic_socket& peer, + endpoint_type& peer_endpoint) + { + asio::error_code ec; + this->get_service().accept(this->get_implementation(), + peer, &peer_endpoint, ec); + asio::detail::throw_error(ec, "accept"); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(io_service); + * asio::ip::tcp::endpoint endpoint; + * asio::error_code ec; + * acceptor.accept(socket, endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + asio::error_code accept( + basic_socket& peer, + endpoint_type& peer_endpoint, asio::error_code& ec) + { + return this->get_service().accept( + this->get_implementation(), peer, &peer_endpoint, ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket, and additionally obtain the endpoint of the remote peer. The + * function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + */ + template + ASIO_INITFN_RESULT_TYPE(AcceptHandler, + void (asio::error_code)) + async_accept(basic_socket& peer, + endpoint_type& peer_endpoint, ASIO_MOVE_ARG(AcceptHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a AcceptHandler. + ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; + + return this->get_service().async_accept(this->get_implementation(), peer, + &peer_endpoint, ASIO_MOVE_CAST(AcceptHandler)(handler)); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP diff --git a/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_iostream.hpp b/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_iostream.hpp new file mode 100644 index 0000000..671770f --- /dev/null +++ b/utils/dnp3_src/deps/asio/asio/include/asio/basic_socket_iostream.hpp @@ -0,0 +1,286 @@ +// +// basic_socket_iostream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_BASIC_SOCKET_IOSTREAM_HPP +#define ASIO_BASIC_SOCKET_IOSTREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if !defined(ASIO_NO_IOSTREAM) + +#include +#include +#include "asio/basic_socket_streambuf.hpp" +#include "asio/stream_socket_service.hpp" + +#if !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +# include "asio/detail/variadic_templates.hpp" + +// A macro that should expand to: +// template +// explicit basic_socket_iostream(T1 x1, ..., Tn xn) +// : std::basic_iostream( +// &this->detail::socket_iostream_base< +// Protocol, StreamSocketService, Time, +// TimeTraits, TimerService>::streambuf_) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +# define ASIO_PRIVATE_CTR_DEF(n) \ + template \ + explicit basic_socket_iostream(ASIO_VARIADIC_PARAMS(n)) \ + : std::basic_iostream( \ + &this->detail::socket_iostream_base< \ + Protocol, StreamSocketService, Time, \ + TimeTraits, TimerService>::streambuf_) \ + { \ + this->setf(std::ios_base::unitbuf); \ + if (rdbuf()->connect(ASIO_VARIADIC_ARGS(n)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +// A macro that should expand to: +// template +// void connect(T1 x1, ..., Tn xn) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +# define ASIO_PRIVATE_CONNECT_DEF(n) \ + template \ + void connect(ASIO_VARIADIC_PARAMS(n)) \ + { \ + if (rdbuf()->connect(ASIO_VARIADIC_ARGS(n)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// A separate base class is used to ensure that the streambuf is initialised +// prior to the basic_socket_iostream's basic_iostream base class. +template +class socket_iostream_base +{ +protected: + basic_socket_streambuf streambuf_; +}; + +} + +/// Iostream interface for a socket. +template , +#if defined(ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + typename Time = boost::posix_time::ptime, + typename TimeTraits = asio::time_traits

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 z zeOj8Ia7N+sm-n3oh35(i)Zig}@(tM0V~mc2g_cD+ymr+S7X~kYMi&*v7#zMNDz4dc z?O6HcijsL758bRoO&=_W8&ER&X9J7x&COeNomLiBocB@o-iJ(nvS4nCeh_z1qI3Vr zN|?XWZA4W*_ZaN~RrTIk6GWs=P9;&$U4k2E0XOW+UFdjodsmvv`U3+x^n3rhMDn@B zlU@V6eh2lEEFD||zVB7Gy@PKp3pyG)CL>(dQHN%qUVS; zhGKFmTD4 zx)V-57e&smJ5hHem<`Rh#UD{Wep|hT8Eog1PMV$@l`wKFqp^>XMZA>chheQ*x=Jlc z-CdVNtk?Cs{F5}&u!4#Q>q zcLdt1(yYujdM~@TcdhzR`I5EjOD#?P+*YycmOkWkKa< zYqONY{5gJ~lX*95S8UHrRL#6ls-*XLt9A5^vIXUjc^9v+Oi!h5+hZVP8{wZ0O zX%^tXWhElb@;&EGns`xUf%3*p(yR(|)9y*!33Uj_`tWW~&Ottbqic=2g?S`gQuZY7 zc)TdhIsSfpF+;leqSE`-cjT@#y>*P6yz=Jeiw94AaGO~bc`|37+lt1|Ul?aUyUWn; zsQT~Ee-7Zhd?hQVI1>vmaJ@q+KO3`<=rkaUQ9zhG-{j%c)JU!pv6uhvZx6mu{hQr~ zG2O0HRc7&m9>WJ`6g%YGxf$8cvfoYmje=g$#<{kl<$1h} zc5eK?zdbULcF^->_>gCJYugf*GyMMl%(x{EWVwjz&uismn55z<#K6E1@*hZmK*BzT z3$6^k`xqR4{SR+G`~S7T1Tg4gbL(JtXS`j?-YwVs?vLQ@qPII3f$EV&1P?IYF6J(k zgeeg4K#_cX#qebF3+5uhgAX`>rZs=~Us7@LN9WPk+{nsKqHszT98vf{3*MJGzlZ!0F@(-Av7gSUTC8kFzwtWGVm1 zc>bjYP&lsh`%Yg428J$ncbykDjOE`O>^Vz6b+dQHv!oq-!Ex|_K-&?`9}TZxFn$2( zW$nE2=q4~s8aNrc**OoCxOT_0^tKo9-x==lX{uVT`e?a~oG%=WcTpKwVB!E~0h(W*%N_#-*04N;> zrHdID8bIp2U4#5weSo*+x%l`nIJ$&626zHFDLFX|?k+HvZ*Z7%PzYEsG}tu=Djy!~ z@9Yg_Gcfq%C#LvhCKV+XRXQ>-xTlr`6y+y7rlb_576Ywvt;hrmfH@37sp)~GsYR7x miNIqsfK?6ygHvXSQ%(s3Lt0U4Dg#4!W}ZiCP61GSa039z-Au0l literal 0 HcmV?d00001 diff --git a/utils/dnp3_src/CHANGELOG.markdown b/utils/dnp3_src/CHANGELOG.markdown new file mode 100644 index 0000000..38c37e3 --- /dev/null +++ b/utils/dnp3_src/CHANGELOG.markdown @@ -0,0 +1,209 @@ +### 2.2.0 ### +* No changes from 2.2.0-RC5 + +### 2.2.0-RC5 ### +* :beetle: Fixed a [bug](https://github.com/automatak/dnp3/issues/200) where connection attempts were not retrieved after failed DNS resolution. + +### 2.2.0-RC4 ### +* :beetle: Fixed a [regression](https://github.com/automatak/dnp3/issues/197) in outstation whereby the session could hang indefinitely if a non-read request was received during UnsolConirmWait. + +### 2.2.0-RC3 ### +* :beetle: Fixed a [regression](https://github.com/automatak/dnp3/issues/195) whereby multi segment messages could be transmitted with trailing garbage. +* :beetle: Fixed a bug whereby improper TLS shutdown from the remote host could result in an infinite loop. TLS shutdown is no longer utilized in favor of just a hard TCP close. + +### 2.2.0-RC2 ### +* :beetle: Java bindings in 2.2.0-RC1 were leaking local references. Modified the bindings to use resource management class to ensure this doens't happen going forward. +* :beetle: Fixed a [bug](https://github.com/automatak/dnp3/issues/187) in outstation/master enable/disable that put the session into an invalid state. + +### 2.2.0-RC1 ### +* :star: Java bindings have been added to the project. +* :star: New API for creating "masters as servers" (aka GPRS-based systems) +* :wrench: DNP3Manager now returns shared_ptr. IChannel now returns shared_ptr. Shutdown is now idempotent on +these interfaces used via shared_ptr. +* :wrench: Channel, master, and outstation now accept all callback interfaces via shared_ptr. +* :wrench: The external format for statistics has been changed to ease maintainence. Each class now owns the statistics it increments. +* :beetle: Fixed a [bug](https://github.com/automatak/dnp3/issues/175) where the keep-alive timer would rapidly fire in C# if set to Timespan.MaxValue. +* :beetle: Fixed a [bug](https://github.com/automatak/dnp3/issues/164) in the outstation state machine where it would incorrectly ignore repeat READ requests. +* :beetle: Fixed a bug in the ASDU formatting where a request for a range of 255 measurement values would result in a malformed response. +* :beetle: Fixed a [bug](https://github.com/automatak/dnp3/issues/173) in the TLS client that caused the channel to be unrecoverable after any disconnect. + +### 2.1.0 ### +* Minor formatting and documentation tweaks + +### 2.1.0-RC6 ### +* :wrench: The C# LinkConfig class now uses Timespan for timeouts for consistency with other API elements. This also solved +an issue where the LinkTimeout could not be effectively disabled since MaxInt wasn't big enough to ensure it never ran. +* :wrench: Moved experimental SA components to the "secauth" branch. +* :wrench: ILogHandler is now injected as an argument to the DNP3Manager constructor as a shared_ptr. +* :star: Master and outstation interfaces can now control their log level independently of the channel they're created on. +* :beetle: Fixed a bug in the C# bindings where the ILogHandler was prematurely freed by the GC. +* Refactored cmake build files into several sub-files for better modularity. + +### 2.1.0-RC5 ### +* :beetle: Fixed a bug in the master multi-drop functionality where removing an active master, caused remaining session to freeze. +* :beetle: Fixed a bug in ClearRestartTask where the completion callback was invoked with the wrong task type. +* :star: HeaderInfo class in ISOEHandler now exposes isEvent member which tells user if header is for an event type. Added this to C# as well. +* :star: C++ outstation demos now load the current timestamp using overloaded MeasUpdate constructor + +### 2.1.0-RC4 ### +* :star: Tagged released now automatically deployed to Nuget via AppVeyor build +* :star: Code generator now produces lookup functions for group variation time/tag information. +* :star: Added a decoder feature used to power the website decoder. + +### 2.1.0-RC3 ### +* :beetle: Fixed a bug in the C# bindings where non-zero based indices were not being detected properly. + +### 2.1.0-RC2 ### +* :beetle: Fixed a bug that was causing the keep-alive to not retry at the configured rate + +### 2.1.0-RC1 ### +* Migrated fully to CMake, including generated SLN +* Separated include vs private headers +* New guide + doxygen docs +* Add an ILinkListener interface inherited by IMasterApplication/IOutstationApplication that allows you to monitor link-layer activity. +* Master can now send any combination and # of commands in a single request +* Support for TLS client/server (optional in build) +* Modified the IMaster interface to inherit from ICommandProcessor which now contains only two methods. +* Master now uses Task[T] everywhere instead of custom Future[T]. Eases uses with TPL and async/await. +* Master now has a parameter to timeout tasks that fail to start within a certain TimeDuration. +* Implemented the RequestLinkStates/LinkStatus heartbeat functionality in 1815. +* :beetle: Fixed a bug in the way CTO objects were handled w/ Group2Var3 and Group4Var3 +* C# bindings now use .NET Task[T] instead of custom Future[T] +* Introduced an experimental version of SAv5 (not intended for production use) + * Significantly refactored the master/outstation internals to accommodate adding SA via inheritance. + * Added parser/formatter generators for variable-length objects in Group120 + + +### 2.0.1 ### +No changes to 2.0.1-RC3 for final 2.0.1 release + +### 2.0.1-RC3 ### +* Workaround for broken std::chrono::steady_clock impl thanks to Liam MacIsaac. +* Based on user feedback, the .NET outstation API now uses a more intuitive "ChangeSet" to update values in the outstation. +* The .NET "simulator" has been restored with more features surfaced and outstation plugins can now be written to simulate devices. + +### 2.0.1-RC2 ### +* DNPManager.AddTCPClient now takes an additional parameter for the local adapter address (0.0.0.0 == all adapters) +* Overloaded CROB constructor allows for non-standard control codes to be specified. +* Fixed a thread-safety issue in the outstation on data update. The API has shifted for updating the outstation database to accomodate this fix. +* Fixed an uninitialized control code variable in the CROB introduced in 2.0.1-RC1. + +### 2.0.1-RC1 ### +* Added support for Group50Var4 (Time and Interval) objects. These are static only objects (no events) that can are read/write. +* Added support for Binary/Analog command events to the parser and the master API courtesy of Sid Hoda. +* Added support for the ASSIGN_CLASS function code. + * Assignment to the outstation db is automatic, but there is a callback on IOutstationApplication for any desired user action + * The master can assign class automatically during the startup handshaking based on callbacks in IMasterApplication +* Substantially refactored/simplified the master scheduler to make extension easier. + * Most tasks that are explicitly rejected via IIN bits (e.g. enable/disable unsol) no longer retry on failure +* Added support for discontigous outstation databases based on an earlier contriubtion from Alan Murray + * Virtual (dnp3) indices are now assigned after creation of the outstation, but before enabling it + * Note: Discontigous mode must be set in the OutstationConfig in C++, automatically detected in C# + * Discontiguous mode is slightly less performant on range-based READ's because of O(log(n)) binary search +* Static and event response types can now be configured on a per-point basis + * In C++ this occurs after creating the outstation instance, but before enabling it. + * In C#, all values are specified in the DatabaseTemplate +* Fixed a minor conformance issue: Group1Var1 is now promoted to Group1Var2 if the quality != ONLINE +* The are now two methods for monitoring master tasks + * Callbacks on IMasterApplication for built-in tasks and ones that were created with a userId + * Optional per-task callback interfaces supplied when the task was created +* Arbitrary master scans (qualifiers 0x06, 0x00/0x01, 0x07/0x08) can now be created in C# using an API contributed by Damon Sutherland +* Added a flag to the outstation that limits the number of queued event checks to 1. This was done for determinism on embedded systems with limited space to queue executor actions. + + + +### 2.0.0 ### +* Fixed an issue in openpal::Synchronized where the stack would deadlock under heavy contention +* Fixed bug where counter 'numTransportErrorRx' was incremented twice +* The log alias in LogRoot is now dynamically sized removed the artificial limitation + + +### 2.0.0-RC3 ### +* Dynamic memory allocation now allowed in core library during initialization. + * Removed various redundant static container types in openpal + * Database and event buffers now create they underlying storage from configuration + * Hard limits that were in Configure.h are no longer necessary. +* C++/C# master API now receives callback whenever an IIN field is received to allow user layer processing. +* Fixed a bug where periodic taks with period < 0 would rapid-retry instead () +* Added an embedded demo for the sam3x8E ARM (arduino DUE) +* Parsers are no longer singletons, both groups of functions to reduce SRAM usage on embedded systems. +* ICommandHandler semantics switched back to Select/Operate to more closely match spec. Operate is indistinguisable from DirectOperate at user layer +* Include guards now prepend library name to avoid potential conflicts +* Master can now bind arbitrary 0x06 (all objects) periodic scans + + +### 2.0.0-RC2 ### + +Conformance fixes based on testing with 3rd party harness. Only remaining level 2 conformance item is handling broadcast addressing. + * Outstation now handles limited count (0x07, 0x08) request headers for class polls and specific variation polls. + * IOutstationApplication can now handle cold/warm restart function codes. + +Master measurement API (ISOEHandler) now informs application of qualifer, group variation, and validity of timestamps for each header received. + +### 2.0.0-RC1 ### + +## Refactoring / Improvements - General ## +* To enable ports to other platforms and MCUs, the 1.1.x library was divided into 4 sub-libraries. + * openpal - The Platform Abstraction Layer (PAL) provides abtract base classes for key abstractions like IPhysicalLayer, IExecutor, ITimer, etc. + * opendnp3 - The core dnp3 library. It only depends on openpal and is platform independent C++11. + * asiopal - Implements the PAL using boost::asio. This PAL can be used on server platforms like Windows, Linux, & OSX. It only depends on openpal. + * asiodnp3 - Provides a nice wrapper to opendnp3 for server platforms. Depends on all three libraries. + +* Library uses a new parser and generator that vastly improves readability, maintainability, performance, and safety. +* Example applications for Atmel Studio for Arduino boards have been added. They are not yet production ready, but a proof of concept. +* Stack depth has been reduced to better suite embedded systems. +* Core library is now organized by layer making navigation, maintainence, and learning the library easier. +* C++ libraries are now exception-free. They can be compiled with -fno-exceptions. +* IExecutor now uses an "Action0" which is a parameterless functor. Uses type-safe erasure/lambdas combined with static allocation. +* Core library now uses sprintf instead of iostreams. All usage of std::string removed to improve portability. +* Removed some instances of recursion in the link layer CRC checking. The library is now recursion-free. +* The library no longer uses BOOST. Instead it uses the standalone verison (header only) of [ASIO](http://think-async.com/) +* Tests were ported from BOOST_TEST to [Catch](https://github.com/philsquared/Catch). Catch is header only and redistributed with the project. +* Core library no longer uses STL. This makes ports to MCUs much easier. +* Core library no longer uses dynamic memory allocation. Databases and buffers are either statically allocated or injected allowing the user to choose. +* Library no longer uses size_t as this type changes length on 32/64-bit platforms. Explicit types are now used from . +* Application layer objects and most enums are now generated using a companion Scala project in the 'generation' folder. +* Buffer wrappers "WriteBuffer" and "ReadOnlyBuffer" are now passed around internally instead of pairs of uint8_t* and uint32_t. +* Upgraded solution file to VS2013 +* x86 and x64 outputs now build side-by-side +* LogEntry class no longer carries timestamp. This allows the timestamp to be set by the specific platform. +* Setpoint/Control terminology changed to AnalogOutput & BinaryOutput to correspond to the specification. +* Libraries no longer have separate src/include directories. This decision was premature. +* Clang is now an officially supported compiler and will also be used for static analysis. Project compiles with Clang 3.4. +* Logging is now explicitly controlled using the bitfields instead of enums. This allows dnp3 specific log levels to be defined without polluting openpal with their definitions. + +## External Features ## + +* Ticket 56 - Measurement types can now tell the user if the timestamp is valid or not (bool IsTimeValid() const) +* Ticket 43 - Master command callbacks now provide a type that can distinguish between local and remote failure, e.g. when the repsonse times out or the channel is closed. +* Ticket 47 - TCP client can now perform asynchronous DNS host resolution and try mutliple resolved addresses in a single "open" sequence. +* Ticket 56 - C++ channels can also specify a "strategy" for full control over the wait period for retry. +* Ticket 30 - Outstation API now provides control of the NeedTime IIN bit. +* Ticket 29 - Scans are now exposed as part of the master API. Callbacks can be registered to observe success and failure. Class scans may be defined dynamically and performed on demand. +* C++ TCP Client/Server can now configure native socket types with an optional functor. This allows platform-specific customization of things like TCP keep-alives. +* Master applications now specify "ISOEHandler" (Sequence of Events) instead of "IDataObserver". It allows users to discern between static and event types. +* Renamed outstation API "IDataObserver" to the more descriptive "IMeasurementLoader" +* Outstation now uses a simple interface "ITimeWriteHandler" to receive time write requests +* The start of a master or outstation is delayed until a Enable() method is called. Stacks may be dynamically paused/resumed at runtime with the Enable/Disable methods. +* Master now supports additional types: + * Frozen Counters, Double-bit Binaries, and Octet Strings +* Outstation now supports additional types: + * Frozen Counters, Double-bit Binaries, and AO/BO status events +* Java Future can now be called with an optional timeout +* Channels now have expoential backoff capability controlled by min/max retry parameters. +* Each channel can low control the its log level dynamically via the SetLogFilters() method. + +## Bug / conformance fixes ## +* Default integrity poll is now a Class 1/2/3/0 scan as per the specification. +* Outstation now reports events in correct order-of-occurence across all seven types it supports. +* Physical layer disconnects now observer the minRetry parameter. This prevents rapid connect/disconnect cycling when a server is closing connections. +* Transport layer can now receive non-fin packets with payload length between 1 and 249. It's very strange for an implementation to do this, but its actually in the spec. +* Count-of-zero headers are now explicitly disallowed and parsing is halted. +* Ticket 57 - When a READ is received while waiting for a confirm, any further retries should be canceled. (also fixed on 1.1.x) +* Ticket 62 - Fixed a bug where the master scheduler could hang if the the channel was closed while waiting for response to a command. + +## Removed ## +* VTO "routers" are now longer provided. 0-length strings of all types (Groups 110-113) are now explicitly not allowed. +* ASIOPAL now explicitly uses std::chrono::steady_clock for timers. There is no longer a typedef. +* Library no longer supports 4-octet qualifier codes. All indices used uint16_t as underlying type. +* Support for "delta" values has been removed. New implementations do not need to support this according to the spec. diff --git a/utils/dnp3_src/CMakeLists.txt b/utils/dnp3_src/CMakeLists.txt new file mode 100644 index 0000000..a94cc67 --- /dev/null +++ b/utils/dnp3_src/CMakeLists.txt @@ -0,0 +1,260 @@ +cmake_minimum_required (VERSION 2.8) + +project (opendnp3) +set(OPENDNP3_MAJOR_VERSION 2) +set(OPENDNP3_MINOR_VERSION 2) +set(OPENDNP3_MICRO_VERSION 1) +set(OPENDNP3_VERSION ${OPENDNP3_MAJOR_VERSION}.${OPENDNP3_MINOR_VERSION}.${OPENDNP3_MICRO_VERSION}) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING + "Choose the type of build, options are: Debug Release +RelWithDebInfo MinSizeRel." + FORCE) +endif() + +message("CMake build is: ${CMAKE_BUILD_TYPE}") + +include(${PROJECT_SOURCE_DIR}/cmake/settings.cmake) + +# various optional libraries and projects + +option(DNP3_ALL "Build all optional projects (secauth, demos, tests)" OFF) +option(DNP3_TEST "Build tests" OFF) +option(DNP3_DEMO "Build demo applications" OFF) +option(DNP3_DECODER "Build the decoder library" OFF) +option(DNP3_TLS "Build TLS client/server support" OFF) +option(DNP3_JAVA "Build the Java bindings" OFF) + +# other options off-by-default that you can enable +option(WERROR "Set all warnings to errors" OFF) +option(STATICLIBS "Builds static versions of all installed libraries" OFF) +option(COVERAGE "Builds the libraries with coverage info for gcov (gcc only)" OFF) +option(PROFILE "Builds the libraries with profiling support (gcc only)" OFF) + +if(DNP3_ALL) + message("enabling all optional components") + set(DNP3_DEMO ON) + set(DNP3_TEST ON) + set(DNP3_TLS ON) + set(DNP3_DECODER ON) + set(DNP3_JAVA ON) +endif() + +if(DNP3_JAVA) + find_package(Java COMPONENTS Development) + find_package(JNI REQUIRED) + include_directories(${JNI_INCLUDE_DIRS}) +endif() + +SET(ASIO_SUBMODULE_DIR "${PROJECT_SOURCE_DIR}/deps/asio/asio/include") + +# detection stuff for ASIO +if (EXISTS "${ASIO_SUBMODULE_DIR}/asio.hpp") + message("ASIO has been checked out as a git submodule: ${ASIO_SUBMODULE_DIR}") + include_directories(${ASIO_SUBMODULE_DIR}) +else() + message("ASIO has NOT been checked out as a git submodule...") + if (ASIO_HOME) + message("ASIO_HOME defined in cache: ${ASIO_HOME}") + include_directories(${ASIO_HOME}) + else() + if(DEFINED ENV{ASIO_HOME}) + message("ASIO_HOME defined in environment: $ENV{ASIO_HOME}") + include_directories($ENV{ASIO_HOME}) + else() + message("ASIO_HOME was not defined. ASIO expected to be on include path") + endif() + endif() +endif() + +# required for ASIO in C++11 only mode +add_definitions(-DASIO_STANDALONE) + +if(DNP3_TLS) + add_definitions(-DOPENDNP3_USE_TLS) + + find_package(OpenSSL REQUIRED) + message("OpenSSL libraries: ${OPENSSL_LIBRARIES}") + if(WIN32) + include_directories(${OPENSSL_INCLUDE_DIR}) + endif() +endif() + +set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS}) + +# include paths for all the local libraries +include_directories(./cpp/libs/src) +include_directories(./cpp/libs/include) +include_directories(./cpp/tests/libs/src) + +# ---- openpal library ---- +file(GLOB_RECURSE openpal_SRC ./cpp/libs/src/openpal/*.cpp ./cpp/libs/src/openpal/*.h ./cpp/libs/include/openpal/*.h) +add_library(openpal ${LIB_TYPE} ${openpal_SRC}) +install(TARGETS openpal DESTINATION lib) +set_target_properties(openpal PROPERTIES FOLDER libs) + +# ---- opendnp3 library ---- +file(GLOB_RECURSE opendnp3_SRC ./cpp/libs/src/opendnp3/*.cpp ./cpp/libs/src/opendnp3/*.h ./cpp/libs/include/opendnp3/*.h) +add_library(opendnp3 ${LIB_TYPE} ${opendnp3_SRC}) +target_link_libraries(opendnp3 openpal) +install(TARGETS opendnp3 DESTINATION lib) +set_target_properties(opendnp3 PROPERTIES FOLDER libs) + +if(DNP3_DECODER) + file(GLOB_RECURSE dnp3decode_SRC ./cpp/libs/src/dnp3decode/*.cpp ./cpp/libs/src/dnp3decode/*.h ./cpp/libs/include/dnp3decode/*.h) + add_library(dnp3decode ${LIB_TYPE} ${dnp3decode_SRC}) + target_link_libraries(dnp3decode opendnp3) + install(TARGETS dnp3decode DESTINATION lib) + set_target_properties(dnp3decode PROPERTIES FOLDER libs) +endif() + +# ---- asiopal library ---- +file(GLOB_RECURSE asiopal_HPP ./cpp/libs/src/asiopal/*.h ./cpp/libs/include/asiopal/*.h) + +if(DNP3_TLS) + file(GLOB_RECURSE asiopal_CPP ./cpp/libs/src/asiopal/*.cpp) +else() + file(GLOB asiopal_CPP ./cpp/libs/src/asiopal/*.cpp) +endif() + +add_library(asiopal ${LIB_TYPE} ${asiopal_HPP} ${asiopal_CPP}) + +set(asiopal_link_libraries "openpal") +if(DNP3_TLS) + set(asiopal_link_libraries "${asiopal_link_libraries};${OPENSSL_LIBRARIES}") +endif() + +target_link_libraries(asiopal ${asiopal_link_libraries}) +install(TARGETS asiopal DESTINATION lib) +set_target_properties(asiopal PROPERTIES FOLDER libs) + +# ---- asiodnp3 library ---- +file(GLOB_RECURSE asiodnp3_HPP ./cpp/libs/src/asiodnp3/*.h ./cpp/libs/include/asiodnp3/*.h) +if(DNP3_TLS) + file(GLOB_RECURSE asiodnp3_CPP ./cpp/libs/src/asiodnp3/*.cpp) +else() + file(GLOB asiodnp3_CPP ./cpp/libs/src/asiodnp3/*.cpp) +endif() +add_library(asiodnp3 ${LIB_TYPE} ${asiodnp3_HPP} ${asiodnp3_CPP}) +target_link_libraries(asiodnp3 asiopal opendnp3) +install(TARGETS asiodnp3 DESTINATION lib) +set_target_properties(asiodnp3 PROPERTIES FOLDER libs) + +if(DNP3_JAVA) + file(GLOB_RECURSE opendnp3java_SRC ./java/cpp/*.h ./java/cpp/*.cpp) + add_library(opendnp3java SHARED ${opendnp3java_SRC}) + target_link_libraries(opendnp3java asiodnp3) + install(TARGETS opendnp3java DESTINATION lib) + set_target_properties(opendnp3java PROPERTIES FOLDER libs) +endif() + +# ----- install ----- + +# common pattern and exludes for all installed headers +set(INSTALL_ARGS FILES_MATCHING PATTERN "*.h" PATTERN ".deps" EXCLUDE PATTERN ".libs" EXCLUDE) +install(DIRECTORY ./cpp/libs/include/ DESTINATION include ${INSTALL_ARGS}) + +if(DNP3_DEMO) + + # ----- master demo executable ----- + add_executable(master-demo ./cpp/examples/master/main.cpp) + target_link_libraries (master-demo LINK_PUBLIC asiodnp3 ${PTHREAD}) + set_target_properties(master-demo PROPERTIES FOLDER demos) + + # ----- master demo executable ----- + add_executable(master-gprs-demo ./cpp/examples/master-gprs/main.cpp) + target_link_libraries (master-gprs-demo LINK_PUBLIC asiodnp3 ${PTHREAD}) + set_target_properties(master-gprs-demo PROPERTIES FOLDER demos) + + # ----- outstation demo executable ----- + add_executable(outstation-demo ./cpp/examples/outstation/main.cpp) + target_link_libraries (outstation-demo LINK_PUBLIC asiodnp3 ${PTHREAD}) + set_target_properties(outstation-demo PROPERTIES FOLDER demos) + + if(DNP3_DECODER) + + # ----- decoder executable ----- + add_executable(decoder ./cpp/examples/decoder/main.cpp) + target_link_libraries (decoder asiodnp3 dnp3decode ${PTHREAD}) + set_target_properties(decoder PROPERTIES FOLDER demos) + + endif() + + if(DNP3_TLS) + + # ----- master tls executable ----- + add_executable(master-tls-demo ./cpp/examples/tls/master/main.cpp) + target_link_libraries (master-tls-demo LINK_PUBLIC asiodnp3 ${PTHREAD}) + set_target_properties(master-tls-demo PROPERTIES FOLDER demos/tls) + + # ----- outstation tls executable ----- + add_executable(outstation-tls-demo ./cpp/examples/tls/outstation/main.cpp) + target_link_libraries (outstation-tls-demo LINK_PUBLIC asiodnp3 ${PTHREAD}) + set_target_properties(outstation-tls-demo PROPERTIES FOLDER demos/tls) + + # ----- master-gprs tls executable ----- + add_executable(master-gprs-tls-demo ./cpp/examples/tls/master-gprs/main.cpp) + target_link_libraries (master-gprs-tls-demo LINK_PUBLIC asiodnp3 ${PTHREAD}) + set_target_properties(master-gprs-tls-demo PROPERTIES FOLDER demos/tls) + + endif() + +endif() + +if(DNP3_TEST) + + enable_testing() + + # ----- testlib library ------ + file(GLOB_RECURSE testlib_SRC ./cpp/tests/libs/src/testlib/*.cpp ./cpp/tests/libs/src/testlib/*.h) + add_library(testlib ${testlib_SRC}) + target_link_libraries(testlib openpal) + set_target_properties(testlib PROPERTIES FOLDER tests/mocks) + + # ----- dnp3mocks library ------ + file(GLOB_RECURSE dnp3mocks_SRC ./cpp/tests/libs/src/dnp3mocks/*.cpp ./cpp/tests/libs/src/dnp3mocks/*.h) + add_library(dnp3mocks ${dnp3mocks_SRC}) + target_link_libraries(dnp3mocks opendnp3 testlib) + set_target_properties(dnp3mocks PROPERTIES FOLDER tests/mocks) + + # ----- openpal tests ----- + file(GLOB_RECURSE openpal_TESTSRC ./cpp/tests/openpal/src/*.cpp ./cpp/tests/openpal/src/*.h) + add_executable (testopenpal ${openpal_TESTSRC}) + target_link_libraries (testopenpal LINK_PUBLIC testlib ${PTHREAD}) + set_target_properties(testopenpal PROPERTIES FOLDER tests) + add_test(testopenpal testopenpal) + + # ----- opendnp3 tests ----- + file(GLOB_RECURSE opendnp3_TESTSRC ./cpp/tests/opendnp3/src/*.cpp ./cpp/tests/opendnp3/src/*.h) + add_executable (testopendnp3 ${opendnp3_TESTSRC}) + target_link_libraries (testopendnp3 LINK_PUBLIC dnp3mocks ${PTHREAD}) + set_target_properties(testopendnp3 PROPERTIES FOLDER tests) + add_test(testopendnp3 testopendnp3) + + # ----- asiopal tests ----- + if(DNP3_TLS) + file(GLOB_RECURSE asiopal_TESTSRC ./cpp/tests/asiopal/src/*.cpp ./cpp/tests/asiopal/src/*.h) + else() + file(GLOB asiopal_TESTSRC ./cpp/tests/asiopal/src/*.cpp ./cpp/tests/asiopal/src/*.h ./cpp/tests/asiopal/src/mocks/*.cpp ./cpp/tests/asiopal/src/mocks/*.h) + endif() + add_executable (testasiopal ${asiopal_TESTSRC}) + target_link_libraries (testasiopal LINK_PUBLIC asiopal testlib ${PTHREAD}) + set_target_properties(testasiopal PROPERTIES FOLDER tests) + add_test(testasiopal testasiopal) + + # ----- asiodnp3 tests ----- + file(GLOB_RECURSE asiodnp3_TESTSRC ./cpp/tests/asiodnp3/src/*.cpp ./cpp/tests/asiodnp3/src/*.h) + add_executable (testasiodnp3 ${asiodnp3_TESTSRC}) + target_link_libraries (testasiodnp3 LINK_PUBLIC asiodnp3 dnp3mocks ${PTHREAD}) + set_target_properties(testasiodnp3 PROPERTIES FOLDER tests) + add_test(testasiodnp3 testasiodnp3) + +endif() + +add_custom_target( + format + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND astyle -R ./cpp/*.h ./cpp/*.cpp --options=./config/astyle.cfg --exclude=./cpp/libs/include/opendnp3/gen --exclude=./cpp/libs/src/opendnp3/gen --exclude=./cpp/libs/src/opendnp3/objects + COMMAND astyle -R ./java/cpp/adapters/*.h ./java/cpp/adapters/*.cpp --options=./config/astyle.cfg +) diff --git a/utils/dnp3_src/NOTICE b/utils/dnp3_src/NOTICE new file mode 100644 index 0000000..fa5f273 --- /dev/null +++ b/utils/dnp3_src/NOTICE @@ -0,0 +1,19 @@ +========================================================================= +== NOTICE file corresponding to the section 4 d of == +== the Apache License, Version 2.0, == +== in this case for the opendnp3 == +========================================================================= + +This product includes software developed by Green Energy Corp +(http://www.greenenergycorp.com/) and Automatak LLC (https://wwww.automatak.com). + +Please read the LICENSE file present in the root directory of this +distribution. + +Aside from contributions to the oepdnp3 distribution listed above, this repository +also distributes the following 3rd party softare: + +https://github.com/philsquared/Catch (test only dependency) + +Project requires, but specified as a git-submodule: + * ASIO (https://github.com/chriskohlhoff/asio) 1.10.6 or later diff --git a/utils/dnp3_src/README.md b/utils/dnp3_src/README.md new file mode 100755 index 0000000..6ff9b22 --- /dev/null +++ b/utils/dnp3_src/README.md @@ -0,0 +1,31 @@ +Overview +======== + +Opendnp3 is a portable, scalable, and rigorously tested implementation +of the DNP3 (www.dnp.org) protocol stack written in C++11. The library +is designed for high-performance applications like many concurrent TCP +sessions or huge device simulations. It also embeds very nicely on Linux. + +Documentation +============= + +The documentation can be found on the [project homepage](http://www.automatak.com/opendnp3/#documentation). + +If you want to help contribute to the official guide its in [this repo](https://github.com/automatak/dnp3-guide). + +License +============= + +Licensed under the terms of the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html). + +Copyright (c) 2010, 2011 Green Energy Corp + +Copyright (c) 2013 - 2015 Automatak LLC + +Copyright (c) 2010 - 2015 various contributors + + + + + + diff --git a/utils/dnp3_src/appveyor.yml b/utils/dnp3_src/appveyor.yml new file mode 100644 index 0000000..4e5015b --- /dev/null +++ b/utils/dnp3_src/appveyor.yml @@ -0,0 +1,42 @@ +version: 2.0.{build} +branches: + only: + - 2.0.x +os: Visual Studio 2015 +configuration: Release +platform: x86 +clone_folder: C:\projects\dnp3 +environment: + OSSL_LIB32_DIR: C:\OpenSSL-Win32\lib\VC + OPENDNP3_DIR: C:\projects\dnp3\build\lib +install: +- git describe --tags --exact-match & cmd /c exit 0 +- git submodule update --init --recursive +build_script: +- cmd: MKDIR build +- cmd: CD build +- cmd: MKDIR lib +- cmd: cmake .. -DCMAKE_INSTALL_PREFIX=lib -DDNP3_TEST=ON -DDNP3_TLS=ON -DCMAKE_BUILD_TYPE=Release +- cmd: msbuild opendnp3.sln /p:Configuration=Release /p:Platform=Win32 +- cmd: msbuild INSTALL.vcxproj /p:Configuration=Release /p:Platform=Win32 +- cmd: cd .. +- cmd: msbuild dotnet\bindings.sln /p:Configuration=Release /p:Platform=Win32 +after_build: +- ps: >- + if ($env:APPVEYOR_REPO_TAG -eq "true"){ + nuget pack dotnet\nuget\opendnp3.nuspec -Version "$env:APPVEYOR_REPO_TAG_NAME" + } +test_script: +- cmd: c:\projects\dnp3\build\Release\testasiodnp3.exe +- cmd: c:\projects\dnp3\build\Release\testasiopal.exe +- cmd: c:\projects\dnp3\build\Release\testopendnp3.exe +- cmd: c:\projects\dnp3\build\Release\testopenpal.exe +artifacts: +- path: '**\*.nupkg' + name: nuget +deploy: + provider: NuGet + api_key: + secure: H7w8XBF6q0Gxyo1xKhywjZ4qrjfy3W87oGAAu30BIas1paWIE1UMvk6QM/3xzVE9 + on: + appveyor_repo_tag: true diff --git a/utils/dnp3_src/build-dotnet.bat b/utils/dnp3_src/build-dotnet.bat new file mode 100644 index 0000000..1312b60 --- /dev/null +++ b/utils/dnp3_src/build-dotnet.bat @@ -0,0 +1,43 @@ +@ECHO OFF + +SETLOCAL + +SET CONFIGURATION=Release +IF NOT [%1]==[] (SET CONFIGURATION=%1) +SET PLATFORM=Win32 +IF NOT [%2]==[] (SET PLATFORM=%2) + +where cmake 1>nul +IF ERRORLEVEL 1 ( + ECHO cmake could not be found + GOTO :QUIT +) +IF ["%OSSL_LIB32_DIR%"]==[] ( + ECHO OpenSSL could not be found + GOTO :QUIT +) +ECHO OSSL_LIB32_DIR is %OSSL_LIB32_DIR% +IF ["%VS140COMNTOOLS%"]==[] ( + ECHO VS2015 could not be found + GOTO: QUIT +) +ECHO VS140COMNTOOLS is %VS140COMNTOOLS% + +:BUILD +CALL "%VS140COMNTOOLS%VsDevCmd.bat" + +IF EXIST build RMDIR build /s /q +MKDIR build\lib +CD build + +SET OPENDNP3_DIR=%CD%\lib +ECHO OPENDNP3_DIR is %OPENDNP3_DIR% + +cmake .. -DCMAKE_INSTALL_PREFIX=lib -DDNP3_TEST=ON -DDNP3_TLS=ON -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G"Visual Studio 14 2015" +msbuild opendnp3.sln /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% +msbuild INSTALL.vcxproj /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% +msbuild ..\dotnet\bindings.sln /target:Clean +msbuild ..\dotnet\bindings.sln /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% + +:QUIT +ENDLOCAL \ No newline at end of file diff --git a/utils/dnp3_src/cmake/inc/msvc.cmake b/utils/dnp3_src/cmake/inc/msvc.cmake new file mode 100644 index 0000000..3d2158e --- /dev/null +++ b/utils/dnp3_src/cmake/inc/msvc.cmake @@ -0,0 +1,24 @@ +if (WIN32) + if(MSVC) + add_definitions(-D_WIN32_WINNT=0x0501) + add_definitions(-DASIO_HAS_STD_SYSTEM_ERROR) + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS ${WINSOCKAPI} /wd4251 /wd4996 /wd4273 /wd4275 /wd4018 /wd4146 /EHsc") + + set_property(GLOBAL PROPERTY USE_FOLDERS ON) #allows the creation of solution folders + set(LIB_TYPE STATIC) #default to static on MSVC + else() + if (MINGW) + # MINGW is a hybred between the Windows system and GCC compiler + add_definitions(-D_WIN32_WINNT=0x0501) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") + + set(LIB_TYPE STATIC) #default to static on MinGW + + # We need to link the demos with these + set(NET_LIBS "ws2_32" "wsock32") + endif() + endif() +endif() + diff --git a/utils/dnp3_src/cmake/inc/posix.cmake b/utils/dnp3_src/cmake/inc/posix.cmake new file mode 100644 index 0000000..d93d2f9 --- /dev/null +++ b/utils/dnp3_src/cmake/inc/posix.cmake @@ -0,0 +1,52 @@ +if (UNIX) + set(PTHREAD pthread) + find_package(Threads) + if(STATICLIBS) + set(LIB_TYPE STATIC) + else() + set(LIB_TYPE SHARED) + endif() + + set(CMAKE_C_FLAGS "-Wall -Wno-multichar -Wunused-variable -Wno-unused-parameter -Wunused-function -Wunused -Wno-system-headers -Wwrite-strings -save-temps") + + if (${CYGWIN}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + elseif(${MINGW}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + endif() + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated -Wno-parentheses -std=c++14") + + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + + # Compiler-specific C++14 activation. + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) + message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.9 or greater") + endif () + elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) + message(FATAL_ERROR "${PROJECT_NAME} requires clang 3.5 or greater") + endif () + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + else () + message(FATAL_ERROR "Your C++ compiler does not support C++14: ${CMAKE_CXX_COMPILER_ID} - ${CMAKE_CXX_COMPILER_VERSION}") + endif () + + if(COVERAGE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") + endif() + + if(PROFILE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") + endif() + + if (WERROR) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + endif() + +endif() diff --git a/utils/dnp3_src/cmake/settings.cmake b/utils/dnp3_src/cmake/settings.cmake new file mode 100644 index 0000000..4f0f0cc --- /dev/null +++ b/utils/dnp3_src/cmake/settings.cmake @@ -0,0 +1,6 @@ +get_filename_component(settings_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) + +include("${settings_cmake_dir}/inc/msvc.cmake") +include("${settings_cmake_dir}/inc/posix.cmake") + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/utils/dnp3_src/config/APACHE_LICENSE_HEADER b/utils/dnp3_src/config/APACHE_LICENSE_HEADER new file mode 100644 index 0000000..86942f8 --- /dev/null +++ b/utils/dnp3_src/config/APACHE_LICENSE_HEADER @@ -0,0 +1,19 @@ +Licensed to Green Energy Corp (www.greenenergycorp.com) under one or +more contributor license agreements. See the NOTICE file distributed +with this work for additional information regarding copyright ownership. +Green Energy Corp licenses this file to you under the Apache License, +Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This project was forked on 01/01/2013 by Automatak, LLC and modifications +may have been made to this file. Automatak, LLC licenses these modifications +to you under the terms of the License. + diff --git a/utils/dnp3_src/config/astyle.cfg b/utils/dnp3_src/config/astyle.cfg new file mode 100755 index 0000000..76f33cf --- /dev/null +++ b/utils/dnp3_src/config/astyle.cfg @@ -0,0 +1,9 @@ +# don't create backup files +--style=allman +--suffix=none +--indent=tab +--indent-cases +--pad-oper +--break-closing-brackets +--keep-one-line-statements +--align-pointer=type diff --git a/utils/dnp3_src/config/doxygen.config b/utils/dnp3_src/config/doxygen.config new file mode 100644 index 0000000..ff2388b --- /dev/null +++ b/utils/dnp3_src/config/doxygen.config @@ -0,0 +1,2460 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = opendnp3 + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 2.2.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Reference implementation of DNP3 (IEEE-1815)" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./doc + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = YES + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ./cpp/libs/include/openpal \ + ./cpp/libs/include/opendnp3 \ + ./cpp/libs/include/asiodnp3 \ + ./cpp/libs/include/asiopal \ + ./config/doxygen_files + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.cpp \ + *.h \ + *.dox + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = asio:: + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = ./config/doxygen_files/img + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /opendnp3, a rigorously-tested, Apache-licensed implementation of the +DNP3 protocol (aka IEEE-1815). + +About this page +=============== +This is autogenerated C++ API documentation for developers. This documentation +complements the developers guide. + +Please refer to the guide for architecture, supported features, build instructions, and examples. +*/ + +/** + * @namespace openpal + * + * Some docs here for openpal +*/ +namespace openpal {} diff --git a/utils/dnp3_src/config/formatHeaders.xml b/utils/dnp3_src/config/formatHeaders.xml new file mode 100644 index 0000000..4a32494 --- /dev/null +++ b/utils/dnp3_src/config/formatHeaders.xml @@ -0,0 +1,49 @@ + + 4.0.0 + + com.automatak.dnp3 + formatting + 1.1.0 + pom + + opendnp3 + http://www.github.com/automatak/dnp3 + This is a project only for header formatting, nothing more + + + + + com.mycila + license-maven-plugin + 2.5 + +