Переглянути джерело

Closes #215 Normalize all line endings

Signed-off-by: Martin Melik Merkumians <melik-merkumians@acin.tuwien.ac.at>
Martin Melik Merkumians 6 роки тому
батько
коміт
091e2de36f

+ 3 - 3
AUTHORS

@@ -1,4 +1,4 @@
-Kurt Schweiger
-Rene Smodic
-Alois Zoitl
+Kurt Schweiger
+Rene Smodic
+Alois Zoitl
 Jonathan Engdahl

+ 390 - 390
ChangeLog.txt

@@ -1,390 +1,390 @@
-2011-11-22  alil
-
-	* src/cip/cipclass3connection.c, src/cip/cipconnectionmanager.c,
-	  src/cip/cipconnectionmanager.h, src/cip/cipioconnection.c: fixed
-	  issue in handling connection class trigger
-
-2011-11-21  alil
-
-	* ChangeLog.txt, src/cip/cipconnectionmanager.c,
-	  src/cip/cipconnectionmanager.h, src/cip/cipioconnection.c: added
-	  support for production inhibit time network segment
-	* ChangeLog.txt, README: updated ChangeLog.txt and README for 1.1.
-	  release
-	* .:
-	* : updated documentation for upcoming release
-
-2011-11-18  alil
-
-	* : fixed issue with latest changes to connection path handling
-	* : updated stc file
-	* : updated some parameters
-	* : first version of application triggered connection support
-
-2011-11-17  alil
-
-	* : added IApp_HandleApplication as starting point for application
-	  triggered connections
-	* : fixed issue in close socket
-	* : improved forward open infrastructure non assembly object I/O
-	  connections
-
-2011-09-13  alil
-
-	* : reworked the structure CIP_Class in order to make its
-	  maintenance easier.
-
-2011-08-25  alil
-
-	* : reworked connection handling mechanisms in a way that any CIP
-	  object can be a connection target
-
-2011-05-18  alil
-
-	* : added support for compilation on win32
-	* : fixed bug# 3285739: config assembly return value wrong
-
-2011-02-17  alil
-
-	* : fixed issue with 64Bit datatype support
-
-2011-01-04  alil
-
-	* : merged changes from 1.0.3 release branch
-
-2010-12-17  alil
-
-	* : fixed wrong endless loop in isConnectedOutputAssembly
-
-2010-12-16  alil
-
-	* : added check in setAttributeSingle of assembly objects if they
-	  are the write target in any open connection
-	* : fixed handling of configuration data
-	* : added more than 1 simultaneous connections for listen only and
-	  input only
-	* : fixed wrong initialization of listen only connections
-
-2010-12-09  alil
-
-	* : moved checking of correct originator address for connected
-	  messages into the handleReceivedConnectedData function in order
-	  to correctly check even if data is presented from wrong socket.
-	* : fixed an issue in forward open of listen and input only
-	  connections
-
-2010-12-01  alil
-
-	* : Fixed Bug# 3124374: faulty if in getListenOnlyConnection()
-	  thanks csar
-
-2010-10-21  alil
-
-	* : added config flag for enabling/disabling the support of 64Bit
-	  datatypes
-	* : Added support for 64Bit integers, implemented a basic data type
-	  decoding infrastructure that simplifies the implementation of
-	  services like SetAttributeSingle, moved encodeData and decodeData
-	  into the public interface of opener in order to allow device
-	  implementers to use them for implementing setting and getting of
-	  special attributes like structs.
-	* : Refactored the names of the encapsulation message handling
-	  functions to better show that these are the functions for
-	  handling received messages.
-
-2010-09-24  alil
-
-	* : Fixed wrong reply connection ID in connected explicit messages
-
-2010-08-11  alil
-
-	* : fixed bug# 3042699: Network handler should close sockets
-	  consistently
-
-2010-07-27  alil
-
-	* : Fixed Bug# 3034698: alignment
-
-2010-06-23  alil
-
-	* : fixed Bug# 3020064: error in tcpip object attr. 4
-
-2010-06-22  alil
-
-	* : Fixed Bug# 3019069: socket close
-
-2010-06-21  alil
-
-	* : worked to improve handling of to large packets
-
-2010-06-16  alil
-
-	* : reworked outputAttribute function to be more flexible and
-	  better usable for encoding not only certain attributes but also
-	  for arrays and structures.
-
-2010-06-14  alil
-
-	* : Fixed Bug# 3015757: endianess bug in cipcommon.c
-
-2010-06-04  alil
-
-	* : Fixed Bug# 3011151: Bug in notifyConnectedCPF (== should be =)
-
-2010-05-27  alil
-
-	* : Fixed Bug# 3007819: T_to_O_RPI
-	* : consolidated connection manager extended error defintions
-
-2010-05-25  alil
-
-	* : fixed issue when explicit messages should not return a value
-	* : fixed issues in returning the correct messages.
-	* : Fixed Bug# 3006795: unconnected send
-
-2010-05-21  alil
-
-	* : changed attrib type back to 16Bit
-
-2010-05-20  alil
-
-	* : Fixed Bug# 2996649: Identity object mixes Status (#5) with
-	  State (#8)
-	* : Fixed Bug# 3004678: attribute id bug: 8/16/32-bit?
-	* : Fixed Bug 3004683: Message Router: 16-bit attribute id
-
-2010-05-14  alil
-
-	* : added stc file for example application
-
-2010-05-12  alil
-
-	* : Fixed Bug #3000134: connection failures can put stack in
-	  unrecoverable state
-
-2010-05-11  alil
-
-	* : Applied Patch #3000005: trivial: mark correct socket closed
-
-2010-05-07  alil
-
-	* : fixed Bug 2997845: if CIP Item Id is bad, need to return
-	  encapsulation error
-
-2010-05-05  alil
-
-	* : improved reset handling in demo app
-	* : changed assembly object to do not have getAttributeAll per
-	  default
-	* : fixed explicit messaging handling regarding the return vars of
-	  the involved functions; allow that objects do not have
-	  getAttributeAll per default (e.g., needed for assembly object)
-	* : corrected setAssemblyAttributeSingle to return the right error
-	  values
-	* : changed revision of assembly class to 2 as required by the cip
-	  spec
-
-2010-05-03  alil
-
-	* : merged changes from 1.0.1 release
-
-2010-04-28  alil
-
-	* : changed assembly ids to the vendor specific range, updated
-	  opener_sample_app.eds, move ChangeLog to ChangeLog.txt
-	* : fixed bug that dissallowed using 16bit class instance ids
-
-2010-04-27  alil
-
-	* : updated ChangeLog
-
-2010-04-21  alil
-
-	* : Applied patch ID: 2989571 (explicit message access
-	  get/setattribute single) for assembly objects
-
-2010-04-15  alil
-
-	* : changed file headers to make them easier to maintain
-
-2010-04-07  alil
-
-	* : fixed bug 2983235
-
-2010-03-16  alil
-
-	* : fixed assert error thanks to csar
-
-2010-03-13  alil
-
-	* : applied custom assertion patch, thanks to bumpp
-
-2010-03-08  alil
-
-	* : applied domain name patch
-
-2010-03-05  alil
-
-	* : moved the encapsulate data to one central plaze
-	* : improved buffer usage in the encapsulation layer. this uses
-	  global vars makes opener easier to read and is the basis for
-	  multiple requests at the same time. This request is based on the
-	  patch submitted by bumpp. Thanks.
-
-2010-02-24  alil
-
-	* : made some changes reported by splint
-
-2010-02-23  alil
-
-	* : fixed wrong asserts in cip startup. Thanks to Mr. Kaiser for
-	  reporting this issue.
-
-2010-02-20  alil
-
-	* : added patch for incarnation id based connection id generation.
-	  Thanks to bumpp
-	* : fixed some pointer checks in ciptcpipinterface.c string
-	  handling
-
-2010-02-11  alil
-
-	* : fixed issue in api declaration; fixed issue for compiling
-	  networkhandler under linux
-	* : first quick fix for the "hijacked" port problem
-
-2010-02-04  alil
-
-	* : finished work on shutdown and clean up code. If opener is now
-	  shutdown it should free all allocated resources.
-	* : added support for connection shutdown on opener close
-
-2010-02-03  alil
-
-	* : Applied patch from bumpp:
-	  This patch adds value definitions for the List Identity Object's
-	  State
-	  attribute, and adds use of the "operational" define in
-	  ListIdentity()
-	  function.
-	  Changed in ListIdentity() to use the status value of the identity
-	  object instead of a constant.
-
-2010-01-24  alil
-
-	* : applied EIP_INVALID_SOCKET patch
-
-2010-01-15  alil
-
-	* : added new api for freeing allocated memory
-
-2010-01-13  alil
-
-	* : fixed wrong IO connection event on application establishment.
-	* : fixed wrong if statement in manageConnections handling
-	  connection timeouts
-
-2009-11-04  alil
-
-	* : fixed issue in an return value of ForwardOpen
-
-2009-11-03  alil
-
-	* : changed sample app to mirror outputs to the inputs
-	* : added first simple eds file with just the connections
-	* : reworked documentation
-
-2009-10-29  alil
-
-	* : added coding rules, and eclipse project settings for the code
-	  formatting
-
-2009-10-27  alil
-
-	* : fully implemented the correct behavior of exclusive owner,
-	  input only, and listen only connections.
-
-2009-10-22  alil
-
-	* : added callback for informing the application on connection
-	  state changes
-	* : starting point for new IO connection handling supporting
-	  application connection types, Attention not finished
-	  implementation!!!
-	  However exclusive owner and input only should work. Please check
-	  for the new application interface.
-
-2009-10-15  alil
-
-	* : fixed wrong handling of timeout multiplier
-
-2009-10-14  alil
-
-	* : updated connection id choosing to conform to the EIP specs
-	* : changed watchdogtimeout behavior to be per default timed out as
-	  it is required on EIP
-
-2009-10-07  alil
-
-	* : fixed issue with wrong usage of connectionIDs when given by the
-	  originator
-
-2009-09-24  alil
-
-	* : implemented support for heartbeat connections; fixed some
-	  issues with peer-to-peer connections
-
-2009-09-08  alil
-
-	* : removed testing output message
-
-2009-09-07  alil
-
-	* : worked on documentation, fixed spelling errors
-
-2009-09-03  alil
-
-	* : reworked tracing facilities to create better code especially
-	  for production code
-
-2009-09-02  alil
-
-	* : made OpENer compile able with c++, updated porting guide to
-	  include ref to setDeviceSerial
-
-2009-09-01  alil
-
-	* : added function for setting the serial number during device
-	  setup allowing to set the serial number more easily per device;
-	  changed main to prompt for command line parameters, updated TODO
-	  and README
-	* : added setsockopt for listen to broadcast messages. is necessary
-	  on some linuxes
-	* : made opener compile with ansi switch
-
-2009-08-31  alil
-
-	* : finished porting guide documentation, update and fixed some
-	  doxygen issues
-	* : finished porting guide documentation, update and fixed some
-	  doxygen issues
-
-2009-08-27  alil
-
-	* : fixed issue in assembly object creation, correctly setup
-	  default build in eclipse project
-
-2009-08-26  alil
-
-	* : worked on general documentation and introduction
-
-2009-08-25  alil
-
-	* : updated documentation main page
-	* : updated documentation of the encapsulation layer
-
-2009-08-24  alil
-
-	* : initial import
-	* :
-
+2011-11-22  alil
+
+	* src/cip/cipclass3connection.c, src/cip/cipconnectionmanager.c,
+	  src/cip/cipconnectionmanager.h, src/cip/cipioconnection.c: fixed
+	  issue in handling connection class trigger
+
+2011-11-21  alil
+
+	* ChangeLog.txt, src/cip/cipconnectionmanager.c,
+	  src/cip/cipconnectionmanager.h, src/cip/cipioconnection.c: added
+	  support for production inhibit time network segment
+	* ChangeLog.txt, README: updated ChangeLog.txt and README for 1.1.
+	  release
+	* .:
+	* : updated documentation for upcoming release
+
+2011-11-18  alil
+
+	* : fixed issue with latest changes to connection path handling
+	* : updated stc file
+	* : updated some parameters
+	* : first version of application triggered connection support
+
+2011-11-17  alil
+
+	* : added IApp_HandleApplication as starting point for application
+	  triggered connections
+	* : fixed issue in close socket
+	* : improved forward open infrastructure non assembly object I/O
+	  connections
+
+2011-09-13  alil
+
+	* : reworked the structure CIP_Class in order to make its
+	  maintenance easier.
+
+2011-08-25  alil
+
+	* : reworked connection handling mechanisms in a way that any CIP
+	  object can be a connection target
+
+2011-05-18  alil
+
+	* : added support for compilation on win32
+	* : fixed bug# 3285739: config assembly return value wrong
+
+2011-02-17  alil
+
+	* : fixed issue with 64Bit datatype support
+
+2011-01-04  alil
+
+	* : merged changes from 1.0.3 release branch
+
+2010-12-17  alil
+
+	* : fixed wrong endless loop in isConnectedOutputAssembly
+
+2010-12-16  alil
+
+	* : added check in setAttributeSingle of assembly objects if they
+	  are the write target in any open connection
+	* : fixed handling of configuration data
+	* : added more than 1 simultaneous connections for listen only and
+	  input only
+	* : fixed wrong initialization of listen only connections
+
+2010-12-09  alil
+
+	* : moved checking of correct originator address for connected
+	  messages into the handleReceivedConnectedData function in order
+	  to correctly check even if data is presented from wrong socket.
+	* : fixed an issue in forward open of listen and input only
+	  connections
+
+2010-12-01  alil
+
+	* : Fixed Bug# 3124374: faulty if in getListenOnlyConnection()
+	  thanks csar
+
+2010-10-21  alil
+
+	* : added config flag for enabling/disabling the support of 64Bit
+	  datatypes
+	* : Added support for 64Bit integers, implemented a basic data type
+	  decoding infrastructure that simplifies the implementation of
+	  services like SetAttributeSingle, moved encodeData and decodeData
+	  into the public interface of opener in order to allow device
+	  implementers to use them for implementing setting and getting of
+	  special attributes like structs.
+	* : Refactored the names of the encapsulation message handling
+	  functions to better show that these are the functions for
+	  handling received messages.
+
+2010-09-24  alil
+
+	* : Fixed wrong reply connection ID in connected explicit messages
+
+2010-08-11  alil
+
+	* : fixed bug# 3042699: Network handler should close sockets
+	  consistently
+
+2010-07-27  alil
+
+	* : Fixed Bug# 3034698: alignment
+
+2010-06-23  alil
+
+	* : fixed Bug# 3020064: error in tcpip object attr. 4
+
+2010-06-22  alil
+
+	* : Fixed Bug# 3019069: socket close
+
+2010-06-21  alil
+
+	* : worked to improve handling of to large packets
+
+2010-06-16  alil
+
+	* : reworked outputAttribute function to be more flexible and
+	  better usable for encoding not only certain attributes but also
+	  for arrays and structures.
+
+2010-06-14  alil
+
+	* : Fixed Bug# 3015757: endianess bug in cipcommon.c
+
+2010-06-04  alil
+
+	* : Fixed Bug# 3011151: Bug in notifyConnectedCPF (== should be =)
+
+2010-05-27  alil
+
+	* : Fixed Bug# 3007819: T_to_O_RPI
+	* : consolidated connection manager extended error defintions
+
+2010-05-25  alil
+
+	* : fixed issue when explicit messages should not return a value
+	* : fixed issues in returning the correct messages.
+	* : Fixed Bug# 3006795: unconnected send
+
+2010-05-21  alil
+
+	* : changed attrib type back to 16Bit
+
+2010-05-20  alil
+
+	* : Fixed Bug# 2996649: Identity object mixes Status (#5) with
+	  State (#8)
+	* : Fixed Bug# 3004678: attribute id bug: 8/16/32-bit?
+	* : Fixed Bug 3004683: Message Router: 16-bit attribute id
+
+2010-05-14  alil
+
+	* : added stc file for example application
+
+2010-05-12  alil
+
+	* : Fixed Bug #3000134: connection failures can put stack in
+	  unrecoverable state
+
+2010-05-11  alil
+
+	* : Applied Patch #3000005: trivial: mark correct socket closed
+
+2010-05-07  alil
+
+	* : fixed Bug 2997845: if CIP Item Id is bad, need to return
+	  encapsulation error
+
+2010-05-05  alil
+
+	* : improved reset handling in demo app
+	* : changed assembly object to do not have getAttributeAll per
+	  default
+	* : fixed explicit messaging handling regarding the return vars of
+	  the involved functions; allow that objects do not have
+	  getAttributeAll per default (e.g., needed for assembly object)
+	* : corrected setAssemblyAttributeSingle to return the right error
+	  values
+	* : changed revision of assembly class to 2 as required by the cip
+	  spec
+
+2010-05-03  alil
+
+	* : merged changes from 1.0.1 release
+
+2010-04-28  alil
+
+	* : changed assembly ids to the vendor specific range, updated
+	  opener_sample_app.eds, move ChangeLog to ChangeLog.txt
+	* : fixed bug that dissallowed using 16bit class instance ids
+
+2010-04-27  alil
+
+	* : updated ChangeLog
+
+2010-04-21  alil
+
+	* : Applied patch ID: 2989571 (explicit message access
+	  get/setattribute single) for assembly objects
+
+2010-04-15  alil
+
+	* : changed file headers to make them easier to maintain
+
+2010-04-07  alil
+
+	* : fixed bug 2983235
+
+2010-03-16  alil
+
+	* : fixed assert error thanks to csar
+
+2010-03-13  alil
+
+	* : applied custom assertion patch, thanks to bumpp
+
+2010-03-08  alil
+
+	* : applied domain name patch
+
+2010-03-05  alil
+
+	* : moved the encapsulate data to one central plaze
+	* : improved buffer usage in the encapsulation layer. this uses
+	  global vars makes opener easier to read and is the basis for
+	  multiple requests at the same time. This request is based on the
+	  patch submitted by bumpp. Thanks.
+
+2010-02-24  alil
+
+	* : made some changes reported by splint
+
+2010-02-23  alil
+
+	* : fixed wrong asserts in cip startup. Thanks to Mr. Kaiser for
+	  reporting this issue.
+
+2010-02-20  alil
+
+	* : added patch for incarnation id based connection id generation.
+	  Thanks to bumpp
+	* : fixed some pointer checks in ciptcpipinterface.c string
+	  handling
+
+2010-02-11  alil
+
+	* : fixed issue in api declaration; fixed issue for compiling
+	  networkhandler under linux
+	* : first quick fix for the "hijacked" port problem
+
+2010-02-04  alil
+
+	* : finished work on shutdown and clean up code. If opener is now
+	  shutdown it should free all allocated resources.
+	* : added support for connection shutdown on opener close
+
+2010-02-03  alil
+
+	* : Applied patch from bumpp:
+	  This patch adds value definitions for the List Identity Object's
+	  State
+	  attribute, and adds use of the "operational" define in
+	  ListIdentity()
+	  function.
+	  Changed in ListIdentity() to use the status value of the identity
+	  object instead of a constant.
+
+2010-01-24  alil
+
+	* : applied EIP_INVALID_SOCKET patch
+
+2010-01-15  alil
+
+	* : added new api for freeing allocated memory
+
+2010-01-13  alil
+
+	* : fixed wrong IO connection event on application establishment.
+	* : fixed wrong if statement in manageConnections handling
+	  connection timeouts
+
+2009-11-04  alil
+
+	* : fixed issue in an return value of ForwardOpen
+
+2009-11-03  alil
+
+	* : changed sample app to mirror outputs to the inputs
+	* : added first simple eds file with just the connections
+	* : reworked documentation
+
+2009-10-29  alil
+
+	* : added coding rules, and eclipse project settings for the code
+	  formatting
+
+2009-10-27  alil
+
+	* : fully implemented the correct behavior of exclusive owner,
+	  input only, and listen only connections.
+
+2009-10-22  alil
+
+	* : added callback for informing the application on connection
+	  state changes
+	* : starting point for new IO connection handling supporting
+	  application connection types, Attention not finished
+	  implementation!!!
+	  However exclusive owner and input only should work. Please check
+	  for the new application interface.
+
+2009-10-15  alil
+
+	* : fixed wrong handling of timeout multiplier
+
+2009-10-14  alil
+
+	* : updated connection id choosing to conform to the EIP specs
+	* : changed watchdogtimeout behavior to be per default timed out as
+	  it is required on EIP
+
+2009-10-07  alil
+
+	* : fixed issue with wrong usage of connectionIDs when given by the
+	  originator
+
+2009-09-24  alil
+
+	* : implemented support for heartbeat connections; fixed some
+	  issues with peer-to-peer connections
+
+2009-09-08  alil
+
+	* : removed testing output message
+
+2009-09-07  alil
+
+	* : worked on documentation, fixed spelling errors
+
+2009-09-03  alil
+
+	* : reworked tracing facilities to create better code especially
+	  for production code
+
+2009-09-02  alil
+
+	* : made OpENer compile able with c++, updated porting guide to
+	  include ref to setDeviceSerial
+
+2009-09-01  alil
+
+	* : added function for setting the serial number during device
+	  setup allowing to set the serial number more easily per device;
+	  changed main to prompt for command line parameters, updated TODO
+	  and README
+	* : added setsockopt for listen to broadcast messages. is necessary
+	  on some linuxes
+	* : made opener compile with ansi switch
+
+2009-08-31  alil
+
+	* : finished porting guide documentation, update and fixed some
+	  doxygen issues
+	* : finished porting guide documentation, update and fixed some
+	  doxygen issues
+
+2009-08-27  alil
+
+	* : fixed issue in assembly object creation, correctly setup
+	  default build in eclipse project
+
+2009-08-26  alil
+
+	* : worked on general documentation and introduction
+
+2009-08-25  alil
+
+	* : updated documentation main page
+	* : updated documentation of the encapsulation layer
+
+2009-08-24  alil
+
+	* : initial import
+	* :
+

Різницю між файлами не показано, бо вона завелика
+ 0 - 115
data/OpENerPC.stc


+ 359 - 359
data/opener_sample_app.eds

@@ -1,359 +1,359 @@
-$ EZ-EDS Version 3.23.1.20171205 Generated Electronic Data Sheet
-
-[File]
-        DescText = "EDS file for the sample application of OpENer";
-        CreateDate = 11-03-2009;
-        CreateTime = 13:15:23;
-        ModDate = 02-06-2018;
-        ModTime = 14:05:38;
-        Revision = 2.3;
-        HomeURL = "https://github.com/EIPStackGroup/OpENer";
-
-[Device]
-        VendCode = 1;
-        VendName = "Rockwell Automation";
-        ProdType = 12;
-        ProdTypeStr = "Communications Adapter";
-        ProdCode = 65001;
-        MajRev = 2;
-        MinRev = 3;
-        ProdName = "OpENer PC";
-        Catalog = "OpENer-2.x";
-
-[Device Classification]
-        Class1 = EtherNetIP;
-
-[Params]
-        Param1 =
-                0,                      $ reserved, shall equal 0
-                ,,                      $ Link Path Size, Link Path
-                0x0000,                 $ Descriptor
-                0xD1,                   $ Data Type
-                1,                      $ Data Size in bytes
-                "Input Data",           $ name
-                "",                     $ units
-                "New Help String",      $ help string
-                ,,0,                    $ min, max, default data values
-                ,,,,                    $ mult, div, base, offset scaling
-                ,,,,                    $ mult, div, base, offset links
-                ;                       $ decimal places
-        Param2 =
-                0,                      $ reserved, shall equal 0
-                ,,                      $ Link Path Size, Link Path
-                0x0000,                 $ Descriptor
-                0xD1,                   $ Data Type
-                1,                      $ Data Size in bytes
-                "Output Data",          $ name
-                "",                     $ units
-                "New Help String",      $ help string
-                ,,0,                    $ min, max, default data values
-                ,,,,                    $ mult, div, base, offset scaling
-                ,,,,                    $ mult, div, base, offset links
-                ;                       $ decimal places
-        Param3 =
-                0,                      $ reserved, shall equal 0
-                ,,                      $ Link Path Size, Link Path
-                0x0000,                 $ Descriptor
-                0xD1,                   $ Data Type
-                1,                      $ Data Size in bytes
-                "Config Data",          $ name
-                "",                     $ units
-                "New Help String",      $ help string
-                ,,0,                    $ min, max, default data values
-                ,,,,                    $ mult, div, base, offset scaling
-                ,,,,                    $ mult, div, base, offset links
-                ;                       $ decimal places
-        Param4 =
-                0,                      $ reserved, shall equal 0
-                ,,                      $ Link Path Size, Link Path
-                0x0000,                 $ Descriptor
-                0xC8,                   $ Data Type
-                4,                      $ Data Size in bytes
-                "RPI",                  $ name
-                "",                     $ units
-                "New Help String",      $ help string
-                20000,,30000,           $ min, max, default data values
-                ,,,,                    $ mult, div, base, offset scaling
-                ,,,,                    $ mult, div, base, offset links
-                ;                       $ decimal places
-
-[Assembly]
-        Object_Name = "Assembly Object";
-        Object_Class_Code = 0x04;
-        Number_Of_Static_Instances = 6;
-        Assem100 =
-                "Input Assembly",
-                "",
-                32,
-                0x0000,
-                ,,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1,
-                8,Param1;
-        Assem150 =
-                "Output Assembly",
-                "",
-                32,
-                0x0001,
-                ,,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2,
-                8,Param2;
-        Assem151 =
-                "Config Assembly",
-                "",
-                10,
-                0x0001,
-                ,,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3,
-                8,Param3;
-
-[Connection Manager]
-        Revision = 1;
-        Object_Name = "Connection Manager Object";
-        Object_Class_Code = 0x06;
-        MaxInst = 1;
-        Number_Of_Static_Instances = 1;
-        Max_Number_Of_Dynamic_Instances = 0;
-        Connection1 =
-                0x84010002,             $ 0-15    = supported transport classes
-                                        $ 16      = trigger: cyclic
-                                        $ 17      = trigger: change of state
-                                        $ 18      = trigger: application
-                                        $ 19-23   = trigger: reserved
-                                        $ 24      = transport type: listen-only
-                                        $ 25      = transport type: input-only
-                                        $ 26      = transport type: exclusive-owner
-                                        $ 27      = transport type: redundant-owner
-                                        $ 28-30   = reserved
-                                        $ 31      = Client = 0 / Server = 1
-                0x44640405,             $ 0       = O->T fixed size supported
-                                        $ 1       = O->T variable size supported
-                                        $ 2       = T->O fixed size supported
-                                        $ 3       = T->O variable size supported
-                                        $ 4-5     = O->T number of bytes per slot (obsolete)
-                                        $ 6-7     = T->O number of bytes per slot (obsolete)
-                                        $ 8-10    = O->T Real time transfer format
-                                        $ 11      = reserved
-                                        $ 12-14   = T->O Real time transfer format
-                                        $ 15      = reserved
-                                        $ 16      = O->T connection type: NULL
-                                        $ 17      = O->T connection type: MULTICAST
-                                        $ 18      = O->T connection type: POINT2POINT
-                                        $ 19      = O->T connection type: reserved
-                                        $ 20      = T->O connection type: NULL
-                                        $ 21      = T->O connection type: MULTICAST
-                                        $ 22      = T->O connection type: POINT2POINT
-                                        $ 23      = T->O connection type: reserved
-                                        $ 24      = O->T priority: LOW
-                                        $ 25      = O->T priority: HIGH
-                                        $ 26      = O->T priority: SCHEDULED
-                                        $ 27      = O->T priority: reserved
-                                        $ 28      = T->O priority: LOW
-                                        $ 29      = T->O priority: HIGH
-                                        $ 30      = T->O priority: SCHEDULED
-                                        $ 31      = T->O priority: reserved
-                Param4,,Assem150,       $ O->T RPI, size, format
-                Param4,,Assem100,       $ T->O RPI, size, format
-                ,,                      $ config #1 size, format
-                ,Assem151,              $ config #2 size, format
-                "Exlusive Owner",       $ Connection Name
-                "",                     $ help string
-                "20 04 24 97 2C 96 2C 64";    $ Path
-        Connection2 =
-                0x02010002,             $ 0-15    = supported transport classes
-                                        $ 16      = trigger: cyclic
-                                        $ 17      = trigger: change of state
-                                        $ 18      = trigger: application
-                                        $ 19-23   = trigger: reserved
-                                        $ 24      = transport type: listen-only
-                                        $ 25      = transport type: input-only
-                                        $ 26      = transport type: exclusive-owner
-                                        $ 27      = transport type: redundant-owner
-                                        $ 28-30   = reserved
-                                        $ 31      = Client = 0 / Server = 1
-                0x44640305,             $ 0       = O->T fixed size supported
-                                        $ 1       = O->T variable size supported
-                                        $ 2       = T->O fixed size supported
-                                        $ 3       = T->O variable size supported
-                                        $ 4-5     = O->T number of bytes per slot (obsolete)
-                                        $ 6-7     = T->O number of bytes per slot (obsolete)
-                                        $ 8-10    = O->T Real time transfer format
-                                        $ 11      = reserved
-                                        $ 12-14   = T->O Real time transfer format
-                                        $ 15      = reserved
-                                        $ 16      = O->T connection type: NULL
-                                        $ 17      = O->T connection type: MULTICAST
-                                        $ 18      = O->T connection type: POINT2POINT
-                                        $ 19      = O->T connection type: reserved
-                                        $ 20      = T->O connection type: NULL
-                                        $ 21      = T->O connection type: MULTICAST
-                                        $ 22      = T->O connection type: POINT2POINT
-                                        $ 23      = T->O connection type: reserved
-                                        $ 24      = O->T priority: LOW
-                                        $ 25      = O->T priority: HIGH
-                                        $ 26      = O->T priority: SCHEDULED
-                                        $ 27      = O->T priority: reserved
-                                        $ 28      = T->O priority: LOW
-                                        $ 29      = T->O priority: HIGH
-                                        $ 30      = T->O priority: SCHEDULED
-                                        $ 31      = T->O priority: reserved
-                Param4,0,,              $ O->T RPI, size, format
-                Param4,32,Assem100,     $ T->O RPI, size, format
-                ,,                      $ config #1 size, format
-                0,,                     $ config #2 size, format
-                "Input Only",           $ Connection Name
-                "",                     $ help string
-                "20 04 24 97 2C 98 2C 64";    $ Path
-        Connection3 =
-                0x01010002,             $ 0-15    = supported transport classes
-                                        $ 16      = trigger: cyclic
-                                        $ 17      = trigger: change of state
-                                        $ 18      = trigger: application
-                                        $ 19-23   = trigger: reserved
-                                        $ 24      = transport type: listen-only
-                                        $ 25      = transport type: input-only
-                                        $ 26      = transport type: exclusive-owner
-                                        $ 27      = transport type: redundant-owner
-                                        $ 28-30   = reserved
-                                        $ 31      = Client = 0 / Server = 1
-                0x44240305,             $ 0       = O->T fixed size supported
-                                        $ 1       = O->T variable size supported
-                                        $ 2       = T->O fixed size supported
-                                        $ 3       = T->O variable size supported
-                                        $ 4-5     = O->T number of bytes per slot (obsolete)
-                                        $ 6-7     = T->O number of bytes per slot (obsolete)
-                                        $ 8-10    = O->T Real time transfer format
-                                        $ 11      = reserved
-                                        $ 12-14   = T->O Real time transfer format
-                                        $ 15      = reserved
-                                        $ 16      = O->T connection type: NULL
-                                        $ 17      = O->T connection type: MULTICAST
-                                        $ 18      = O->T connection type: POINT2POINT
-                                        $ 19      = O->T connection type: reserved
-                                        $ 20      = T->O connection type: NULL
-                                        $ 21      = T->O connection type: MULTICAST
-                                        $ 22      = T->O connection type: POINT2POINT
-                                        $ 23      = T->O connection type: reserved
-                                        $ 24      = O->T priority: LOW
-                                        $ 25      = O->T priority: HIGH
-                                        $ 26      = O->T priority: SCHEDULED
-                                        $ 27      = O->T priority: reserved
-                                        $ 28      = T->O priority: LOW
-                                        $ 29      = T->O priority: HIGH
-                                        $ 30      = T->O priority: SCHEDULED
-                                        $ 31      = T->O priority: reserved
-                Param4,0,,              $ O->T RPI, size, format
-                Param4,,Assem100,       $ T->O RPI, size, format
-                ,,                      $ config #1 size, format
-                ,,                      $ config #2 size, format
-                "Listen Only",          $ Connection Name
-                "",                     $ help string
-                "20 04 24 97 2C 99 2C 64";    $ Path
-
-[Capacity]
-        MaxMsgConnections = 6;
-        MaxIOProduceConsume = 2;
-        MaxIOMcastProducers = 1;
-        MaxIOMcastConsumers = 1;
-        MaxConsumersPerMcast = 6;
-        TSpec1 = TxRx, 32, 100;
-
-[TCP/IP Interface Class]
-        Revision = 4;
-        Object_Name = "TCP/IP Interface Object";
-        Object_Class_Code = 0xF5;
-        MaxInst = 1;
-        Number_Of_Static_Instances = 1;
-        Max_Number_Of_Dynamic_Instances = 0;
-
-[Ethernet Link Class]
-        Revision = 4;
-        Object_Name = "Ethernet Link Object";
-        Object_Class_Code = 0xF6;
-        MaxInst = 1;
-        Number_Of_Static_Instances = 1;
-        Max_Number_Of_Dynamic_Instances = 0;
-
-[Identity Class]
-        Revision = 1;
-        Object_Name = "Identity Object";
-        Object_Class_Code = 0x01;
-        MaxInst = 1;
-        Number_Of_Static_Instances = 1;
-        Max_Number_Of_Dynamic_Instances = 0;
-
-[QoS Class]
-        Revision = 1;
-        Object_Name = "QoS Object";
-        Object_Class_Code = 0x48;
-        MaxInst = 1;
-        Number_Of_Static_Instances = 1;
-        Max_Number_Of_Dynamic_Instances = 0;
-
+$ EZ-EDS Version 3.23.1.20171205 Generated Electronic Data Sheet
+
+[File]
+        DescText = "EDS file for the sample application of OpENer";
+        CreateDate = 11-03-2009;
+        CreateTime = 13:15:23;
+        ModDate = 02-06-2018;
+        ModTime = 14:05:38;
+        Revision = 2.3;
+        HomeURL = "https://github.com/EIPStackGroup/OpENer";
+
+[Device]
+        VendCode = 1;
+        VendName = "Rockwell Automation";
+        ProdType = 12;
+        ProdTypeStr = "Communications Adapter";
+        ProdCode = 65001;
+        MajRev = 2;
+        MinRev = 3;
+        ProdName = "OpENer PC";
+        Catalog = "OpENer-2.x";
+
+[Device Classification]
+        Class1 = EtherNetIP;
+
+[Params]
+        Param1 =
+                0,                      $ reserved, shall equal 0
+                ,,                      $ Link Path Size, Link Path
+                0x0000,                 $ Descriptor
+                0xD1,                   $ Data Type
+                1,                      $ Data Size in bytes
+                "Input Data",           $ name
+                "",                     $ units
+                "New Help String",      $ help string
+                ,,0,                    $ min, max, default data values
+                ,,,,                    $ mult, div, base, offset scaling
+                ,,,,                    $ mult, div, base, offset links
+                ;                       $ decimal places
+        Param2 =
+                0,                      $ reserved, shall equal 0
+                ,,                      $ Link Path Size, Link Path
+                0x0000,                 $ Descriptor
+                0xD1,                   $ Data Type
+                1,                      $ Data Size in bytes
+                "Output Data",          $ name
+                "",                     $ units
+                "New Help String",      $ help string
+                ,,0,                    $ min, max, default data values
+                ,,,,                    $ mult, div, base, offset scaling
+                ,,,,                    $ mult, div, base, offset links
+                ;                       $ decimal places
+        Param3 =
+                0,                      $ reserved, shall equal 0
+                ,,                      $ Link Path Size, Link Path
+                0x0000,                 $ Descriptor
+                0xD1,                   $ Data Type
+                1,                      $ Data Size in bytes
+                "Config Data",          $ name
+                "",                     $ units
+                "New Help String",      $ help string
+                ,,0,                    $ min, max, default data values
+                ,,,,                    $ mult, div, base, offset scaling
+                ,,,,                    $ mult, div, base, offset links
+                ;                       $ decimal places
+        Param4 =
+                0,                      $ reserved, shall equal 0
+                ,,                      $ Link Path Size, Link Path
+                0x0000,                 $ Descriptor
+                0xC8,                   $ Data Type
+                4,                      $ Data Size in bytes
+                "RPI",                  $ name
+                "",                     $ units
+                "New Help String",      $ help string
+                20000,,30000,           $ min, max, default data values
+                ,,,,                    $ mult, div, base, offset scaling
+                ,,,,                    $ mult, div, base, offset links
+                ;                       $ decimal places
+
+[Assembly]
+        Object_Name = "Assembly Object";
+        Object_Class_Code = 0x04;
+        Number_Of_Static_Instances = 6;
+        Assem100 =
+                "Input Assembly",
+                "",
+                32,
+                0x0000,
+                ,,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1,
+                8,Param1;
+        Assem150 =
+                "Output Assembly",
+                "",
+                32,
+                0x0001,
+                ,,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2,
+                8,Param2;
+        Assem151 =
+                "Config Assembly",
+                "",
+                10,
+                0x0001,
+                ,,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3,
+                8,Param3;
+
+[Connection Manager]
+        Revision = 1;
+        Object_Name = "Connection Manager Object";
+        Object_Class_Code = 0x06;
+        MaxInst = 1;
+        Number_Of_Static_Instances = 1;
+        Max_Number_Of_Dynamic_Instances = 0;
+        Connection1 =
+                0x84010002,             $ 0-15    = supported transport classes
+                                        $ 16      = trigger: cyclic
+                                        $ 17      = trigger: change of state
+                                        $ 18      = trigger: application
+                                        $ 19-23   = trigger: reserved
+                                        $ 24      = transport type: listen-only
+                                        $ 25      = transport type: input-only
+                                        $ 26      = transport type: exclusive-owner
+                                        $ 27      = transport type: redundant-owner
+                                        $ 28-30   = reserved
+                                        $ 31      = Client = 0 / Server = 1
+                0x44640405,             $ 0       = O->T fixed size supported
+                                        $ 1       = O->T variable size supported
+                                        $ 2       = T->O fixed size supported
+                                        $ 3       = T->O variable size supported
+                                        $ 4-5     = O->T number of bytes per slot (obsolete)
+                                        $ 6-7     = T->O number of bytes per slot (obsolete)
+                                        $ 8-10    = O->T Real time transfer format
+                                        $ 11      = reserved
+                                        $ 12-14   = T->O Real time transfer format
+                                        $ 15      = reserved
+                                        $ 16      = O->T connection type: NULL
+                                        $ 17      = O->T connection type: MULTICAST
+                                        $ 18      = O->T connection type: POINT2POINT
+                                        $ 19      = O->T connection type: reserved
+                                        $ 20      = T->O connection type: NULL
+                                        $ 21      = T->O connection type: MULTICAST
+                                        $ 22      = T->O connection type: POINT2POINT
+                                        $ 23      = T->O connection type: reserved
+                                        $ 24      = O->T priority: LOW
+                                        $ 25      = O->T priority: HIGH
+                                        $ 26      = O->T priority: SCHEDULED
+                                        $ 27      = O->T priority: reserved
+                                        $ 28      = T->O priority: LOW
+                                        $ 29      = T->O priority: HIGH
+                                        $ 30      = T->O priority: SCHEDULED
+                                        $ 31      = T->O priority: reserved
+                Param4,,Assem150,       $ O->T RPI, size, format
+                Param4,,Assem100,       $ T->O RPI, size, format
+                ,,                      $ config #1 size, format
+                ,Assem151,              $ config #2 size, format
+                "Exlusive Owner",       $ Connection Name
+                "",                     $ help string
+                "20 04 24 97 2C 96 2C 64";    $ Path
+        Connection2 =
+                0x02010002,             $ 0-15    = supported transport classes
+                                        $ 16      = trigger: cyclic
+                                        $ 17      = trigger: change of state
+                                        $ 18      = trigger: application
+                                        $ 19-23   = trigger: reserved
+                                        $ 24      = transport type: listen-only
+                                        $ 25      = transport type: input-only
+                                        $ 26      = transport type: exclusive-owner
+                                        $ 27      = transport type: redundant-owner
+                                        $ 28-30   = reserved
+                                        $ 31      = Client = 0 / Server = 1
+                0x44640305,             $ 0       = O->T fixed size supported
+                                        $ 1       = O->T variable size supported
+                                        $ 2       = T->O fixed size supported
+                                        $ 3       = T->O variable size supported
+                                        $ 4-5     = O->T number of bytes per slot (obsolete)
+                                        $ 6-7     = T->O number of bytes per slot (obsolete)
+                                        $ 8-10    = O->T Real time transfer format
+                                        $ 11      = reserved
+                                        $ 12-14   = T->O Real time transfer format
+                                        $ 15      = reserved
+                                        $ 16      = O->T connection type: NULL
+                                        $ 17      = O->T connection type: MULTICAST
+                                        $ 18      = O->T connection type: POINT2POINT
+                                        $ 19      = O->T connection type: reserved
+                                        $ 20      = T->O connection type: NULL
+                                        $ 21      = T->O connection type: MULTICAST
+                                        $ 22      = T->O connection type: POINT2POINT
+                                        $ 23      = T->O connection type: reserved
+                                        $ 24      = O->T priority: LOW
+                                        $ 25      = O->T priority: HIGH
+                                        $ 26      = O->T priority: SCHEDULED
+                                        $ 27      = O->T priority: reserved
+                                        $ 28      = T->O priority: LOW
+                                        $ 29      = T->O priority: HIGH
+                                        $ 30      = T->O priority: SCHEDULED
+                                        $ 31      = T->O priority: reserved
+                Param4,0,,              $ O->T RPI, size, format
+                Param4,32,Assem100,     $ T->O RPI, size, format
+                ,,                      $ config #1 size, format
+                0,,                     $ config #2 size, format
+                "Input Only",           $ Connection Name
+                "",                     $ help string
+                "20 04 24 97 2C 98 2C 64";    $ Path
+        Connection3 =
+                0x01010002,             $ 0-15    = supported transport classes
+                                        $ 16      = trigger: cyclic
+                                        $ 17      = trigger: change of state
+                                        $ 18      = trigger: application
+                                        $ 19-23   = trigger: reserved
+                                        $ 24      = transport type: listen-only
+                                        $ 25      = transport type: input-only
+                                        $ 26      = transport type: exclusive-owner
+                                        $ 27      = transport type: redundant-owner
+                                        $ 28-30   = reserved
+                                        $ 31      = Client = 0 / Server = 1
+                0x44240305,             $ 0       = O->T fixed size supported
+                                        $ 1       = O->T variable size supported
+                                        $ 2       = T->O fixed size supported
+                                        $ 3       = T->O variable size supported
+                                        $ 4-5     = O->T number of bytes per slot (obsolete)
+                                        $ 6-7     = T->O number of bytes per slot (obsolete)
+                                        $ 8-10    = O->T Real time transfer format
+                                        $ 11      = reserved
+                                        $ 12-14   = T->O Real time transfer format
+                                        $ 15      = reserved
+                                        $ 16      = O->T connection type: NULL
+                                        $ 17      = O->T connection type: MULTICAST
+                                        $ 18      = O->T connection type: POINT2POINT
+                                        $ 19      = O->T connection type: reserved
+                                        $ 20      = T->O connection type: NULL
+                                        $ 21      = T->O connection type: MULTICAST
+                                        $ 22      = T->O connection type: POINT2POINT
+                                        $ 23      = T->O connection type: reserved
+                                        $ 24      = O->T priority: LOW
+                                        $ 25      = O->T priority: HIGH
+                                        $ 26      = O->T priority: SCHEDULED
+                                        $ 27      = O->T priority: reserved
+                                        $ 28      = T->O priority: LOW
+                                        $ 29      = T->O priority: HIGH
+                                        $ 30      = T->O priority: SCHEDULED
+                                        $ 31      = T->O priority: reserved
+                Param4,0,,              $ O->T RPI, size, format
+                Param4,,Assem100,       $ T->O RPI, size, format
+                ,,                      $ config #1 size, format
+                ,,                      $ config #2 size, format
+                "Listen Only",          $ Connection Name
+                "",                     $ help string
+                "20 04 24 97 2C 99 2C 64";    $ Path
+
+[Capacity]
+        MaxMsgConnections = 6;
+        MaxIOProduceConsume = 2;
+        MaxIOMcastProducers = 1;
+        MaxIOMcastConsumers = 1;
+        MaxConsumersPerMcast = 6;
+        TSpec1 = TxRx, 32, 100;
+
+[TCP/IP Interface Class]
+        Revision = 4;
+        Object_Name = "TCP/IP Interface Object";
+        Object_Class_Code = 0xF5;
+        MaxInst = 1;
+        Number_Of_Static_Instances = 1;
+        Max_Number_Of_Dynamic_Instances = 0;
+
+[Ethernet Link Class]
+        Revision = 4;
+        Object_Name = "Ethernet Link Object";
+        Object_Class_Code = 0xF6;
+        MaxInst = 1;
+        Number_Of_Static_Instances = 1;
+        Max_Number_Of_Dynamic_Instances = 0;
+
+[Identity Class]
+        Revision = 1;
+        Object_Name = "Identity Object";
+        Object_Class_Code = 0x01;
+        MaxInst = 1;
+        Number_Of_Static_Instances = 1;
+        Max_Number_Of_Dynamic_Instances = 0;
+
+[QoS Class]
+        Revision = 1;
+        Object_Name = "QoS Object";
+        Object_Class_Code = 0x48;
+        MaxInst = 1;
+        Number_Of_Static_Instances = 1;
+        Max_Number_Of_Dynamic_Instances = 0;
+

+ 55 - 55
license.txt

@@ -1,55 +1,55 @@
-                    SOFTWARE DISTRIBUTION LICENSE FOR THE 
-                     ETHERNET/IP(TM) COMMUNICATION STACK 
-                         (ADAPTED BSD STYLE LICENSE)   
-
-Copyright (c) 2009, Rockwell Automation, Inc. ALL RIGHTS RESERVED.
-EtherNet/IP is a trademark of ODVA, Inc.
-
-Redistribution of the Communications Stack Software for EtherNet/IP and use in 
-source and binary forms, with or without modification, are permitted provided 
-that the following conditions are met:
-
-Redistributions of source code must retain the above copyright and trademark 
-notices, this list of conditions and the following disclaimer in the 
-documentation and/or other materials provided with the distribution.
-
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or 
-other materials provided with the distribution.
-
-Neither the name of Rockwell Automation, ODVA, nor the names of its 
-contributors may be used to endorse or promote products derived from this 
-software without specific prior written permission from the respective owners.
-
-The Communications Stack Software for EtherNet/IP, or any portion thereof, with
-or without modifications, may be incorporated into products for sale.  However,
-the software does not, by itself, convey any right to make, have made, use, 
-import, offer to sell, sell, lease, market, or otherwise distribute or dispose 
-of any products that implement this software, which products might be covered 
-by valid patents or copyrights of ODVA, Inc., its members or other licensors 
-nor does this software result in any license to use the EtherNet/IP mark owned 
-by ODVA. To make, have made, use, import, offer to sell, sell, lease, market, 
-or otherwise distribute or dispose of any products that implement this software, 
-and to use the EtherNet/IP mark, one must obtain the necessary license from 
-ODVA through its Terms of Usage Agreement for the EtherNet/IP technology, 
-available through the ODVA web site at www.odva.org. This license requirement 
-applies equally (a) to devices that completely implement ODVA's Final 
-Specification for EtherNet/IP (“Network Devices”), (b) to components of such 
-Network Devices to the extent they implement portions of the Final 
-Specification for EtherNet/IP, and (c) to enabling technology products, such as
-any other EtherNet/IP or other network protocol stack designed for use in 
-Network Devices to the extent they implement portions of the Final 
-Specification for EtherNet/IP. Persons or entities who are not already licensed
-for the EtherNet/IP technology must contact ODVA for a Terms of Usage Agreement.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+                    SOFTWARE DISTRIBUTION LICENSE FOR THE 
+                     ETHERNET/IP(TM) COMMUNICATION STACK 
+                         (ADAPTED BSD STYLE LICENSE)   
+
+Copyright (c) 2009, Rockwell Automation, Inc. ALL RIGHTS RESERVED.
+EtherNet/IP is a trademark of ODVA, Inc.
+
+Redistribution of the Communications Stack Software for EtherNet/IP and use in 
+source and binary forms, with or without modification, are permitted provided 
+that the following conditions are met:
+
+Redistributions of source code must retain the above copyright and trademark 
+notices, this list of conditions and the following disclaimer in the 
+documentation and/or other materials provided with the distribution.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or 
+other materials provided with the distribution.
+
+Neither the name of Rockwell Automation, ODVA, nor the names of its 
+contributors may be used to endorse or promote products derived from this 
+software without specific prior written permission from the respective owners.
+
+The Communications Stack Software for EtherNet/IP, or any portion thereof, with
+or without modifications, may be incorporated into products for sale.  However,
+the software does not, by itself, convey any right to make, have made, use, 
+import, offer to sell, sell, lease, market, or otherwise distribute or dispose 
+of any products that implement this software, which products might be covered 
+by valid patents or copyrights of ODVA, Inc., its members or other licensors 
+nor does this software result in any license to use the EtherNet/IP mark owned 
+by ODVA. To make, have made, use, import, offer to sell, sell, lease, market, 
+or otherwise distribute or dispose of any products that implement this software, 
+and to use the EtherNet/IP mark, one must obtain the necessary license from 
+ODVA through its Terms of Usage Agreement for the EtherNet/IP technology, 
+available through the ODVA web site at www.odva.org. This license requirement 
+applies equally (a) to devices that completely implement ODVA's Final 
+Specification for EtherNet/IP (“Network Devices”), (b) to components of such 
+Network Devices to the extent they implement portions of the Final 
+Specification for EtherNet/IP, and (c) to enabling technology products, such as
+any other EtherNet/IP or other network protocol stack designed for use in 
+Network Devices to the extent they implement portions of the Final 
+Specification for EtherNet/IP. Persons or entities who are not already licensed
+for the EtherNet/IP technology must contact ODVA for a Terms of Usage Agreement.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+

+ 6 - 6
source/contrib/msinttypes/README

@@ -1,6 +1,6 @@
-The files in this directory are from the msinttypes project done by Alexander Chemeris.
-
-The original files can be found under : http://code.google.com/p/msinttypes/
-
-The files are provided under the BSD license. For details please read the header of the C-header files in this directory.
-
+The files in this directory are from the msinttypes project done by Alexander Chemeris.
+
+The original files can be found under : http://code.google.com/p/msinttypes/
+
+The files are provided under the BSD license. For details please read the header of the C-header files in this directory.
+

+ 305 - 305
source/contrib/msinttypes/inttypes.h

@@ -1,305 +1,305 @@
-// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
-//
-//  Copyright (c) 2006 Alexander Chemeris
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-//   1. Redistributions of source code must retain the above copyright notice,
-//      this list of conditions and the following disclaimer.
-//
-//   2. Redistributions in binary form must reproduce the above copyright
-//      notice, this list of conditions and the following disclaimer in the
-//      documentation and/or other materials provided with the distribution.
-//
-//   3. The name of the author may be used to endorse or promote products
-//      derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_INTTYPES_H_ // [
-#define _MSC_INTTYPES_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#include <stdint.h>
-
-// 7.8 Format conversion of integer types
-
-typedef struct {
-  intmax_t quot;
-  intmax_t rem;
-} imaxdiv_t;
-
-// 7.8.1 Macros for format specifiers
-
-#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
-
-// The fprintf macros for signed integers are:
-#define PRId8       "d"
-#define PRIi8       "i"
-#define PRIdLEAST8  "d"
-#define PRIiLEAST8  "i"
-#define PRIdFAST8   "d"
-#define PRIiFAST8   "i"
-
-#define PRId16       "hd"
-#define PRIi16       "hi"
-#define PRIdLEAST16  "hd"
-#define PRIiLEAST16  "hi"
-#define PRIdFAST16   "hd"
-#define PRIiFAST16   "hi"
-
-#define PRId32       "I32d"
-#define PRIi32       "I32i"
-#define PRIdLEAST32  "I32d"
-#define PRIiLEAST32  "I32i"
-#define PRIdFAST32   "I32d"
-#define PRIiFAST32   "I32i"
-
-#define PRId64       "I64d"
-#define PRIi64       "I64i"
-#define PRIdLEAST64  "I64d"
-#define PRIiLEAST64  "I64i"
-#define PRIdFAST64   "I64d"
-#define PRIiFAST64   "I64i"
-
-#define PRIdMAX     "I64d"
-#define PRIiMAX     "I64i"
-
-#define PRIdPTR     "Id"
-#define PRIiPTR     "Ii"
-
-// The fprintf macros for unsigned integers are:
-#define PRIo8       "o"
-#define PRIu8       "u"
-#define PRIx8       "x"
-#define PRIX8       "X"
-#define PRIoLEAST8  "o"
-#define PRIuLEAST8  "u"
-#define PRIxLEAST8  "x"
-#define PRIXLEAST8  "X"
-#define PRIoFAST8   "o"
-#define PRIuFAST8   "u"
-#define PRIxFAST8   "x"
-#define PRIXFAST8   "X"
-
-#define PRIo16       "ho"
-#define PRIu16       "hu"
-#define PRIx16       "hx"
-#define PRIX16       "hX"
-#define PRIoLEAST16  "ho"
-#define PRIuLEAST16  "hu"
-#define PRIxLEAST16  "hx"
-#define PRIXLEAST16  "hX"
-#define PRIoFAST16   "ho"
-#define PRIuFAST16   "hu"
-#define PRIxFAST16   "hx"
-#define PRIXFAST16   "hX"
-
-#define PRIo32       "I32o"
-#define PRIu32       "I32u"
-#define PRIx32       "I32x"
-#define PRIX32       "I32X"
-#define PRIoLEAST32  "I32o"
-#define PRIuLEAST32  "I32u"
-#define PRIxLEAST32  "I32x"
-#define PRIXLEAST32  "I32X"
-#define PRIoFAST32   "I32o"
-#define PRIuFAST32   "I32u"
-#define PRIxFAST32   "I32x"
-#define PRIXFAST32   "I32X"
-
-#define PRIo64       "I64o"
-#define PRIu64       "I64u"
-#define PRIx64       "I64x"
-#define PRIX64       "I64X"
-#define PRIoLEAST64  "I64o"
-#define PRIuLEAST64  "I64u"
-#define PRIxLEAST64  "I64x"
-#define PRIXLEAST64  "I64X"
-#define PRIoFAST64   "I64o"
-#define PRIuFAST64   "I64u"
-#define PRIxFAST64   "I64x"
-#define PRIXFAST64   "I64X"
-
-#define PRIoMAX     "I64o"
-#define PRIuMAX     "I64u"
-#define PRIxMAX     "I64x"
-#define PRIXMAX     "I64X"
-
-#define PRIoPTR     "Io"
-#define PRIuPTR     "Iu"
-#define PRIxPTR     "Ix"
-#define PRIXPTR     "IX"
-
-// The fscanf macros for signed integers are:
-#define SCNd8       "d"
-#define SCNi8       "i"
-#define SCNdLEAST8  "d"
-#define SCNiLEAST8  "i"
-#define SCNdFAST8   "d"
-#define SCNiFAST8   "i"
-
-#define SCNd16       "hd"
-#define SCNi16       "hi"
-#define SCNdLEAST16  "hd"
-#define SCNiLEAST16  "hi"
-#define SCNdFAST16   "hd"
-#define SCNiFAST16   "hi"
-
-#define SCNd32       "ld"
-#define SCNi32       "li"
-#define SCNdLEAST32  "ld"
-#define SCNiLEAST32  "li"
-#define SCNdFAST32   "ld"
-#define SCNiFAST32   "li"
-
-#define SCNd64       "I64d"
-#define SCNi64       "I64i"
-#define SCNdLEAST64  "I64d"
-#define SCNiLEAST64  "I64i"
-#define SCNdFAST64   "I64d"
-#define SCNiFAST64   "I64i"
-
-#define SCNdMAX     "I64d"
-#define SCNiMAX     "I64i"
-
-#ifdef _WIN64 // [
-#  define SCNdPTR     "I64d"
-#  define SCNiPTR     "I64i"
-#else  // _WIN64 ][
-#  define SCNdPTR     "ld"
-#  define SCNiPTR     "li"
-#endif  // _WIN64 ]
-
-// The fscanf macros for unsigned integers are:
-#define SCNo8       "o"
-#define SCNu8       "u"
-#define SCNx8       "x"
-#define SCNX8       "X"
-#define SCNoLEAST8  "o"
-#define SCNuLEAST8  "u"
-#define SCNxLEAST8  "x"
-#define SCNXLEAST8  "X"
-#define SCNoFAST8   "o"
-#define SCNuFAST8   "u"
-#define SCNxFAST8   "x"
-#define SCNXFAST8   "X"
-
-#define SCNo16       "ho"
-#define SCNu16       "hu"
-#define SCNx16       "hx"
-#define SCNX16       "hX"
-#define SCNoLEAST16  "ho"
-#define SCNuLEAST16  "hu"
-#define SCNxLEAST16  "hx"
-#define SCNXLEAST16  "hX"
-#define SCNoFAST16   "ho"
-#define SCNuFAST16   "hu"
-#define SCNxFAST16   "hx"
-#define SCNXFAST16   "hX"
-
-#define SCNo32       "lo"
-#define SCNu32       "lu"
-#define SCNx32       "lx"
-#define SCNX32       "lX"
-#define SCNoLEAST32  "lo"
-#define SCNuLEAST32  "lu"
-#define SCNxLEAST32  "lx"
-#define SCNXLEAST32  "lX"
-#define SCNoFAST32   "lo"
-#define SCNuFAST32   "lu"
-#define SCNxFAST32   "lx"
-#define SCNXFAST32   "lX"
-
-#define SCNo64       "I64o"
-#define SCNu64       "I64u"
-#define SCNx64       "I64x"
-#define SCNX64       "I64X"
-#define SCNoLEAST64  "I64o"
-#define SCNuLEAST64  "I64u"
-#define SCNxLEAST64  "I64x"
-#define SCNXLEAST64  "I64X"
-#define SCNoFAST64   "I64o"
-#define SCNuFAST64   "I64u"
-#define SCNxFAST64   "I64x"
-#define SCNXFAST64   "I64X"
-
-#define SCNoMAX     "I64o"
-#define SCNuMAX     "I64u"
-#define SCNxMAX     "I64x"
-#define SCNXMAX     "I64X"
-
-#ifdef _WIN64 // [
-#  define SCNoPTR     "I64o"
-#  define SCNuPTR     "I64u"
-#  define SCNxPTR     "I64x"
-#  define SCNXPTR     "I64X"
-#else  // _WIN64 ][
-#  define SCNoPTR     "lo"
-#  define SCNuPTR     "lu"
-#  define SCNxPTR     "lx"
-#  define SCNXPTR     "lX"
-#endif  // _WIN64 ]
-
-#endif // __STDC_FORMAT_MACROS ]
-
-// 7.8.2 Functions for greatest-width integer types
-
-// 7.8.2.1 The imaxabs function
-#define imaxabs _abs64
-
-// 7.8.2.2 The imaxdiv function
-
-// This is modified version of div() function from Microsoft's div.c found
-// in %MSVC.NET%\crt\src\div.c
-#ifdef STATIC_IMAXDIV // [
-static
-#else // STATIC_IMAXDIV ][
-__inline
-#endif // STATIC_IMAXDIV ]
-imaxdiv_t __cdecl imaxdiv(intmax_t numer,
-                          intmax_t denom) {
-  imaxdiv_t result;
-
-  result.quot = numer / denom;
-  result.rem = numer % denom;
-
-  if (numer < 0 && result.rem > 0) {
-    // did division wrong; must fix up
-    ++result.quot;
-    result.rem -= denom;
-  }
-
-  return result;
-}
-
-// 7.8.2.3 The strtoimax and strtoumax functions
-#define strtoimax _strtoi64
-#define strtoumax _strtoui64
-
-// 7.8.2.4 The wcstoimax and wcstoumax functions
-#define wcstoimax _wcstoi64
-#define wcstoumax _wcstoui64
-
-
-#endif // _MSC_INTTYPES_H_ ]
+// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+//  Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+//
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+//
+//   3. The name of the author may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <stdint.h>
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+  intmax_t quot;
+  intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8       "d"
+#define PRIi8       "i"
+#define PRIdLEAST8  "d"
+#define PRIiLEAST8  "i"
+#define PRIdFAST8   "d"
+#define PRIiFAST8   "i"
+
+#define PRId16       "hd"
+#define PRIi16       "hi"
+#define PRIdLEAST16  "hd"
+#define PRIiLEAST16  "hi"
+#define PRIdFAST16   "hd"
+#define PRIiFAST16   "hi"
+
+#define PRId32       "I32d"
+#define PRIi32       "I32i"
+#define PRIdLEAST32  "I32d"
+#define PRIiLEAST32  "I32i"
+#define PRIdFAST32   "I32d"
+#define PRIiFAST32   "I32i"
+
+#define PRId64       "I64d"
+#define PRIi64       "I64i"
+#define PRIdLEAST64  "I64d"
+#define PRIiLEAST64  "I64i"
+#define PRIdFAST64   "I64d"
+#define PRIiFAST64   "I64i"
+
+#define PRIdMAX     "I64d"
+#define PRIiMAX     "I64i"
+
+#define PRIdPTR     "Id"
+#define PRIiPTR     "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8       "o"
+#define PRIu8       "u"
+#define PRIx8       "x"
+#define PRIX8       "X"
+#define PRIoLEAST8  "o"
+#define PRIuLEAST8  "u"
+#define PRIxLEAST8  "x"
+#define PRIXLEAST8  "X"
+#define PRIoFAST8   "o"
+#define PRIuFAST8   "u"
+#define PRIxFAST8   "x"
+#define PRIXFAST8   "X"
+
+#define PRIo16       "ho"
+#define PRIu16       "hu"
+#define PRIx16       "hx"
+#define PRIX16       "hX"
+#define PRIoLEAST16  "ho"
+#define PRIuLEAST16  "hu"
+#define PRIxLEAST16  "hx"
+#define PRIXLEAST16  "hX"
+#define PRIoFAST16   "ho"
+#define PRIuFAST16   "hu"
+#define PRIxFAST16   "hx"
+#define PRIXFAST16   "hX"
+
+#define PRIo32       "I32o"
+#define PRIu32       "I32u"
+#define PRIx32       "I32x"
+#define PRIX32       "I32X"
+#define PRIoLEAST32  "I32o"
+#define PRIuLEAST32  "I32u"
+#define PRIxLEAST32  "I32x"
+#define PRIXLEAST32  "I32X"
+#define PRIoFAST32   "I32o"
+#define PRIuFAST32   "I32u"
+#define PRIxFAST32   "I32x"
+#define PRIXFAST32   "I32X"
+
+#define PRIo64       "I64o"
+#define PRIu64       "I64u"
+#define PRIx64       "I64x"
+#define PRIX64       "I64X"
+#define PRIoLEAST64  "I64o"
+#define PRIuLEAST64  "I64u"
+#define PRIxLEAST64  "I64x"
+#define PRIXLEAST64  "I64X"
+#define PRIoFAST64   "I64o"
+#define PRIuFAST64   "I64u"
+#define PRIxFAST64   "I64x"
+#define PRIXFAST64   "I64X"
+
+#define PRIoMAX     "I64o"
+#define PRIuMAX     "I64u"
+#define PRIxMAX     "I64x"
+#define PRIXMAX     "I64X"
+
+#define PRIoPTR     "Io"
+#define PRIuPTR     "Iu"
+#define PRIxPTR     "Ix"
+#define PRIXPTR     "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8       "d"
+#define SCNi8       "i"
+#define SCNdLEAST8  "d"
+#define SCNiLEAST8  "i"
+#define SCNdFAST8   "d"
+#define SCNiFAST8   "i"
+
+#define SCNd16       "hd"
+#define SCNi16       "hi"
+#define SCNdLEAST16  "hd"
+#define SCNiLEAST16  "hi"
+#define SCNdFAST16   "hd"
+#define SCNiFAST16   "hi"
+
+#define SCNd32       "ld"
+#define SCNi32       "li"
+#define SCNdLEAST32  "ld"
+#define SCNiLEAST32  "li"
+#define SCNdFAST32   "ld"
+#define SCNiFAST32   "li"
+
+#define SCNd64       "I64d"
+#define SCNi64       "I64i"
+#define SCNdLEAST64  "I64d"
+#define SCNiLEAST64  "I64i"
+#define SCNdFAST64   "I64d"
+#define SCNiFAST64   "I64i"
+
+#define SCNdMAX     "I64d"
+#define SCNiMAX     "I64i"
+
+#ifdef _WIN64 // [
+#  define SCNdPTR     "I64d"
+#  define SCNiPTR     "I64i"
+#else  // _WIN64 ][
+#  define SCNdPTR     "ld"
+#  define SCNiPTR     "li"
+#endif  // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8       "o"
+#define SCNu8       "u"
+#define SCNx8       "x"
+#define SCNX8       "X"
+#define SCNoLEAST8  "o"
+#define SCNuLEAST8  "u"
+#define SCNxLEAST8  "x"
+#define SCNXLEAST8  "X"
+#define SCNoFAST8   "o"
+#define SCNuFAST8   "u"
+#define SCNxFAST8   "x"
+#define SCNXFAST8   "X"
+
+#define SCNo16       "ho"
+#define SCNu16       "hu"
+#define SCNx16       "hx"
+#define SCNX16       "hX"
+#define SCNoLEAST16  "ho"
+#define SCNuLEAST16  "hu"
+#define SCNxLEAST16  "hx"
+#define SCNXLEAST16  "hX"
+#define SCNoFAST16   "ho"
+#define SCNuFAST16   "hu"
+#define SCNxFAST16   "hx"
+#define SCNXFAST16   "hX"
+
+#define SCNo32       "lo"
+#define SCNu32       "lu"
+#define SCNx32       "lx"
+#define SCNX32       "lX"
+#define SCNoLEAST32  "lo"
+#define SCNuLEAST32  "lu"
+#define SCNxLEAST32  "lx"
+#define SCNXLEAST32  "lX"
+#define SCNoFAST32   "lo"
+#define SCNuFAST32   "lu"
+#define SCNxFAST32   "lx"
+#define SCNXFAST32   "lX"
+
+#define SCNo64       "I64o"
+#define SCNu64       "I64u"
+#define SCNx64       "I64x"
+#define SCNX64       "I64X"
+#define SCNoLEAST64  "I64o"
+#define SCNuLEAST64  "I64u"
+#define SCNxLEAST64  "I64x"
+#define SCNXLEAST64  "I64X"
+#define SCNoFAST64   "I64o"
+#define SCNuFAST64   "I64u"
+#define SCNxFAST64   "I64x"
+#define SCNXFAST64   "I64X"
+
+#define SCNoMAX     "I64o"
+#define SCNuMAX     "I64u"
+#define SCNxMAX     "I64x"
+#define SCNXMAX     "I64X"
+
+#ifdef _WIN64 // [
+#  define SCNoPTR     "I64o"
+#  define SCNuPTR     "I64u"
+#  define SCNxPTR     "I64x"
+#  define SCNXPTR     "I64X"
+#else  // _WIN64 ][
+#  define SCNoPTR     "lo"
+#  define SCNuPTR     "lu"
+#  define SCNxPTR     "lx"
+#  define SCNXPTR     "lX"
+#endif  // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+__inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer,
+                          intmax_t denom) {
+  imaxdiv_t result;
+
+  result.quot = numer / denom;
+  result.rem = numer % denom;
+
+  if (numer < 0 && result.rem > 0) {
+    // did division wrong; must fix up
+    ++result.quot;
+    result.rem -= denom;
+  }
+
+  return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]

+ 131 - 131
source/doc/coding_rules/src/opener_coding_rules.tex

@@ -1,68 +1,68 @@
-\documentclass[final,a4paper,10pt, oneside]{article}
+\documentclass[final,a4paper,10pt, oneside]{article}
 \usepackage[latin1]{inputenc}
-\usepackage[T1]{fontenc}
-
-\usepackage{a4wide} 
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%   important definitions at the beginning
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-\title{Coding Rules for\\ \emph{OpENer} --- Open Source EtherNet/IP$^{TM}$ Adapter Stack\\\large Version 2.0}
-\author{Martin Melik Merkumians\thanks{melik-merkumians\@@acin.tuwien.ac.at}}
-\date{2015-11-15}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Links
-\usepackage{ifpdf}
-\ifpdf
- \usepackage[pdftex, colorlinks, pdfstartview=FitH, plainpages=false, pdfpagelabels]{hyperref}
- \pdfcompresslevel=9
-\else
- \usepackage[dvipdfm, colorlinks]{hyperref}
-\fi
-
-\hypersetup{colorlinks, linkcolor=black, filecolor=black, urlcolor=black, citecolor=black, pdftitle={Coding Rules for OpENer},pdfauthor={Alois Zoitl}}
-
-% Font
-\usepackage{mathpazo}
-
-\usepackage[centerlast,small,bf]{caption} %zentriert, kleiner als fliesstext, fett (gilt nur fuer 'Abbildung x:')
-
-% Figures
-\usepackage[dvips]{graphicx}
-
-% Listings
-\usepackage{listings}
-\lstset{language=C++}
-\lstset{commentstyle=\textit}
-\lstset{linewidth=\textwidth}
+\usepackage[T1]{fontenc}
+
+\usepackage{a4wide} 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%   important definitions at the beginning
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+\title{Coding Rules for\\ \emph{OpENer} --- Open Source EtherNet/IP$^{TM}$ Adapter Stack\\\large Version 2.0}
+\author{Martin Melik Merkumians\thanks{melik-merkumians\@@acin.tuwien.ac.at}}
+\date{2015-11-15}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Links
+\usepackage{ifpdf}
+\ifpdf
+ \usepackage[pdftex, colorlinks, pdfstartview=FitH, plainpages=false, pdfpagelabels]{hyperref}
+ \pdfcompresslevel=9
+\else
+ \usepackage[dvipdfm, colorlinks]{hyperref}
+\fi
+
+\hypersetup{colorlinks, linkcolor=black, filecolor=black, urlcolor=black, citecolor=black, pdftitle={Coding Rules for OpENer},pdfauthor={Alois Zoitl}}
+
+% Font
+\usepackage{mathpazo}
+
+\usepackage[centerlast,small,bf]{caption} %zentriert, kleiner als fliesstext, fett (gilt nur fuer 'Abbildung x:')
+
+% Figures
+\usepackage[dvips]{graphicx}
+
+% Listings
+\usepackage{listings}
+\lstset{language=C++}
+\lstset{commentstyle=\textit}
+\lstset{linewidth=\textwidth}
 \lstset{basicstyle=\scriptsize}
 
 \usepackage{fancyref}
-\usepackage{hyperref}
-
-
-
-\begin{document}
-
-\maketitle
-
+\usepackage{hyperref}
+
+
+
+\begin{document}
+
+\maketitle
+
 \tableofcontents
 
 \section{Introduction}
 This document describes the coding rules, which has to be used in the OpENer project. These rules are mainly the Google C++ style rules, with some extensions specific to C and the OpENer project. If something is not covered by the rules given in this document, please check the official Google C++ style guide, available at \url{http://google.github.io/styleguide/cppguide.html}. Additional code style examples can be found at \url{https://gist.github.com/davidzchen/9187878}.
 
-As the OpENer code style aims to be as close as possible to the established Google C++ code style, please file an issue if anything in this guide contradicts the Google C++ code style.
-
-\section{Comments}
-A sufficient amount of comments has to be written. There are never too many comments, whereas invalid comments are worse than none --- thus invalid comments have to be removed from the source code. Comments have to be written in English. 
-
-
+As the OpENer code style aims to be as close as possible to the established Google C++ code style, please file an issue if anything in this guide contradicts the Google C++ code style.
+
+\section{Comments}
+A sufficient amount of comments has to be written. There are never too many comments, whereas invalid comments are worse than none --- thus invalid comments have to be removed from the source code. Comments have to be written in English. 
+
+
 Comments for function, structure, \ldots~ definitions have to follow the conventions of \emph{Doxygen} to allow the automated generation of documentation for the source code. Hereby Java-style Doxygen comments shall be used. Doxygen comments shall therefore start with slash and two starts, and use the @ symbol to indicate Doxygen keywords. For enums, variables, and strucutres inline documentation with \emph{/**<} shall be used. Autobrief behavior shall not be assumed for Doxygen comments. See the example below.
 \begin{lstlisting}[frame=trbl]{}
 /** @brief function, structure, enum, etc. to comment
@@ -77,58 +77,58 @@ int foo(char bar) {
 
 const int g_kFooBar = 1; /**< Global constant which needs documentation */
 
-\end{lstlisting}
-
-Comments have to be meaningful, to describe to program and to be up to date.
-
-
-\subsection{Fileheaders}
-Every source-file must contain a fileheader as follows:
-\begin{lstlisting}[frame=trbl]{}
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
- *
- * Contributors:
- *     <date>: <author>, <author email> - changes
- ******************************************************************************/
-\end{lstlisting}
-Each author needs to explain his changes in the code. 
-\subsection{Revision History}
-%To track changes in the source files every new file version must contain it's version information in the following form:
-%\begin{center}
-%  @version: $<$date$>$/$<$author$>$: $<$description$>$
-%\end{center}
-%An additional example is given in the appendix \ref{subsec:FileHeader} of this document.
-The revision history has to be done in a style  usable by Doxygen. This means that the history is independent of the files, but all classes are documented.
-
-\subsection{Keywords}
-The following Keywords should be used in the source code to mark special comments:
-\begin{itemize}
-	\item \textbf{TODO:} For comments about possible or needed extensions
-	\item \textbf{FIXME:} To be used for comments about potential (or known) bugs
-\end{itemize}
-
-\section{Datatypes}
-\Fref{tab:datatypes} contains the definitions of important standard datatypes. This is done to ensure a machine independant defintion of the bit-width of the standard data types. For \emph{OpENer}-development these definitions are in the file: \verb|src/typedefs.h|
-
+\end{lstlisting}
+
+Comments have to be meaningful, to describe to program and to be up to date.
+
+
+\subsection{Fileheaders}
+Every source-file must contain a fileheader as follows:
+\begin{lstlisting}[frame=trbl]{}
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved. 
+ *
+ * Contributors:
+ *     <date>: <author>, <author email> - changes
+ ******************************************************************************/
+\end{lstlisting}
+Each author needs to explain his changes in the code. 
+\subsection{Revision History}
+%To track changes in the source files every new file version must contain it's version information in the following form:
+%\begin{center}
+%  @version: $<$date$>$/$<$author$>$: $<$description$>$
+%\end{center}
+%An additional example is given in the appendix \ref{subsec:FileHeader} of this document.
+The revision history has to be done in a style  usable by Doxygen. This means that the history is independent of the files, but all classes are documented.
+
+\subsection{Keywords}
+The following Keywords should be used in the source code to mark special comments:
+\begin{itemize}
+	\item \textbf{TODO:} For comments about possible or needed extensions
+	\item \textbf{FIXME:} To be used for comments about potential (or known) bugs
+\end{itemize}
+
+\section{Datatypes}
+\Fref{tab:datatypes} contains the definitions of important standard datatypes. This is done to ensure a machine independant defintion of the bit-width of the standard data types. For \emph{OpENer}-development these definitions are in the file: \verb|src/typedefs.h|
+
 \begin{table}[h] 
-\caption{Data types used in OpENer} \label{tab:datatypes}
-	\centering 
-		\begin{tabular}{lll}
-			defined data type	& bit-width / description & used C-datatype \\
-			\hline
-			EipByte	&	8 bit unsigned	&   uint8\_t\\
-			EipInt8	&	8 bit signed	&	int8\_t	 \\
-			EipInt16	&	16 bit signed	&	int16\_t	 \\
+\caption{Data types used in OpENer} \label{tab:datatypes}
+	\centering 
+		\begin{tabular}{lll}
+			defined data type	& bit-width / description & used C-datatype \\
+			\hline
+			EipByte	&	8 bit unsigned	&   uint8\_t\\
+			EipInt8	&	8 bit signed	&	int8\_t	 \\
+			EipInt16	&	16 bit signed	&	int16\_t	 \\
 			EipInt32	&	32 bit signed	&	int32\_t	 \\
-			EipInt64 & 64 bit signed & int64\_t \\
-			EipUint8	&	8 bit unsigned	&	uint8\_t	 \\
-			EipUint16	&	16 bit unsigned	&	uint16\_t	 \\
+			EipInt64 & 64 bit signed & int64\_t \\
+			EipUint8	&	8 bit unsigned	&	uint8\_t	 \\
+			EipUint16	&	16 bit unsigned	&	uint16\_t	 \\
 			EipUint32	&	32 bit unsigned	&	uint32\_t	 \\
-			EipUint64 & 64 bit unsigned & uint64\_t \\
-			EipFloat	&	single precission IEEE float (32 bit) &	float	 \\
-			EipDfloat	&	double precission IEEE float (64 bit) &	double	\\
+			EipUint64 & 64 bit unsigned & uint64\_t \\
+			EipFloat	&	single precission IEEE float (32 bit) &	float	 \\
+			EipDfloat	&	double precission IEEE float (64 bit) &	double	\\
 			EipBool8	&	byte variable as boolean value	&	unit8\_t	 \\
 			
 			CipOctet & unspecified type & uint8\_t \\
@@ -148,46 +148,46 @@ The following Keywords should be used in the source code to mark special comment
 			CipLint & 64 bit signed & int64\_t \\
 			CipUlint & 64 bit unsigned & uint64\_t \\
 			CipLword & 64 bit unsigned & uint64\_t
-		\end{tabular}
-\end{table} 
-
-These data types shall only be used when the bit size is important for the correct operation of the code, whereby Eip-prefixed data types shall be used for communication functions, and Cip-prefixed data types shall be used for CIP related functions and objects. If not we advice to use the type \verb|int| or \verb|unsigned int| for most variables, as this is the most efficient data type and can lead on some platforms (e.g., ARM) even to smaller code size.
-
-\section{Naming of Identifiers}
-Every identifier has to be named in English. The first character of an identifier must not contain underscores (there are some compiler directives which start with underscores and this could lead to conflicts). Mixed case letters has to be used and the appropriate prefixes have to be inserted where necessary.
-
-\subsection{Pre- \& Postfixes}
+		\end{tabular}
+\end{table} 
+
+These data types shall only be used when the bit size is important for the correct operation of the code, whereby Eip-prefixed data types shall be used for communication functions, and Cip-prefixed data types shall be used for CIP related functions and objects. If not we advice to use the type \verb|int| or \verb|unsigned int| for most variables, as this is the most efficient data type and can lead on some platforms (e.g., ARM) even to smaller code size.
+
+\section{Naming of Identifiers}
+Every identifier has to be named in English. The first character of an identifier must not contain underscores (there are some compiler directives which start with underscores and this could lead to conflicts). Mixed case letters has to be used and the appropriate prefixes have to be inserted where necessary.
+
+\subsection{Pre- \& Postfixes}
 The following prefixes have to be applied to identifiers:\\
 \begin{itemize}
 	\item \emph{"g\_"} shall be prefixed for global variables.
 	\item \emph{"\_"} shall be postfixed for member variables. These are usually CIP object variables with file-global scope.
 \end{itemize}
 
-\subsection{Variables}
+\subsection{Variables}
 Variables have to be named self explanatory. The names have to be provided with the appropriate pre- or postfix and shall be all lowercase letters, and if a name consists of more than one word underscores shall be used for separating these words. The only exception are loop variables (thereby the use of i, j, k is allowed). Only one variable declaration per line is allowed. Pointer operators at the declaration have to be located in front of the variable (not after the type identifier). If possible initializations have to be done directly at the declaration.
 
 \paragraph{Examples}
-\begin{quote}
+\begin{quote}
 \begin{lstlisting}
 int i;
 int local_variable;
-CipBool boolean_flag_in_cip_object_;
+CipBool boolean_flag_in_cip_object_;
 \end{lstlisting}
-\end{quote}
+\end{quote}
 
 \subsection{Constants}
-The preferred way to declare constants is to define them as\emph{const} data types, if this is not possible constants shall be defined as pre-processor statements, via \emph{\#define}.
+The preferred way to declare constants is to define them as\emph{const} data types, if this is not possible constants shall be defined as pre-processor statements, via \emph{\#define}.
 If constants are defined as C constants the name of the constant shall start with \emph{k}, followed by the constant name in Pascal case.
 If a constant is defined as a pre-processor statement the constant name shall be all upper case, separating multiple words with underscored.
 Avoid the using ``magic numbers'' (e.g. \verb|if (x == 3){...}|). Instead use constants.
 
 \paragraph{Examples}
-\begin{quote}
+\begin{quote}
 \begin{lstlisting}
 static int g_global_variable;
 static const int g_kAGlobalConstant = 73:
 const int kAnImportantConstant = 42;
-#define DO_NOT_DO_THIS_IF_IT_IS_NOT_NECESSARY bad
+#define DO_NOT_DO_THIS_IF_IT_IS_NOT_NECESSARY bad
 \end{lstlisting}
 \end{quote}
 
@@ -200,7 +200,7 @@ Functions names shall be Pascal cased, function parameters shall be named like v
 \end{itemize}
 
 \paragraph{Examples}
-\begin{quote}
+\begin{quote}
 \begin{lstlisting}
 int FooBar(const int foo, const char* const bar, double* additional_return_value)
 \end{lstlisting}
@@ -212,7 +212,7 @@ The default case for structs shall be, that they are defined as anonymous struct
 The element names inside the struct are following the normal conventions for their types.
 
 \paragraph{Examples}
-\begin{quote}
+\begin{quote}
 \begin{lstlisting}
 typedef struct {
     int foo;
@@ -230,7 +230,7 @@ typedef the_excpetion {
 Enums shall be defined anonymous and typedef'ed to a type name. As the values inside an enum are constant, the naming scheme of constants apply for enum members. As Enums do not define their own namespace, the enum type name shall be added between the initial \emph{k} and the constant name.
 
 \paragraph{Examples}
-\begin{quote}
+\begin{quote}
 \begin{lstlisting}
 typedef enum {
     kImportantEnumConstant1 = 0,
@@ -239,11 +239,11 @@ typedef enum {
 \end{lstlisting}
 \end{quote}
 
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\section{Code Formatting}
-In order to have consistent code formating the Google C++ coding style rules shall apply. When using Eclipse as development environment the coding format xml file is available at \url{https://github.com/google/styleguide}. By pressing \verb|<ctrl><shift>f| the formatter will format the code according to these rules.
-
-
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Code Formatting}
+In order to have consistent code formating the Google C++ coding style rules shall apply. When using Eclipse as development environment the coding format xml file is available at \url{https://github.com/google/styleguide}. By pressing \verb|<ctrl><shift>f| the formatter will format the code according to these rules.
+
+
 \end{document}

+ 450 - 450
source/src/cip/appcontype.c

@@ -1,450 +1,450 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-
-#include <string.h>
-
-#include "appcontype.h"
-
-#include "cipconnectionmanager.h"
-#include "cipconnectionobject.h"
-#include "opener_api.h"
-#include "assert.h"
-#include "trace.h"
-#include "cipepath.h"
-
-/** @brief Exclusive Owner connection data */
-typedef struct {
-  unsigned int output_assembly; /**< the O-to-T point for the connection */
-  unsigned int input_assembly; /**< the T-to-O point for the connection */
-  unsigned int config_assembly; /**< the config point for the connection */
-  CipConnectionObject connection_data; /**< the connection data, only one connection is allowed per O-to-T point*/
-} ExclusiveOwnerConnection;
-
-/** @brief Input Only connection data */
-typedef struct {
-  unsigned int output_assembly; /**< the O-to-T point for the connection */
-  unsigned int input_assembly; /**< the T-to-O point for the connection */
-  unsigned int config_assembly; /**< the config point for the connection */
-  CipConnectionObject connection_data[
-    OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH];                                   /*< the connection data */
-} InputOnlyConnection;
-
-/** @brief Listen Only connection data */
-typedef struct {
-  unsigned int output_assembly; /**< the O-to-T point for the connection */
-  unsigned int input_assembly; /**< the T-to-O point for the connection */
-  unsigned int config_assembly; /**< the config point for the connection */
-  CipConnectionObject connection_data[
-    OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH
-  ];                                                                               /**< the connection data */
-} ListenOnlyConnection;
-
-ExclusiveOwnerConnection g_exlusive_owner_connections[
-  OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS];                                                     /**< Exclusive Owner connections */
-
-InputOnlyConnection g_input_only_connections[OPENER_CIP_NUM_INPUT_ONLY_CONNS]; /**< Input Only connections */
-
-ListenOnlyConnection g_listen_only_connections[OPENER_CIP_NUM_LISTEN_ONLY_CONNS]; /**< Listen Only connections */
-
-/** @brief Takes an ConnectionObject and searches and returns an Exclusive Owner Connection based on the ConnectionObject,
- * if there is non it returns NULL
- *
- * @param connection_object Connection Object which will be searched for in the Exclusive Owner Connections
- * @param extended_error Pointer to the extended error variable, will be written if an error occurs
- * @return The corresponding Exclusive Owner Connection or NULL if there is non
- */
-CipConnectionObject *GetExclusiveOwnerConnection(
-  const CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error);
-
-/** @brief Takes an ConnectionObject and searches and returns an Input Only Connection based on the ConnectionObject,
- * if there is non it returns NULL
- *
- * @param connection_object Connection Object which will be searched for in the Input Only Connections
- * @param extended_error Pointer to the extended error variable, will be written if an error occurs
- * @return The corresponding Exclusive Owner Connection or NULL if there is non
- */
-CipConnectionObject *GetInputOnlyConnection(
-  const CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error);
-
-/** @brief Takes an ConnectionObject and searches and returns an Listen Only Connection based on the ConnectionObject,
- * if there is non it returns NULL
- *
- * @param connection_object Connection Object which will be searched for in the Listen Only Connections
- * @param extended_error Pointer to the extended error variable, will be written if an error occurs
- * @return The corresponding Exclusive Owner Connection or NULL if there is non
- */
-CipConnectionObject *GetListenOnlyConnection(
-  const CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error);
-
-void ConfigureExclusiveOwnerConnectionPoint(
-  const unsigned int connection_number,
-  const unsigned int output_assembly,
-  const unsigned int input_assembly,
-  const unsigned int config_assembly) {
-  if (OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS > connection_number) {
-    g_exlusive_owner_connections[connection_number].output_assembly =
-      output_assembly;
-    g_exlusive_owner_connections[connection_number].input_assembly =
-      input_assembly;
-    g_exlusive_owner_connections[connection_number].config_assembly =
-      config_assembly;
-  }
-}
-
-void ConfigureInputOnlyConnectionPoint(const unsigned int connection_number,
-                                       const unsigned int output_assembly,
-                                       const unsigned int input_assembly,
-                                       const unsigned int config_assembly) {
-  if (OPENER_CIP_NUM_INPUT_ONLY_CONNS > connection_number) {
-    g_input_only_connections[connection_number].output_assembly =
-      output_assembly;
-    g_input_only_connections[connection_number].input_assembly = input_assembly;
-    g_input_only_connections[connection_number].config_assembly =
-      config_assembly;
-  }
-}
-
-void ConfigureListenOnlyConnectionPoint(const unsigned int connection_number,
-                                        const unsigned int output_assembly,
-                                        const unsigned int input_assembly,
-                                        const unsigned int config_assembly) {
-  if (OPENER_CIP_NUM_LISTEN_ONLY_CONNS > connection_number) {
-    g_listen_only_connections[connection_number].output_assembly =
-      output_assembly;
-    g_listen_only_connections[connection_number].input_assembly =
-      input_assembly;
-    g_listen_only_connections[connection_number].config_assembly =
-      config_assembly;
-  }
-}
-
-CipConnectionObject *GetIoConnectionForConnectionData(
-  CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error) {
-
-  *extended_error = 0;
-
-  CipConnectionObject *io_connection = GetExclusiveOwnerConnection(
-    connection_object,
-    extended_error);
-  if (NULL == io_connection) {
-    if (kConnectionManagerExtendedStatusCodeSuccess == *extended_error) {
-      /* we found no connection and don't have an error so try input only next */
-      io_connection = GetInputOnlyConnection(connection_object, extended_error);
-      if (NULL == io_connection) {
-        if (kConnectionManagerExtendedStatusCodeSuccess == *extended_error) {
-          /* we found no connection and don't have an error so try listen only next */
-          io_connection = GetListenOnlyConnection(connection_object,
-                                                  extended_error);
-          if ( (NULL == io_connection) &&
-               (kCipErrorSuccess == *extended_error) ) {
-            /* no application connection type was found that suits the given data */
-            *extended_error =
-              kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
-          } else {
-            ConnectionObjectSetInstanceType(connection_object,
-                                            kConnectionObjectInstanceTypeIOListenOnly);
-            OPENER_TRACE_INFO("IO Listen only connection requested\n");
-            //Is listen only connection
-          }
-        }
-      } else {
-        ConnectionObjectSetInstanceType(connection_object,
-                                        kConnectionObjectInstanceTypeIOInputOnly);
-        OPENER_TRACE_INFO("IO Input only connection requested\n");
-        //is Input only connection
-      }
-    }
-  } else {
-    ConnectionObjectSetInstanceType(connection_object,
-                                    kConnectionObjectInstanceTypeIOExclusiveOwner);
-    OPENER_TRACE_INFO("IO Exclusive Owner connection requested\n");
-    //Is exclusive owner connection
-  }
-
-  if (NULL != io_connection) {
-    ConnectionObjectDeepCopy(io_connection, connection_object);
-  }
-
-  return io_connection;
-}
-
-CipConnectionObject *GetExclusiveOwnerConnection(
-  const CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error) {
-
-  for (size_t i = 0; i < OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS; ++i) {
-    if ( (g_exlusive_owner_connections[i].output_assembly ==
-          connection_object->consumed_path.instance_id)
-         && (g_exlusive_owner_connections[i].input_assembly ==
-             connection_object->produced_path.instance_id)
-         && (g_exlusive_owner_connections[i].config_assembly ==
-             connection_object->configuration_path.instance_id) ) {
-
-      /* check if on other connection point with the same output assembly is currently connected */
-      CipConnectionObject *exclusive_owner = GetConnectedOutputAssembly(
-        connection_object->produced_path.instance_id);
-      if ( NULL
-           != exclusive_owner ) {
-        if(kConnectionObjectStateEstablished ==
-           ConnectionObjectGetState(exclusive_owner) ) {
-          *extended_error =
-            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
-          OPENER_TRACE_INFO("Hit an Ownership conflict in appcontype.c:198\n");
-          break;
-        }
-        if(kConnectionObjectStateTimedOut ==
-           ConnectionObjectGetState(exclusive_owner)
-           && ConnectionObjectEqualOriginator(connection_object,
-                                              exclusive_owner) ) {
-          g_exlusive_owner_connections[i].connection_data.
-          connection_close_function(&(g_exlusive_owner_connections[i].
-                                      connection_data) );
-          return &(g_exlusive_owner_connections[i].connection_data);
-        } else {
-          *extended_error =
-            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
-          OPENER_TRACE_INFO(
-            "Hit an Ownership conflict with timed out connection");
-          break;
-        }
-      }
-      return &(g_exlusive_owner_connections[i].connection_data);
-    }
-  }
-  return NULL;
-}
-
-CipConnectionObject *GetInputOnlyConnection(
-  const CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error) {
-
-  for (size_t i = 0; i < OPENER_CIP_NUM_INPUT_ONLY_CONNS; ++i) {
-    if (g_input_only_connections[i].output_assembly
-        == connection_object->consumed_path.instance_id) { /* we have the same output assembly */
-      if (g_input_only_connections[i].input_assembly
-          != connection_object->produced_path.instance_id) {
-        *extended_error =
-          kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
-        break;
-      }
-      if (g_input_only_connections[i].config_assembly
-          != connection_object->configuration_path.instance_id) {
-        *extended_error =
-          kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
-        break;
-      }
-
-      for (size_t j = 0; j < OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH;
-           ++j) {
-        if (kConnectionObjectStateTimedOut
-            == ConnectionObjectGetState(&(g_input_only_connections[i].
-                                          connection_data[j]) )
-            && ConnectionObjectEqualOriginator(connection_object,
-                                               &(g_input_only_connections[i].
-                                                 connection_data[j]) ) )
-        {
-          g_input_only_connections[i].connection_data[j].
-          connection_close_function(
-            &g_input_only_connections[i].connection_data[j]);
-          return &(g_input_only_connections[i].connection_data[j]);
-        }
-      }
-
-      for (size_t j = 0; j < OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH;
-           ++j) {
-        if (kConnectionObjectStateNonExistent
-            == ConnectionObjectGetState(&(g_input_only_connections[i].
-                                          connection_data[j]) ) ) {
-          return &(g_input_only_connections[i].connection_data[j]);
-        }
-      }
-      *extended_error =
-        kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections;
-      break;
-    }
-  }
-  return NULL;
-}
-
-CipConnectionObject *GetListenOnlyConnection(
-  const CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error) {
-
-  for (size_t i = 0; i < OPENER_CIP_NUM_LISTEN_ONLY_CONNS; i++) {
-    if (g_listen_only_connections[i].output_assembly
-        == connection_object->consumed_path.instance_id) { /* we have the same output assembly */
-      if (g_listen_only_connections[i].input_assembly
-          != connection_object->produced_path.instance_id) {
-        *extended_error =
-          kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
-        break;
-      }
-      if (g_listen_only_connections[i].config_assembly
-          != connection_object->configuration_path.instance_id) {
-        *extended_error =
-          kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
-        break;
-      }
-
-      if ( NULL
-           == GetExistingProducerMulticastConnection(
-             connection_object->produced_path.instance_id) ) {
-        *extended_error =
-          kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened;
-        break;
-      }
-
-      for (size_t j = 0; j < OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH;
-           ++j) {
-        if (kConnectionObjectStateTimedOut
-            == ConnectionObjectGetState(&(g_listen_only_connections[i].
-                                          connection_data[j]) )
-            && ConnectionObjectEqualOriginator(connection_object,
-                                               &(g_listen_only_connections[i].
-                                                 connection_data[j]) ) )
-        {
-          g_listen_only_connections[i].connection_data[j].
-          connection_close_function(
-            &g_listen_only_connections[i].connection_data[j]);
-          return &(g_listen_only_connections[i].connection_data[j]);
-        }
-      }
-
-      for (size_t j = 0; j < OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH;
-           j++) {
-        if (kConnectionObjectStateNonExistent
-            == ConnectionObjectGetState(&(g_listen_only_connections[i].
-                                          connection_data[j]) ) ) {
-          return &(g_listen_only_connections[i].connection_data[j]);
-        }
-      }
-      *extended_error =
-        kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections;
-      break;
-    }
-  }
-  return NULL;
-}
-
-CipConnectionObject *GetExistingProducerMulticastConnection(
-  const EipUint32 input_point) {
-  DoublyLinkedListNode *node = connection_list.first;
-
-  while (NULL != node) {
-    CipConnectionObject *producer_multicast_connection = node->data;
-    if ( true ==
-         ConnectionObjectIsTypeIOConnection(producer_multicast_connection) &&
-         (input_point ==
-          producer_multicast_connection->produced_path.instance_id) &&
-         ( kConnectionObjectConnectionTypeMulticast ==
-           ConnectionObjectGetTToOConnectionType(producer_multicast_connection) )
-         &&
-         (kEipInvalidSocket !=
-          producer_multicast_connection->socket[
-            kUdpCommuncationDirectionProducing]) )
-    {
-      /* we have a connection that produces the same input assembly,
-       * is a multicast producer and manages the connection.
-       */
-      return producer_multicast_connection;
-    }
-    node = node->next;
-  }
-  return NULL;
-}
-
-CipConnectionObject *GetNextNonControlMasterConnection(
-  const EipUint32 input_point) {
-  DoublyLinkedListNode *node = connection_list.first;
-
-  while (NULL != node) {
-    CipConnectionObject *next_non_control_master_connection =
-      node->data;
-    if ( true ==
-         ConnectionObjectIsTypeNonLOIOConnection(
-           next_non_control_master_connection)
-         && kConnectionObjectStateEstablished ==
-         ConnectionObjectGetState(next_non_control_master_connection)
-         && input_point ==
-         next_non_control_master_connection->produced_path.instance_id
-         &&  kConnectionObjectConnectionTypeMulticast ==
-         ConnectionObjectGetTToOConnectionType(
-           next_non_control_master_connection)
-         && (kEipInvalidSocket ==
-             next_non_control_master_connection->socket[
-               kUdpCommuncationDirectionProducing
-             ]) ) {
-      /* we have a connection that produces the same input assembly,
-       * is a multicast producer and does not manage the connection.
-       */
-      return next_non_control_master_connection;
-    }
-    node = node->next;
-  }
-  return NULL;
-}
-
-void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
-                                             const ConnectionObjectInstanceType instance_type)
-{
-
-  OPENER_TRACE_INFO("Close all instance type %d only connections\n",
-                    instance_type);
-  DoublyLinkedListNode *node = connection_list.first;
-  while (NULL != node) {
-    CipConnectionObject *connection = node->data;
-    node = node->next;
-    if ( (instance_type == ConnectionObjectGetInstanceType(connection) )
-         && (input_point == connection->produced_path.instance_id) ) {
-      CipConnectionObject *connection_to_delete = connection;
-      CheckIoConnectionEvent(
-        connection_to_delete->consumed_path.instance_id,
-        connection_to_delete->produced_path.instance_id,
-        kIoConnectionEventClosed);
-
-      assert(connection_to_delete->connection_close_function != NULL);
-      connection_to_delete->connection_close_function(connection_to_delete);
-    }
-  }
-}
-
-void CloseAllConnections(void) {
-  DoublyLinkedListNode *node = connection_list.first;
-  while (NULL != node) {
-    CipConnectionObject *connection = node->data;
-    assert(connection->connection_close_function != NULL);
-    connection->connection_close_function(connection);
-    node = connection_list.first;
-  }
-}
-
-bool ConnectionWithSameConfigPointExists(const EipUint32 config_point) {
-  DoublyLinkedListNode *node = connection_list.first;
-
-  while (NULL != node) {
-    CipConnectionObject *connection = node->data;
-    OPENER_ASSERT(NULL != connection)
-    if (config_point == connection->configuration_path.instance_id) {
-      return true;
-    }
-    node = node->next;
-  }
-  return false;
-}
-
-void InitializeIoConnectionData(void) {
-  memset( g_exlusive_owner_connections, 0,
-          OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS *
-          sizeof(ExclusiveOwnerConnection) );
-  memset( g_input_only_connections, 0,
-          OPENER_CIP_NUM_INPUT_ONLY_CONNS * sizeof(InputOnlyConnection) );
-  memset( g_listen_only_connections, 0,
-          OPENER_CIP_NUM_LISTEN_ONLY_CONNS * sizeof(ListenOnlyConnection) );
-}
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "appcontype.h"
+
+#include "cipconnectionmanager.h"
+#include "cipconnectionobject.h"
+#include "opener_api.h"
+#include "assert.h"
+#include "trace.h"
+#include "cipepath.h"
+
+/** @brief Exclusive Owner connection data */
+typedef struct {
+  unsigned int output_assembly; /**< the O-to-T point for the connection */
+  unsigned int input_assembly; /**< the T-to-O point for the connection */
+  unsigned int config_assembly; /**< the config point for the connection */
+  CipConnectionObject connection_data; /**< the connection data, only one connection is allowed per O-to-T point*/
+} ExclusiveOwnerConnection;
+
+/** @brief Input Only connection data */
+typedef struct {
+  unsigned int output_assembly; /**< the O-to-T point for the connection */
+  unsigned int input_assembly; /**< the T-to-O point for the connection */
+  unsigned int config_assembly; /**< the config point for the connection */
+  CipConnectionObject connection_data[
+    OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH];                                   /*< the connection data */
+} InputOnlyConnection;
+
+/** @brief Listen Only connection data */
+typedef struct {
+  unsigned int output_assembly; /**< the O-to-T point for the connection */
+  unsigned int input_assembly; /**< the T-to-O point for the connection */
+  unsigned int config_assembly; /**< the config point for the connection */
+  CipConnectionObject connection_data[
+    OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH
+  ];                                                                               /**< the connection data */
+} ListenOnlyConnection;
+
+ExclusiveOwnerConnection g_exlusive_owner_connections[
+  OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS];                                                     /**< Exclusive Owner connections */
+
+InputOnlyConnection g_input_only_connections[OPENER_CIP_NUM_INPUT_ONLY_CONNS]; /**< Input Only connections */
+
+ListenOnlyConnection g_listen_only_connections[OPENER_CIP_NUM_LISTEN_ONLY_CONNS]; /**< Listen Only connections */
+
+/** @brief Takes an ConnectionObject and searches and returns an Exclusive Owner Connection based on the ConnectionObject,
+ * if there is non it returns NULL
+ *
+ * @param connection_object Connection Object which will be searched for in the Exclusive Owner Connections
+ * @param extended_error Pointer to the extended error variable, will be written if an error occurs
+ * @return The corresponding Exclusive Owner Connection or NULL if there is non
+ */
+CipConnectionObject *GetExclusiveOwnerConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
+
+/** @brief Takes an ConnectionObject and searches and returns an Input Only Connection based on the ConnectionObject,
+ * if there is non it returns NULL
+ *
+ * @param connection_object Connection Object which will be searched for in the Input Only Connections
+ * @param extended_error Pointer to the extended error variable, will be written if an error occurs
+ * @return The corresponding Exclusive Owner Connection or NULL if there is non
+ */
+CipConnectionObject *GetInputOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
+
+/** @brief Takes an ConnectionObject and searches and returns an Listen Only Connection based on the ConnectionObject,
+ * if there is non it returns NULL
+ *
+ * @param connection_object Connection Object which will be searched for in the Listen Only Connections
+ * @param extended_error Pointer to the extended error variable, will be written if an error occurs
+ * @return The corresponding Exclusive Owner Connection or NULL if there is non
+ */
+CipConnectionObject *GetListenOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
+
+void ConfigureExclusiveOwnerConnectionPoint(
+  const unsigned int connection_number,
+  const unsigned int output_assembly,
+  const unsigned int input_assembly,
+  const unsigned int config_assembly) {
+  if (OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS > connection_number) {
+    g_exlusive_owner_connections[connection_number].output_assembly =
+      output_assembly;
+    g_exlusive_owner_connections[connection_number].input_assembly =
+      input_assembly;
+    g_exlusive_owner_connections[connection_number].config_assembly =
+      config_assembly;
+  }
+}
+
+void ConfigureInputOnlyConnectionPoint(const unsigned int connection_number,
+                                       const unsigned int output_assembly,
+                                       const unsigned int input_assembly,
+                                       const unsigned int config_assembly) {
+  if (OPENER_CIP_NUM_INPUT_ONLY_CONNS > connection_number) {
+    g_input_only_connections[connection_number].output_assembly =
+      output_assembly;
+    g_input_only_connections[connection_number].input_assembly = input_assembly;
+    g_input_only_connections[connection_number].config_assembly =
+      config_assembly;
+  }
+}
+
+void ConfigureListenOnlyConnectionPoint(const unsigned int connection_number,
+                                        const unsigned int output_assembly,
+                                        const unsigned int input_assembly,
+                                        const unsigned int config_assembly) {
+  if (OPENER_CIP_NUM_LISTEN_ONLY_CONNS > connection_number) {
+    g_listen_only_connections[connection_number].output_assembly =
+      output_assembly;
+    g_listen_only_connections[connection_number].input_assembly =
+      input_assembly;
+    g_listen_only_connections[connection_number].config_assembly =
+      config_assembly;
+  }
+}
+
+CipConnectionObject *GetIoConnectionForConnectionData(
+  CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
+
+  *extended_error = 0;
+
+  CipConnectionObject *io_connection = GetExclusiveOwnerConnection(
+    connection_object,
+    extended_error);
+  if (NULL == io_connection) {
+    if (kConnectionManagerExtendedStatusCodeSuccess == *extended_error) {
+      /* we found no connection and don't have an error so try input only next */
+      io_connection = GetInputOnlyConnection(connection_object, extended_error);
+      if (NULL == io_connection) {
+        if (kConnectionManagerExtendedStatusCodeSuccess == *extended_error) {
+          /* we found no connection and don't have an error so try listen only next */
+          io_connection = GetListenOnlyConnection(connection_object,
+                                                  extended_error);
+          if ( (NULL == io_connection) &&
+               (kCipErrorSuccess == *extended_error) ) {
+            /* no application connection type was found that suits the given data */
+            *extended_error =
+              kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
+          } else {
+            ConnectionObjectSetInstanceType(connection_object,
+                                            kConnectionObjectInstanceTypeIOListenOnly);
+            OPENER_TRACE_INFO("IO Listen only connection requested\n");
+            //Is listen only connection
+          }
+        }
+      } else {
+        ConnectionObjectSetInstanceType(connection_object,
+                                        kConnectionObjectInstanceTypeIOInputOnly);
+        OPENER_TRACE_INFO("IO Input only connection requested\n");
+        //is Input only connection
+      }
+    }
+  } else {
+    ConnectionObjectSetInstanceType(connection_object,
+                                    kConnectionObjectInstanceTypeIOExclusiveOwner);
+    OPENER_TRACE_INFO("IO Exclusive Owner connection requested\n");
+    //Is exclusive owner connection
+  }
+
+  if (NULL != io_connection) {
+    ConnectionObjectDeepCopy(io_connection, connection_object);
+  }
+
+  return io_connection;
+}
+
+CipConnectionObject *GetExclusiveOwnerConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
+
+  for (size_t i = 0; i < OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS; ++i) {
+    if ( (g_exlusive_owner_connections[i].output_assembly ==
+          connection_object->consumed_path.instance_id)
+         && (g_exlusive_owner_connections[i].input_assembly ==
+             connection_object->produced_path.instance_id)
+         && (g_exlusive_owner_connections[i].config_assembly ==
+             connection_object->configuration_path.instance_id) ) {
+
+      /* check if on other connection point with the same output assembly is currently connected */
+      CipConnectionObject *exclusive_owner = GetConnectedOutputAssembly(
+        connection_object->produced_path.instance_id);
+      if ( NULL
+           != exclusive_owner ) {
+        if(kConnectionObjectStateEstablished ==
+           ConnectionObjectGetState(exclusive_owner) ) {
+          *extended_error =
+            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
+          OPENER_TRACE_INFO("Hit an Ownership conflict in appcontype.c:198\n");
+          break;
+        }
+        if(kConnectionObjectStateTimedOut ==
+           ConnectionObjectGetState(exclusive_owner)
+           && ConnectionObjectEqualOriginator(connection_object,
+                                              exclusive_owner) ) {
+          g_exlusive_owner_connections[i].connection_data.
+          connection_close_function(&(g_exlusive_owner_connections[i].
+                                      connection_data) );
+          return &(g_exlusive_owner_connections[i].connection_data);
+        } else {
+          *extended_error =
+            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
+          OPENER_TRACE_INFO(
+            "Hit an Ownership conflict with timed out connection");
+          break;
+        }
+      }
+      return &(g_exlusive_owner_connections[i].connection_data);
+    }
+  }
+  return NULL;
+}
+
+CipConnectionObject *GetInputOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
+
+  for (size_t i = 0; i < OPENER_CIP_NUM_INPUT_ONLY_CONNS; ++i) {
+    if (g_input_only_connections[i].output_assembly
+        == connection_object->consumed_path.instance_id) { /* we have the same output assembly */
+      if (g_input_only_connections[i].input_assembly
+          != connection_object->produced_path.instance_id) {
+        *extended_error =
+          kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
+        break;
+      }
+      if (g_input_only_connections[i].config_assembly
+          != connection_object->configuration_path.instance_id) {
+        *extended_error =
+          kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
+        break;
+      }
+
+      for (size_t j = 0; j < OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH;
+           ++j) {
+        if (kConnectionObjectStateTimedOut
+            == ConnectionObjectGetState(&(g_input_only_connections[i].
+                                          connection_data[j]) )
+            && ConnectionObjectEqualOriginator(connection_object,
+                                               &(g_input_only_connections[i].
+                                                 connection_data[j]) ) )
+        {
+          g_input_only_connections[i].connection_data[j].
+          connection_close_function(
+            &g_input_only_connections[i].connection_data[j]);
+          return &(g_input_only_connections[i].connection_data[j]);
+        }
+      }
+
+      for (size_t j = 0; j < OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH;
+           ++j) {
+        if (kConnectionObjectStateNonExistent
+            == ConnectionObjectGetState(&(g_input_only_connections[i].
+                                          connection_data[j]) ) ) {
+          return &(g_input_only_connections[i].connection_data[j]);
+        }
+      }
+      *extended_error =
+        kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections;
+      break;
+    }
+  }
+  return NULL;
+}
+
+CipConnectionObject *GetListenOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
+
+  for (size_t i = 0; i < OPENER_CIP_NUM_LISTEN_ONLY_CONNS; i++) {
+    if (g_listen_only_connections[i].output_assembly
+        == connection_object->consumed_path.instance_id) { /* we have the same output assembly */
+      if (g_listen_only_connections[i].input_assembly
+          != connection_object->produced_path.instance_id) {
+        *extended_error =
+          kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
+        break;
+      }
+      if (g_listen_only_connections[i].config_assembly
+          != connection_object->configuration_path.instance_id) {
+        *extended_error =
+          kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
+        break;
+      }
+
+      if ( NULL
+           == GetExistingProducerMulticastConnection(
+             connection_object->produced_path.instance_id) ) {
+        *extended_error =
+          kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened;
+        break;
+      }
+
+      for (size_t j = 0; j < OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH;
+           ++j) {
+        if (kConnectionObjectStateTimedOut
+            == ConnectionObjectGetState(&(g_listen_only_connections[i].
+                                          connection_data[j]) )
+            && ConnectionObjectEqualOriginator(connection_object,
+                                               &(g_listen_only_connections[i].
+                                                 connection_data[j]) ) )
+        {
+          g_listen_only_connections[i].connection_data[j].
+          connection_close_function(
+            &g_listen_only_connections[i].connection_data[j]);
+          return &(g_listen_only_connections[i].connection_data[j]);
+        }
+      }
+
+      for (size_t j = 0; j < OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH;
+           j++) {
+        if (kConnectionObjectStateNonExistent
+            == ConnectionObjectGetState(&(g_listen_only_connections[i].
+                                          connection_data[j]) ) ) {
+          return &(g_listen_only_connections[i].connection_data[j]);
+        }
+      }
+      *extended_error =
+        kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections;
+      break;
+    }
+  }
+  return NULL;
+}
+
+CipConnectionObject *GetExistingProducerMulticastConnection(
+  const EipUint32 input_point) {
+  DoublyLinkedListNode *node = connection_list.first;
+
+  while (NULL != node) {
+    CipConnectionObject *producer_multicast_connection = node->data;
+    if ( true ==
+         ConnectionObjectIsTypeIOConnection(producer_multicast_connection) &&
+         (input_point ==
+          producer_multicast_connection->produced_path.instance_id) &&
+         ( kConnectionObjectConnectionTypeMulticast ==
+           ConnectionObjectGetTToOConnectionType(producer_multicast_connection) )
+         &&
+         (kEipInvalidSocket !=
+          producer_multicast_connection->socket[
+            kUdpCommuncationDirectionProducing]) )
+    {
+      /* we have a connection that produces the same input assembly,
+       * is a multicast producer and manages the connection.
+       */
+      return producer_multicast_connection;
+    }
+    node = node->next;
+  }
+  return NULL;
+}
+
+CipConnectionObject *GetNextNonControlMasterConnection(
+  const EipUint32 input_point) {
+  DoublyLinkedListNode *node = connection_list.first;
+
+  while (NULL != node) {
+    CipConnectionObject *next_non_control_master_connection =
+      node->data;
+    if ( true ==
+         ConnectionObjectIsTypeNonLOIOConnection(
+           next_non_control_master_connection)
+         && kConnectionObjectStateEstablished ==
+         ConnectionObjectGetState(next_non_control_master_connection)
+         && input_point ==
+         next_non_control_master_connection->produced_path.instance_id
+         &&  kConnectionObjectConnectionTypeMulticast ==
+         ConnectionObjectGetTToOConnectionType(
+           next_non_control_master_connection)
+         && (kEipInvalidSocket ==
+             next_non_control_master_connection->socket[
+               kUdpCommuncationDirectionProducing
+             ]) ) {
+      /* we have a connection that produces the same input assembly,
+       * is a multicast producer and does not manage the connection.
+       */
+      return next_non_control_master_connection;
+    }
+    node = node->next;
+  }
+  return NULL;
+}
+
+void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
+                                             const ConnectionObjectInstanceType instance_type)
+{
+
+  OPENER_TRACE_INFO("Close all instance type %d only connections\n",
+                    instance_type);
+  DoublyLinkedListNode *node = connection_list.first;
+  while (NULL != node) {
+    CipConnectionObject *connection = node->data;
+    node = node->next;
+    if ( (instance_type == ConnectionObjectGetInstanceType(connection) )
+         && (input_point == connection->produced_path.instance_id) ) {
+      CipConnectionObject *connection_to_delete = connection;
+      CheckIoConnectionEvent(
+        connection_to_delete->consumed_path.instance_id,
+        connection_to_delete->produced_path.instance_id,
+        kIoConnectionEventClosed);
+
+      assert(connection_to_delete->connection_close_function != NULL);
+      connection_to_delete->connection_close_function(connection_to_delete);
+    }
+  }
+}
+
+void CloseAllConnections(void) {
+  DoublyLinkedListNode *node = connection_list.first;
+  while (NULL != node) {
+    CipConnectionObject *connection = node->data;
+    assert(connection->connection_close_function != NULL);
+    connection->connection_close_function(connection);
+    node = connection_list.first;
+  }
+}
+
+bool ConnectionWithSameConfigPointExists(const EipUint32 config_point) {
+  DoublyLinkedListNode *node = connection_list.first;
+
+  while (NULL != node) {
+    CipConnectionObject *connection = node->data;
+    OPENER_ASSERT(NULL != connection)
+    if (config_point == connection->configuration_path.instance_id) {
+      return true;
+    }
+    node = node->next;
+  }
+  return false;
+}
+
+void InitializeIoConnectionData(void) {
+  memset( g_exlusive_owner_connections, 0,
+          OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS *
+          sizeof(ExclusiveOwnerConnection) );
+  memset( g_input_only_connections, 0,
+          OPENER_CIP_NUM_INPUT_ONLY_CONNS * sizeof(InputOnlyConnection) );
+  memset( g_listen_only_connections, 0,
+          OPENER_CIP_NUM_LISTEN_ONLY_CONNS * sizeof(ListenOnlyConnection) );
+}

+ 76 - 76
source/src/cip/appcontype.h

@@ -1,76 +1,76 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-#ifndef OPENER_APPCONTYPE_H_
-#define OPENER_APPCONTYPE_H_
-
-#include "cipconnectionmanager.h"
-
-extern DoublyLinkedList connection_list;
-
-void InitializeIoConnectionData(void);
-
-/** @brief check if for the given connection data received in a forward_open request
- *  a suitable connection is available.
- *
- *  If a suitable connection is found the connection data is transfered the
- *  application connection type is set (i.e., EConnType).
- *  @param connection_object connection data to be used
- *  @param extended_error pointer to the extended_error variable, if an error occurred this value has the according
- *     error code for the response
- *  @return
- *        - on success: A pointer to the connection object already containing the connection
- *          data given in connection_object.
- *        - on error: NULL
- */
-CipConnectionObject *GetIoConnectionForConnectionData(
-  CipConnectionObject *const RESTRICT connection_object,
-  EipUint16 *const extended_error);
-
-/** @brief Check if there exists already an exclusive owner or listen only connection
- *         which produces the input assembly.
- *
- *  @param input_point the Input point to be produced
- *  @return if a connection could be found a pointer to this connection if not NULL
- */
-CipConnectionObject *GetExistingProducerMulticastConnection(
-  const EipUint32 input_point);
-
-/** @brief check if there exists an producing multicast exclusive owner or
- * listen only connection that should produce the same input but is not in charge
- * of the connection.
- *
- * @param input_point the produced input
- * @return if a connection could be found the pointer to this connection
- *      otherwise NULL.
- */
-CipConnectionObject *GetNextNonControlMasterConnection(
-  const EipUint32 input_point);
-
-/** @brief Close all connection producing the same input and have the same type
- * (i.e., listen only or input only).
- *
- * @param input_point the input point
- * @param instance_type the connection application type
- */
-void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
-                                             const ConnectionObjectInstanceType instance_type);
-
-/**@ brief close all open connections.
- *
- * For I/O connections the sockets will be freed. The sockets for explicit
- * connections are handled by the encapsulation layer, and freed there.
- */
-void CloseAllConnections(void);
-
-/** @brief Check if there is an established connection that uses the same
- * config point.
- *
- * @param config_point The configuration point
- * @return true if connection was found, otherwise false
- */
-bool ConnectionWithSameConfigPointExists(const EipUint32 config_point);
-
-#endif /* OPENER_APPCONTYPE_H_ */
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#ifndef OPENER_APPCONTYPE_H_
+#define OPENER_APPCONTYPE_H_
+
+#include "cipconnectionmanager.h"
+
+extern DoublyLinkedList connection_list;
+
+void InitializeIoConnectionData(void);
+
+/** @brief check if for the given connection data received in a forward_open request
+ *  a suitable connection is available.
+ *
+ *  If a suitable connection is found the connection data is transfered the
+ *  application connection type is set (i.e., EConnType).
+ *  @param connection_object connection data to be used
+ *  @param extended_error pointer to the extended_error variable, if an error occurred this value has the according
+ *     error code for the response
+ *  @return
+ *        - on success: A pointer to the connection object already containing the connection
+ *          data given in connection_object.
+ *        - on error: NULL
+ */
+CipConnectionObject *GetIoConnectionForConnectionData(
+  CipConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
+
+/** @brief Check if there exists already an exclusive owner or listen only connection
+ *         which produces the input assembly.
+ *
+ *  @param input_point the Input point to be produced
+ *  @return if a connection could be found a pointer to this connection if not NULL
+ */
+CipConnectionObject *GetExistingProducerMulticastConnection(
+  const EipUint32 input_point);
+
+/** @brief check if there exists an producing multicast exclusive owner or
+ * listen only connection that should produce the same input but is not in charge
+ * of the connection.
+ *
+ * @param input_point the produced input
+ * @return if a connection could be found the pointer to this connection
+ *      otherwise NULL.
+ */
+CipConnectionObject *GetNextNonControlMasterConnection(
+  const EipUint32 input_point);
+
+/** @brief Close all connection producing the same input and have the same type
+ * (i.e., listen only or input only).
+ *
+ * @param input_point the input point
+ * @param instance_type the connection application type
+ */
+void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
+                                             const ConnectionObjectInstanceType instance_type);
+
+/**@ brief close all open connections.
+ *
+ * For I/O connections the sockets will be freed. The sockets for explicit
+ * connections are handled by the encapsulation layer, and freed there.
+ */
+void CloseAllConnections(void);
+
+/** @brief Check if there is an established connection that uses the same
+ * config point.
+ *
+ * @param config_point The configuration point
+ * @return true if connection was found, otherwise false
+ */
+bool ConnectionWithSameConfigPointExists(const EipUint32 config_point);
+
+#endif /* OPENER_APPCONTYPE_H_ */

+ 213 - 213
source/src/cip/cipassembly.c

@@ -1,213 +1,213 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-
-#include <string.h>
-#include <stdbool.h>
-
-#include "cipassembly.h"
-
-#include "cipcommon.h"
-#include "opener_api.h"
-#include "trace.h"
-#include "cipconnectionmanager.h"
-
-/** @brief Implementation of the SetAttributeSingle CIP service for Assembly
- *          Objects.
- *  Currently only supports Attribute 3 (CIP_BYTE_ARRAY) of an Assembly
- */
-EipStatus SetAssemblyAttributeSingle(CipInstance *const instance,
-                                     CipMessageRouterRequest *const message_router_request,
-                                     CipMessageRouterResponse *const message_router_response,
-                                     struct sockaddr *originator_address,
-                                     const int encapsulation_session);
-
-/** @brief Constructor for the assembly object class
- *
- *  Creates an initializes Assembly class or object instances
- *  @return Pointer to the created Assembly object
- */
-CipClass *CreateAssemblyClass(void) {
-  /* create the CIP Assembly object with zero instances */
-  CipClass *assembly_class = CreateCipClass(kCipAssemblyClassCode, 0, /* # class attributes*/
-                                            7, /* # highest class attribute number*/
-                                            1, /* # class services*/
-                                            2, /* # instance attributes*/
-                                            4, /* # highest instance attribute number*/
-                                            2, /* # instance services*/
-                                            0, /* # instances*/
-                                            "assembly", /* name */
-                                            2, /* Revision, according to the CIP spec currently this has to be 2 */
-                                            NULL); /* # function pointer for initialization*/
-  if(NULL != assembly_class) {
-    InsertService(assembly_class,
-                  kGetAttributeSingle,
-                  &GetAttributeSingle,
-                  "GetAttributeSingle");
-    InsertService(assembly_class,
-                  kSetAttributeSingle,
-                  &SetAssemblyAttributeSingle,
-                  "SetAssemblyAttributeSingle");
-  }
-
-  return assembly_class;
-}
-
-/** @brief create the CIP Assembly object with zero instances
- *
- */
-EipStatus CipAssemblyInitialize(void) {
-  return ( NULL != CreateAssemblyClass() ) ? kEipStatusOk : kEipStatusError;
-}
-
-void ShutdownAssemblies(void) {
-  CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
-
-  if(NULL != assembly_class) {
-    CipInstance *instance = assembly_class->instances;
-    while(NULL != instance) {
-      CipAttributeStruct *attribute = GetCipAttribute(instance, 3);
-      if(NULL != attribute) {
-        CipFree(attribute->data);
-      }
-      instance = instance->next;
-    }
-  }
-}
-
-CipInstance *CreateAssemblyObject(const EipUint32 instance_id,
-                                  EipByte *const data,
-                                  const EipUint16 data_length) {
-  CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
-  if(NULL == assembly_class) {
-    assembly_class = CreateAssemblyClass();
-  }
-
-  if(NULL == assembly_class) {
-    return NULL;
-  }
-
-  CipInstance *const instance = AddCIPInstance(assembly_class, instance_id);  /* add instances (always succeeds (or asserts))*/
-
-  CipByteArray *const assembly_byte_array = (CipByteArray *) CipCalloc(1,
-                                                                       sizeof(
-                                                                         CipByteArray) );
-  if(assembly_byte_array == NULL) {
-    return NULL; /*TODO remove assembly instance in case of error*/
-  }
-
-  assembly_byte_array->length = data_length;
-  assembly_byte_array->data = data;
-  InsertAttribute(instance,
-                  3,
-                  kCipByteArray,
-                  assembly_byte_array,
-                  kSetAndGetAble);
-  /* Attribute 4 Number of bytes in Attribute 3 */
-  InsertAttribute(instance,
-                  4,
-                  kCipUint,
-                  &(assembly_byte_array->length),
-                  kGetableSingle);
-
-  return instance;
-}
-
-EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance,
-                                              const EipUint8 *const data,
-                                              const EipUint16 data_length) {
-  /* empty path (path size = 0) need to be checked and taken care of in future */
-  /* copy received data to Attribute 3 */
-  CipByteArray *assembly_byte_array =
-    (CipByteArray *) instance->attributes->data;
-  if(assembly_byte_array->length != data_length) {
-    OPENER_TRACE_ERR("wrong amount of data arrived for assembly object\n");
-    return kEipStatusError; /*TODO question should we notify the application that wrong data has been received???*/
-  }
-  else{
-    memcpy(assembly_byte_array->data, data, data_length);
-    /* call the application that new data arrived */
-  }
-
-  return AfterAssemblyDataReceived(instance);
-}
-
-EipStatus SetAssemblyAttributeSingle(CipInstance *const instance,
-                                     CipMessageRouterRequest *const message_router_request,
-                                     CipMessageRouterResponse *const message_router_response,
-                                     struct sockaddr *originator_address,
-                                     const int encapsulation_session) {
-  OPENER_TRACE_INFO(" setAttribute %d\n",
-                    message_router_request->request_path.attribute_number);
-
-  const EipUint8 *const router_request_data = message_router_request->data;
-
-  message_router_response->data_length = 0;
-  message_router_response->reply_service =
-    (0x80 | message_router_request->service);
-  message_router_response->general_status = kCipErrorAttributeNotSupported;
-  message_router_response->size_of_additional_status = 0;
-
-  CipAttributeStruct *attribute = GetCipAttribute(instance,
-                                                  message_router_request->request_path.attribute_number);
-
-  if( (attribute != NULL) &&
-      (3 == message_router_request->request_path.attribute_number) ) {
-    if(attribute->data != NULL) {
-      CipByteArray *data = (CipByteArray *) attribute->data;
-
-      /* TODO: check for ATTRIBUTE_SET/GETABLE MASK */
-      if( true == IsConnectedOutputAssembly(instance->instance_number) ) {
-        OPENER_TRACE_WARN(
-          "Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r");
-        message_router_response->general_status = kCipErrorAttributeNotSetable;
-      }
-      else{
-        if(message_router_request->request_path_size < data->length) {
-          OPENER_TRACE_INFO(
-            "Assembly setAssemblyAttributeSingle: not enough data received.\r\n");
-          message_router_response->general_status = kCipErrorNotEnoughData;
-        }
-        else{
-          if(message_router_request->request_path_size > data->length) {
-            OPENER_TRACE_INFO(
-              "Assembly setAssemblyAttributeSingle: too much data received.\r\n");
-            message_router_response->general_status = kCipErrorTooMuchData;
-          }
-          else{
-            memcpy(data->data, router_request_data, data->length);
-
-            if(AfterAssemblyDataReceived(instance) != kEipStatusOk) {
-              /* punt early without updating the status... though I don't know
-               * how much this helps us here, as the attribute's data has already
-               * been overwritten.
-               *
-               * however this is the task of the application side which will
-               * take the data. In addition we have to inform the sender that the
-               * data was not ok.
-               */
-              message_router_response->general_status =
-                kCipErrorInvalidAttributeValue;
-            }
-            else{
-              message_router_response->general_status = kCipErrorSuccess;
-            }
-          }
-        }
-      }
-    }
-    else{
-      /* the attribute was zero we are a heartbeat assembly */
-      message_router_response->general_status = kCipErrorTooMuchData;
-    }
-  }
-
-  if( (attribute != NULL) &&
-      (4 == message_router_request->request_path.attribute_number) ) {
-    message_router_response->general_status = kCipErrorAttributeNotSetable;
-  }
-
-  return kEipStatusOkSend;
-}
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdbool.h>
+
+#include "cipassembly.h"
+
+#include "cipcommon.h"
+#include "opener_api.h"
+#include "trace.h"
+#include "cipconnectionmanager.h"
+
+/** @brief Implementation of the SetAttributeSingle CIP service for Assembly
+ *          Objects.
+ *  Currently only supports Attribute 3 (CIP_BYTE_ARRAY) of an Assembly
+ */
+EipStatus SetAssemblyAttributeSingle(CipInstance *const instance,
+                                     CipMessageRouterRequest *const message_router_request,
+                                     CipMessageRouterResponse *const message_router_response,
+                                     struct sockaddr *originator_address,
+                                     const int encapsulation_session);
+
+/** @brief Constructor for the assembly object class
+ *
+ *  Creates an initializes Assembly class or object instances
+ *  @return Pointer to the created Assembly object
+ */
+CipClass *CreateAssemblyClass(void) {
+  /* create the CIP Assembly object with zero instances */
+  CipClass *assembly_class = CreateCipClass(kCipAssemblyClassCode, 0, /* # class attributes*/
+                                            7, /* # highest class attribute number*/
+                                            1, /* # class services*/
+                                            2, /* # instance attributes*/
+                                            4, /* # highest instance attribute number*/
+                                            2, /* # instance services*/
+                                            0, /* # instances*/
+                                            "assembly", /* name */
+                                            2, /* Revision, according to the CIP spec currently this has to be 2 */
+                                            NULL); /* # function pointer for initialization*/
+  if(NULL != assembly_class) {
+    InsertService(assembly_class,
+                  kGetAttributeSingle,
+                  &GetAttributeSingle,
+                  "GetAttributeSingle");
+    InsertService(assembly_class,
+                  kSetAttributeSingle,
+                  &SetAssemblyAttributeSingle,
+                  "SetAssemblyAttributeSingle");
+  }
+
+  return assembly_class;
+}
+
+/** @brief create the CIP Assembly object with zero instances
+ *
+ */
+EipStatus CipAssemblyInitialize(void) {
+  return ( NULL != CreateAssemblyClass() ) ? kEipStatusOk : kEipStatusError;
+}
+
+void ShutdownAssemblies(void) {
+  CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
+
+  if(NULL != assembly_class) {
+    CipInstance *instance = assembly_class->instances;
+    while(NULL != instance) {
+      CipAttributeStruct *attribute = GetCipAttribute(instance, 3);
+      if(NULL != attribute) {
+        CipFree(attribute->data);
+      }
+      instance = instance->next;
+    }
+  }
+}
+
+CipInstance *CreateAssemblyObject(const EipUint32 instance_id,
+                                  EipByte *const data,
+                                  const EipUint16 data_length) {
+  CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode);
+  if(NULL == assembly_class) {
+    assembly_class = CreateAssemblyClass();
+  }
+
+  if(NULL == assembly_class) {
+    return NULL;
+  }
+
+  CipInstance *const instance = AddCIPInstance(assembly_class, instance_id);  /* add instances (always succeeds (or asserts))*/
+
+  CipByteArray *const assembly_byte_array = (CipByteArray *) CipCalloc(1,
+                                                                       sizeof(
+                                                                         CipByteArray) );
+  if(assembly_byte_array == NULL) {
+    return NULL; /*TODO remove assembly instance in case of error*/
+  }
+
+  assembly_byte_array->length = data_length;
+  assembly_byte_array->data = data;
+  InsertAttribute(instance,
+                  3,
+                  kCipByteArray,
+                  assembly_byte_array,
+                  kSetAndGetAble);
+  /* Attribute 4 Number of bytes in Attribute 3 */
+  InsertAttribute(instance,
+                  4,
+                  kCipUint,
+                  &(assembly_byte_array->length),
+                  kGetableSingle);
+
+  return instance;
+}
+
+EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance,
+                                              const EipUint8 *const data,
+                                              const EipUint16 data_length) {
+  /* empty path (path size = 0) need to be checked and taken care of in future */
+  /* copy received data to Attribute 3 */
+  CipByteArray *assembly_byte_array =
+    (CipByteArray *) instance->attributes->data;
+  if(assembly_byte_array->length != data_length) {
+    OPENER_TRACE_ERR("wrong amount of data arrived for assembly object\n");
+    return kEipStatusError; /*TODO question should we notify the application that wrong data has been received???*/
+  }
+  else{
+    memcpy(assembly_byte_array->data, data, data_length);
+    /* call the application that new data arrived */
+  }
+
+  return AfterAssemblyDataReceived(instance);
+}
+
+EipStatus SetAssemblyAttributeSingle(CipInstance *const instance,
+                                     CipMessageRouterRequest *const message_router_request,
+                                     CipMessageRouterResponse *const message_router_response,
+                                     struct sockaddr *originator_address,
+                                     const int encapsulation_session) {
+  OPENER_TRACE_INFO(" setAttribute %d\n",
+                    message_router_request->request_path.attribute_number);
+
+  const EipUint8 *const router_request_data = message_router_request->data;
+
+  message_router_response->data_length = 0;
+  message_router_response->reply_service =
+    (0x80 | message_router_request->service);
+  message_router_response->general_status = kCipErrorAttributeNotSupported;
+  message_router_response->size_of_additional_status = 0;
+
+  CipAttributeStruct *attribute = GetCipAttribute(instance,
+                                                  message_router_request->request_path.attribute_number);
+
+  if( (attribute != NULL) &&
+      (3 == message_router_request->request_path.attribute_number) ) {
+    if(attribute->data != NULL) {
+      CipByteArray *data = (CipByteArray *) attribute->data;
+
+      /* TODO: check for ATTRIBUTE_SET/GETABLE MASK */
+      if( true == IsConnectedOutputAssembly(instance->instance_number) ) {
+        OPENER_TRACE_WARN(
+          "Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r");
+        message_router_response->general_status = kCipErrorAttributeNotSetable;
+      }
+      else{
+        if(message_router_request->request_path_size < data->length) {
+          OPENER_TRACE_INFO(
+            "Assembly setAssemblyAttributeSingle: not enough data received.\r\n");
+          message_router_response->general_status = kCipErrorNotEnoughData;
+        }
+        else{
+          if(message_router_request->request_path_size > data->length) {
+            OPENER_TRACE_INFO(
+              "Assembly setAssemblyAttributeSingle: too much data received.\r\n");
+            message_router_response->general_status = kCipErrorTooMuchData;
+          }
+          else{
+            memcpy(data->data, router_request_data, data->length);
+
+            if(AfterAssemblyDataReceived(instance) != kEipStatusOk) {
+              /* punt early without updating the status... though I don't know
+               * how much this helps us here, as the attribute's data has already
+               * been overwritten.
+               *
+               * however this is the task of the application side which will
+               * take the data. In addition we have to inform the sender that the
+               * data was not ok.
+               */
+              message_router_response->general_status =
+                kCipErrorInvalidAttributeValue;
+            }
+            else{
+              message_router_response->general_status = kCipErrorSuccess;
+            }
+          }
+        }
+      }
+    }
+    else{
+      /* the attribute was zero we are a heartbeat assembly */
+      message_router_response->general_status = kCipErrorTooMuchData;
+    }
+  }
+
+  if( (attribute != NULL) &&
+      (4 == message_router_request->request_path.attribute_number) ) {
+    message_router_response->general_status = kCipErrorAttributeNotSetable;
+  }
+
+  return kEipStatusOkSend;
+}

+ 97 - 97
source/src/cip/cipclass3connection.c

@@ -1,97 +1,97 @@
-/*******************************************************************************
- * Copyright (c) 2011, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-
-#include <string.h>
-
-#include "cipclass3connection.h"
-
-#include "encap.h"
-
-/**** Global variables ****/
-extern CipConnectionObject explicit_connection_object_pool[
-  OPENER_CIP_NUM_EXPLICIT_CONNS];
-
-CipConnectionObject *GetFreeExplicitConnection(void);
-
-void Class3ConnectionTimeoutHandler(CipConnectionObject *connection_object) {
-  CheckForTimedOutConnectionsAndCloseTCPConnections(connection_object,
-                                                    CloseSessionBySessionHandle);
-  CloseConnection(connection_object);
-}
-
-/**** Implementation ****/
-EipStatus EstablishClass3Connection(
-  CipConnectionObject *RESTRICT const connection_object,
-  EipUint16 *const extended_error) {
-  EipStatus eip_status = kEipStatusOk;
-
-  CipConnectionObject *explicit_connection = GetFreeExplicitConnection();
-
-  if (NULL == explicit_connection) {
-    eip_status = kCipErrorConnectionFailure;
-    *extended_error =
-      kConnectionManagerExtendedStatusCodeErrorNoMoreConnectionsAvailable;
-  } else {
-    ConnectionObjectDeepCopy(explicit_connection, connection_object);
-
-    ConnectionObjectGeneralConfiguration(explicit_connection);
-
-    ConnectionObjectSetInstanceType(explicit_connection,
-                                    kConnectionObjectInstanceTypeExplicitMessaging);
-
-    /* set the connection call backs */
-    explicit_connection->connection_close_function =
-      CloseConnection;
-    /* explicit connection have to be closed on time out*/
-    explicit_connection->connection_timeout_function =
-      Class3ConnectionTimeoutHandler;
-
-    AddNewActiveConnection(explicit_connection);
-  }
-  return eip_status;
-}
-
-/** @brief Searches and returns a free explicit connection slot
- *
- * @return Free explicit connection slot, or NULL if no slot is free
- */
-CipConnectionObject *GetFreeExplicitConnection(void) {
-  for (size_t i = 0; i < OPENER_CIP_NUM_EXPLICIT_CONNS; ++i) {
-    if (ConnectionObjectGetState(&(explicit_connection_object_pool[i]) ) ==
-        kConnectionObjectStateNonExistent) {
-      return &(explicit_connection_object_pool[i]);
-    }
-  }
-  return NULL;
-}
-
-void InitializeClass3ConnectionData(void) {
-  memset( explicit_connection_object_pool, 0,
-          OPENER_CIP_NUM_EXPLICIT_CONNS * sizeof(CipConnectionObject) );
-}
-
-EipStatus CipClass3ConnectionObjectStateEstablishedHandler(
-  CipConnectionObject *RESTRICT const connection_object,
-  ConnectionObjectState new_state) {
-  switch(new_state) {
-    case kConnectionObjectStateNonExistent:
-      ConnectionObjectInitializeEmpty(connection_object);
-      ConnectionObjectSetState(connection_object, new_state);
-      return kEipStatusOk;
-    default: return kEipStatusError;
-  }
-}
-
-EipStatus CipClass3ConnectionObjectStateNonExistentHandler(
-  CipConnectionObject *RESTRICT const connection_object,
-  ConnectionObjectState new_state) {
-  switch(new_state) {
-    case kConnectionObjectStateEstablished:
-      ConnectionObjectSetState(connection_object, new_state);
-      return kEipStatusOk;
-    default: return kEipStatusError;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2011, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "cipclass3connection.h"
+
+#include "encap.h"
+
+/**** Global variables ****/
+extern CipConnectionObject explicit_connection_object_pool[
+  OPENER_CIP_NUM_EXPLICIT_CONNS];
+
+CipConnectionObject *GetFreeExplicitConnection(void);
+
+void Class3ConnectionTimeoutHandler(CipConnectionObject *connection_object) {
+  CheckForTimedOutConnectionsAndCloseTCPConnections(connection_object,
+                                                    CloseSessionBySessionHandle);
+  CloseConnection(connection_object);
+}
+
+/**** Implementation ****/
+EipStatus EstablishClass3Connection(
+  CipConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error) {
+  EipStatus eip_status = kEipStatusOk;
+
+  CipConnectionObject *explicit_connection = GetFreeExplicitConnection();
+
+  if (NULL == explicit_connection) {
+    eip_status = kCipErrorConnectionFailure;
+    *extended_error =
+      kConnectionManagerExtendedStatusCodeErrorNoMoreConnectionsAvailable;
+  } else {
+    ConnectionObjectDeepCopy(explicit_connection, connection_object);
+
+    ConnectionObjectGeneralConfiguration(explicit_connection);
+
+    ConnectionObjectSetInstanceType(explicit_connection,
+                                    kConnectionObjectInstanceTypeExplicitMessaging);
+
+    /* set the connection call backs */
+    explicit_connection->connection_close_function =
+      CloseConnection;
+    /* explicit connection have to be closed on time out*/
+    explicit_connection->connection_timeout_function =
+      Class3ConnectionTimeoutHandler;
+
+    AddNewActiveConnection(explicit_connection);
+  }
+  return eip_status;
+}
+
+/** @brief Searches and returns a free explicit connection slot
+ *
+ * @return Free explicit connection slot, or NULL if no slot is free
+ */
+CipConnectionObject *GetFreeExplicitConnection(void) {
+  for (size_t i = 0; i < OPENER_CIP_NUM_EXPLICIT_CONNS; ++i) {
+    if (ConnectionObjectGetState(&(explicit_connection_object_pool[i]) ) ==
+        kConnectionObjectStateNonExistent) {
+      return &(explicit_connection_object_pool[i]);
+    }
+  }
+  return NULL;
+}
+
+void InitializeClass3ConnectionData(void) {
+  memset( explicit_connection_object_pool, 0,
+          OPENER_CIP_NUM_EXPLICIT_CONNS * sizeof(CipConnectionObject) );
+}
+
+EipStatus CipClass3ConnectionObjectStateEstablishedHandler(
+  CipConnectionObject *RESTRICT const connection_object,
+  ConnectionObjectState new_state) {
+  switch(new_state) {
+    case kConnectionObjectStateNonExistent:
+      ConnectionObjectInitializeEmpty(connection_object);
+      ConnectionObjectSetState(connection_object, new_state);
+      return kEipStatusOk;
+    default: return kEipStatusError;
+  }
+}
+
+EipStatus CipClass3ConnectionObjectStateNonExistentHandler(
+  CipConnectionObject *RESTRICT const connection_object,
+  ConnectionObjectState new_state) {
+  switch(new_state) {
+    case kConnectionObjectStateEstablished:
+      ConnectionObjectSetState(connection_object, new_state);
+      return kEipStatusOk;
+    default: return kEipStatusError;
+  }
+}

+ 62 - 62
source/src/cip/cipclass3connection.h

@@ -1,62 +1,62 @@
-/*******************************************************************************
- * Copyright (c) 2011, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-
-#ifndef OPENER_CIPCLASS3CONNECTION_H_
-#define OPENER_CIPCLASS3CONNECTION_H_
-
-/** @file cipclass3connection.h
- *  @brief CIP Class 3 connection
- *   * Explicit Connection Object State Transition Diagram
- * ----------------------------------------------
- * @dot
- *   digraph ExplicitConnectionObjectStateTransition {
- *     A[label="Any State"]
- *     N[label="Non-existent"]
- *     D[label="Deferred Delete"]
- *     E[label="Established"]
- *
- *     A->N [label="Delete"]
- *     N->E [label="Open Explicit Messaging Connection Response"]
- *     E->N [label="Delete or inactivity time-out"]
- *     E->E [label="Get/Set/Apply Attribute, Reset, Message Produced/Consumed"]
- *     E->D [label="Inactivity time-out and deferred delete set"]
- *     D->N [label="Delete"]
- *   }
- * @enddot
- */
-
-#include "opener_api.h"
-#include "cipconnectionmanager.h"
-#include "cipconnectionobject.h"
-
-typedef EipStatus (*CipConnectionStateHandler)(CipConnectionObject *RESTRICT
-                                               const connection_object,
-                                               ConnectionObjectState new_state);
-
-EipStatus CipClass3ConnectionObjectStateEstablishedHandler(
-  CipConnectionObject *RESTRICT const connection_object,
-  ConnectionObjectState new_state);
-
-/** @brief Check if Class3 connection is available and if yes setup all data.
- *
- * This function can be called after all data has been parsed from the forward open request
- * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
- * @param extended_error the extended error code in case an error happened
- * @return general status on the establishment
- *    - kEipStatusOk ... on success
- *    - On an error the general status code to be put into the response
- */
-EipStatus EstablishClass3Connection(
-  CipConnectionObject *RESTRICT const connection_object,
-  EipUint16 *const extended_error);
-
-/** @brief Initializes the explicit connections mechanism
- *
- *  Prepares the available explicit connection slots for use at the start of the OpENer
- */
-void InitializeClass3ConnectionData(void);
-
-#endif /* OPENER_CIPCLASS3CONNECTION_H_ */
+/*******************************************************************************
+ * Copyright (c) 2011, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef OPENER_CIPCLASS3CONNECTION_H_
+#define OPENER_CIPCLASS3CONNECTION_H_
+
+/** @file cipclass3connection.h
+ *  @brief CIP Class 3 connection
+ *   * Explicit Connection Object State Transition Diagram
+ * ----------------------------------------------
+ * @dot
+ *   digraph ExplicitConnectionObjectStateTransition {
+ *     A[label="Any State"]
+ *     N[label="Non-existent"]
+ *     D[label="Deferred Delete"]
+ *     E[label="Established"]
+ *
+ *     A->N [label="Delete"]
+ *     N->E [label="Open Explicit Messaging Connection Response"]
+ *     E->N [label="Delete or inactivity time-out"]
+ *     E->E [label="Get/Set/Apply Attribute, Reset, Message Produced/Consumed"]
+ *     E->D [label="Inactivity time-out and deferred delete set"]
+ *     D->N [label="Delete"]
+ *   }
+ * @enddot
+ */
+
+#include "opener_api.h"
+#include "cipconnectionmanager.h"
+#include "cipconnectionobject.h"
+
+typedef EipStatus (*CipConnectionStateHandler)(CipConnectionObject *RESTRICT
+                                               const connection_object,
+                                               ConnectionObjectState new_state);
+
+EipStatus CipClass3ConnectionObjectStateEstablishedHandler(
+  CipConnectionObject *RESTRICT const connection_object,
+  ConnectionObjectState new_state);
+
+/** @brief Check if Class3 connection is available and if yes setup all data.
+ *
+ * This function can be called after all data has been parsed from the forward open request
+ * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
+ * @param extended_error the extended error code in case an error happened
+ * @return general status on the establishment
+ *    - kEipStatusOk ... on success
+ *    - On an error the general status code to be put into the response
+ */
+EipStatus EstablishClass3Connection(
+  CipConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error);
+
+/** @brief Initializes the explicit connections mechanism
+ *
+ *  Prepares the available explicit connection slots for use at the start of the OpENer
+ */
+void InitializeClass3ConnectionData(void);
+
+#endif /* OPENER_CIPCLASS3CONNECTION_H_ */

+ 996 - 996
source/src/cip/cipioconnection.c

@@ -1,996 +1,996 @@
-/*******************************************************************************
- * Copyright (c) 2011, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-
-#include <string.h>
-#include <stdbool.h>
-
-#include "cipioconnection.h"
-
-#include "generic_networkhandler.h"
-#include "cipconnectionmanager.h"
-#include "cipassembly.h"
-#include "cipidentity.h"
-#include "ciptcpipinterface.h"
-#include "cipcommon.h"
-#include "appcontype.h"
-#include "cpf.h"
-#include "trace.h"
-#include "endianconv.h"
-
-
-/*The port to be used per default for I/O messages on UDP.*/
-const int kOpenerEipIoUdpPort = 0x08AE;
-
-/* producing multicast connection have to consider the rules that apply for
- * application connection types.
- */
-EipStatus OpenProducingMulticastConnection(
-  CipConnectionObject *connection_object,
-  CipCommonPacketFormatData *common_packet_format_data);
-
-EipStatus OpenMulticastConnection(
-  UdpCommuncationDirection direction,
-  CipConnectionObject *connection_object,
-  CipCommonPacketFormatData *common_packet_format_data);
-
-EipStatus OpenConsumingPointToPointConnection(
-  CipConnectionObject *const connection_object,
-  CipCommonPacketFormatData *const common_packet_format_data);
-
-EipStatus OpenProducingPointToPointConnection(
-  CipConnectionObject *connection_object,
-  CipCommonPacketFormatData *common_packet_format_data);
-
-EipUint16 HandleConfigData(CipConnectionObject *connection_object);
-
-/* Regularly close the IO connection. If it is an exclusive owner or input only
- * connection and in charge of the connection a new owner will be searched
- */
-void CloseIoConnection(CipConnectionObject *connection_object);
-
-void HandleIoConnectionTimeOut(CipConnectionObject *connection_object);
-
-/** @brief  Send the data from the produced CIP Object of the connection via the socket of the connection object
- *   on UDP.
- *      @param connection_object  pointer to the connection object
- *      @return status  EIP_OK .. success
- *                     EIP_ERROR .. error
- */
-EipStatus SendConnectedData(CipConnectionObject *connection_object);
-
-EipStatus HandleReceivedIoConnectionData(
-  CipConnectionObject *connection_object,
-  const EipUint8 *data,
-  EipUint16 data_length);
-
-/**** Global variables ****/
-EipUint8 *g_config_data_buffer = NULL; /**< buffers for the config data coming with a forward open request. */
-unsigned int g_config_data_length = 0; /**< length of g_config_data_buffer. Initialized with 0 */
-
-EipUint32 g_run_idle_state = 0; /**< buffer for holding the run idle information. */
-
-EipUint16 ProcessProductionInhibitTime(CipConnectionObject *io_connection_object)
-{
-  if ( kConnectionObjectTransportClassTriggerProductionTriggerCyclic
-       == ConnectionObjectGetTransportClassTriggerProductionTrigger(
-         io_connection_object) ) {
-    if ( 256 ==
-         ConnectionObjectGetProductionInhibitTime(io_connection_object) ) {
-      OPENER_TRACE_INFO("No PIT segment available\n");
-      /* there was no PIT segment in the connection path; set PIT to one fourth of RPI */
-      ConnectionObjectSetProductionInhibitTime(io_connection_object,
-                                               ConnectionObjectGetTToORequestedPacketInterval(
-                                                 io_connection_object)
-                                               / 4000);
-    } else {
-      /* If a production inhibit time is provided, it needs to be smaller than the Requested Packet Interval */
-      if ( ConnectionObjectGetProductionInhibitTime(io_connection_object)
-           > (ConnectionObjectGetTToORequestedPacketInterval(
-                io_connection_object)
-              / 1000) ) {
-        /* see section C-1.4.3.3 */
-        return kConnectionManagerExtendedStatusCodeRpiNotSupported; /**< RPI not supported. Extended Error code deprecated */
-      }
-    }
-  }
-  return kConnectionManagerExtendedStatusCodeSuccess;
-}
-
-void SetIoConnectionCallbacks(CipConnectionObject *const io_connection_object) {
-  io_connection_object->connection_close_function = CloseIoConnection;
-  io_connection_object->connection_timeout_function = HandleIoConnectionTimeOut;
-  io_connection_object->connection_send_data_function = SendConnectedData;
-  io_connection_object->connection_receive_data_function =
-    HandleReceivedIoConnectionData;
-}
-
-EipUint16 SetupIoConnectionOriginatorToTargetConnectionPoint(
-  CipConnectionObject *const io_connection_object,
-  CipConnectionObject *const RESTRICT connection_object
-  ) {
-  CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
-  CipInstance *instance = NULL;
-  if ( NULL
-       != ( instance =
-              GetCipInstance(
-                assembly_class,
-                io_connection_object->consumed_path.instance_id) ) ) {
-    /* consuming Connection Point is present */
-    io_connection_object->consuming_instance = instance;
-    io_connection_object->consumed_connection_path_length = 6;
-    /*io_connection_object->consumed_path.class_id =
-       io_connection_object->connection_path.class_id;
-       io_connection_object->consumed_connection_path.instance_number =
-       io_connection_object->connection_path.connection_point[
-        kConnectionPointConsumer];*/
-    io_connection_object->consumed_path.attribute_id_or_connection_point = 3;
-    int data_size = ConnectionObjectGetOToTConnectionSize(io_connection_object);
-    int diff_size = 0;
-
-    /* an assembly object should always have an attribute 3 */
-    CipAttributeStruct *attribute = GetCipAttribute(instance,
-                                                    io_connection_object->consumed_path.attribute_id_or_connection_point);
-    OPENER_ASSERT(attribute != NULL)
-    bool is_heartbeat = ( ( (CipByteArray *) attribute->data )->length == 0 );
-    if ( kConnectionObjectTransportClassTriggerTransportClass1
-         == ConnectionObjectGetTransportClassTriggerTransportClass(
-           io_connection_object) ) {
-      /* class 1 connection */
-      data_size -= 2; /* remove 16-bit sequence count length */
-      diff_size += 2;
-    }
-#ifdef OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER
-    if ( (data_size > 0) && (!is_heartbeat) ) {
-      /* we only have an run idle header if it is not an heartbeat connection */
-      data_size -= 4; /* remove the 4 bytes needed for run/idle header */
-      diff_size += 4;
-    }
-#endif
-    if ( ( (CipByteArray *) attribute->data )->length != data_size ) {
-      /*wrong connection size */
-      connection_object->correct_originator_to_target_size =
-        ( (CipByteArray *) attribute->data )->length + diff_size;
-      return kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionSize;
-    }
-  } else {
-    return kConnectionManagerExtendedStatusCodeInvalidConsumingApplicationPath;
-  }
-  return kConnectionManagerExtendedStatusCodeSuccess;
-}
-
-EipUint16 SetupIoConnectionTargetToOriginatorConnectionPoint(
-  CipConnectionObject *const io_connection_object,
-  CipConnectionObject *const RESTRICT connection_object
-  ) {
-  DoublyLinkedListNode *node = connection_list.first;
-  while (NULL != node &&
-         kConnectionObjectConnectionTypeMulticast ==
-         ConnectionObjectGetTToOConnectionType(io_connection_object) ) {
-    CipConnectionObject *iterator = node->data;
-    if(io_connection_object->produced_path.instance_id ==
-       iterator->produced_path.instance_id) {
-      //Check parameters
-      if( ConnectionObjectGetTToORequestedPacketInterval(io_connection_object)
-          !=
-          ConnectionObjectGetTToORequestedPacketInterval(iterator) ) {
-        return kConnectionManagerExtendedStatusCodeErrorRpiValuesNotAcceptable;
-      }
-      if( ConnectionObjectGetTToOConnectionSizeType(
-            io_connection_object) !=
-          ConnectionObjectGetTToOConnectionSizeType(
-            iterator) ) {
-        return
-          kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionFixVar;
-      }
-      if ( ConnectionObjectGetTToOPriority(io_connection_object) !=
-           ConnectionObjectGetTToOPriority(iterator) ) {
-        return
-          kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionPriority;
-      }
-
-      if( ConnectionObjectGetTransportClassTriggerTransportClass(
-            io_connection_object) !=
-          ConnectionObjectGetTransportClassTriggerTransportClass(iterator) ) {
-        return kConnectionManagerExtendedStatusCodeMismatchedTransportClass;
-      }
-
-
-      if( ConnectionObjectGetTransportClassTriggerProductionTrigger(
-            io_connection_object) !=
-          ConnectionObjectGetTransportClassTriggerProductionTrigger(iterator) )
-      {
-        return
-          kConnectionManagerExtendedStatusCodeMismatchedTToOProductionTrigger;
-      }
-
-      if( ConnectionObjectGetProductionInhibitTime(io_connection_object) !=
-          ConnectionObjectGetProductionInhibitTime(iterator) ) {
-        return
-          kConnectionManagerExtendedStatusCodeMismatchedTToOProductionInhibitTimeSegment;
-      }
-
-    }
-
-    node = node->next;
-  }
-
-  /*setup producer side*/
-  CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
-  CipInstance *instance = NULL;
-  if ( NULL
-       != ( instance =
-              GetCipInstance(
-                assembly_class,
-                io_connection_object->produced_path.instance_id) ) ) {
-
-    io_connection_object->producing_instance = instance;
-    int data_size = ConnectionObjectGetTToOConnectionSize(io_connection_object);
-    int diff_size = 0;
-    /* an assembly object should always have an attribute 3 */
-    io_connection_object->produced_path.attribute_id_or_connection_point = 3;
-    CipAttributeStruct *attribute = GetCipAttribute(instance,
-                                                    io_connection_object->produced_path.attribute_id_or_connection_point);
-    OPENER_ASSERT(attribute != NULL)
-    bool is_heartbeat = ( ( (CipByteArray *) attribute->data )->length == 0 );
-    if ( kConnectionObjectTransportClassTriggerTransportClass1 ==
-         ConnectionObjectGetTransportClassTriggerTransportClass(
-           io_connection_object) ) {
-      /* class 1 connection */
-      data_size -= 2; /* remove 16-bit sequence count length */
-      diff_size += 2;
-    }
-#ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
-    if ( (data_size > 0) && (!is_heartbeat) ) {
-      /* we only have an run idle header if it is not an heartbeat connection */
-      data_size -= 4; /* remove the 4 bytes needed for run/idle header */
-      diff_size += 4;
-    }
-#endif
-    if ( ( (CipByteArray *) attribute->data )->length != data_size ) {
-      /*wrong connection size*/
-      connection_object->correct_target_to_originator_size =
-        ( (CipByteArray *) attribute->data )->length + diff_size;
-      return kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionSize;
-    }
-  } else {
-    return kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
-  }
-  return kConnectionManagerExtendedStatusCodeSuccess;
-}
-
-/** @brief Establishes a new IO Type 1 Connection
- *
- * This function needs the guarantee that no Null request will be passed to it.
- * It will generate a new IO connection based on the data parsed in the Forward Open service
- *
- * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
- * @param extended_error the extended error code in case an error happened
- * @return general status on the establishment
- *    - kEipStatusOk ... on success
- *    - On an error the general status code to be put into the response
- */
-EipStatus EstablishIoConnection(
-  CipConnectionObject *RESTRICT const connection_object,
-  EipUint16 *const extended_error
-  ) {
-  EipStatus eip_status = kEipStatusOk;
-
-  CipConnectionObject *io_connection_object = GetIoConnectionForConnectionData(
-    connection_object,
-    extended_error);
-  if(NULL == io_connection_object) {
-    return kCipErrorConnectionFailure;
-  }
-
-  *extended_error = ProcessProductionInhibitTime(io_connection_object);
-
-  if(0 != *extended_error) {
-    return kCipErrorConnectionFailure;
-  }
-
-  SetIoConnectionCallbacks(io_connection_object);
-
-  ConnectionObjectGeneralConfiguration(io_connection_object);
-
-  ConnectionObjectConnectionType originator_to_target_connection_type =
-    ConnectionObjectGetOToTConnectionType(io_connection_object);
-  ConnectionObjectConnectionType target_to_originator_connection_type =
-    ConnectionObjectGetTToOConnectionType(io_connection_object);
-
-  /** Already handled by forward open */
-  OPENER_ASSERT( !(originator_to_target_connection_type ==
-                   kConnectionObjectConnectionTypeNull &&
-                   target_to_originator_connection_type ==
-                   kConnectionObjectConnectionTypeNull) )
-
-  io_connection_object->consuming_instance = NULL;
-  io_connection_object->consumed_connection_path_length = 0;
-  io_connection_object->producing_instance = NULL;
-  io_connection_object->produced_connection_path_length = 0;
-
-
-  /* we don't need to check for zero as this is handled in the connection path parsing */
-
-  if (originator_to_target_connection_type !=
-      kConnectionObjectConnectionTypeNull) {                                         /*setup consumer side*/
-    *extended_error = SetupIoConnectionOriginatorToTargetConnectionPoint(
-      io_connection_object,
-      connection_object);
-    if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
-      return kCipErrorConnectionFailure;
-    }
-  }
-
-
-  if (target_to_originator_connection_type !=
-      kConnectionObjectConnectionTypeNull) {                                         /*setup producer side*/
-    *extended_error = SetupIoConnectionTargetToOriginatorConnectionPoint(
-      io_connection_object,
-      connection_object);
-    if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
-      return kCipErrorConnectionFailure;
-    }
-  }
-
-
-  if (NULL != g_config_data_buffer) { /* config data has been sent with this forward open request */
-    *extended_error = HandleConfigData(io_connection_object);
-    if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
-      return kCipErrorConnectionFailure;
-    }
-  }
-
-  eip_status = OpenCommunicationChannels(io_connection_object);
-  if (kEipStatusOk != eip_status) {
-    *extended_error = 0; /*TODO find out the correct extended error code*/
-    return eip_status;
-  }
-
-  AddNewActiveConnection(io_connection_object);
-  CheckIoConnectionEvent(
-    io_connection_object->consumed_path.instance_id,
-    io_connection_object->produced_path.instance_id,
-    kIoConnectionEventOpened);
-  return eip_status;
-}
-
-/** @brief Open a Point2Point connection dependent on pa_direction.
- *
- * @param connection_object Pointer to registered Object in ConnectionManager.
- * @param common_packet_format_data Index of the connection object
- * @return kEipStatusOk on success, otherwise kEipStatusError
- */
-EipStatus OpenConsumingPointToPointConnection(
-  CipConnectionObject *const connection_object,
-  CipCommonPacketFormatData *const common_packet_format_data
-  ) {
-
-  int j = 0;
-
-  if (common_packet_format_data->address_info_item[0].type_id == 0) { /* it is not used yet */
-    j = 0;
-  } else if (common_packet_format_data->address_info_item[1].type_id == 0) {
-    j = 1;
-  }
-
-  struct sockaddr_in addr =
-  { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(
-      kOpenerEipIoUdpPort) };
-
-  CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
-  int socket = CreateUdpSocket(kUdpCommuncationDirectionConsuming,
-                               &addr,
-                               qos_for_socket);                                            /* the address is only needed for bind used if consuming */
-  if (socket == kEipInvalidSocket) {
-    OPENER_TRACE_ERR(
-      "cannot create UDP socket in OpenPointToPointConnection\n");
-    return kEipStatusError;
-  }
-
-  connection_object->originator_address = addr; /* store the address of the originator for packet scanning */
-  addr.sin_addr.s_addr = INADDR_ANY; /* restore the address */
-  connection_object->socket[kUdpCommuncationDirectionConsuming] = socket;
-
-  common_packet_format_data->address_info_item[j].length = 16;
-  common_packet_format_data->address_info_item[j].type_id =
-    kCipItemIdSocketAddressInfoOriginatorToTarget;
-
-  common_packet_format_data->address_info_item[j].sin_port = addr.sin_port;
-  /*TODO should we add our own address here? */
-  common_packet_format_data->address_info_item[j].sin_addr = addr.sin_addr
-                                                             .s_addr;
-  memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
-  common_packet_format_data->address_info_item[j].sin_family = htons(AF_INET);
-
-  return kEipStatusOk;
-}
-
-EipStatus OpenProducingPointToPointConnection(
-  CipConnectionObject *connection_object,
-  CipCommonPacketFormatData *common_packet_format_data
-  ) {
-  in_port_t port = htons(kOpenerEipIoUdpPort); /* the default port to be used if no port information is part of the forward open request */
-
-  if (kCipItemIdSocketAddressInfoTargetToOriginator
-      == common_packet_format_data->address_info_item[0].type_id) {
-    port = common_packet_format_data->address_info_item[0].sin_port;
-  } else {
-    if (kCipItemIdSocketAddressInfoTargetToOriginator
-        == common_packet_format_data->address_info_item[1].type_id) {
-      port = common_packet_format_data->address_info_item[1].sin_port;
-    }
-  }
-
-  connection_object->remote_address.sin_family = AF_INET;
-  connection_object->remote_address.sin_addr.s_addr = 0; /* we don't know the address of the originate will be set in the IApp_CreateUDPSocket */
-  connection_object->remote_address.sin_port = port;
-
-  CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
-  int socket = CreateUdpSocket(kUdpCommuncationDirectionProducing,
-                               &connection_object->remote_address,
-                               qos_for_socket);                                     /* the address is only needed for bind used if consuming */
-  if (socket == kEipInvalidSocket) {
-    OPENER_TRACE_ERR(
-      "cannot create UDP socket in OpenPointToPointConnection\n");
-    /* *pa_pnExtendedError = 0x0315; miscellaneous*/
-    return kCipErrorConnectionFailure;
-  }
-  connection_object->socket[kUdpCommuncationDirectionProducing] = socket;
-
-  return kEipStatusOk;
-}
-
-EipStatus OpenProducingMulticastConnection(
-  CipConnectionObject *connection_object,
-  CipCommonPacketFormatData *common_packet_format_data
-  ) {
-  CipConnectionObject *existing_connection_object =
-    GetExistingProducerMulticastConnection(
-      connection_object->produced_path.instance_id);
-
-  int j = 0; /* allocate an unused sockaddr struct to use */
-  if (g_common_packet_format_data_item.address_info_item[0].type_id == 0) { /* it is not used yet */
-    j = 0;
-  } else if (g_common_packet_format_data_item.address_info_item[1].type_id
-             == 0) {
-    j = 1;
-  }
-
-  int port = htons(kOpenerEipIoUdpPort);
-  if(kCipItemIdSocketAddressInfoTargetToOriginator !=
-     common_packet_format_data->address_info_item[j].type_id) {
-    port = common_packet_format_data->address_info_item[j].sin_port;
-  }
-
-  common_packet_format_data->address_info_item[j].type_id =
-    kCipItemIdSocketAddressInfoTargetToOriginator;
-
-  if (NULL == existing_connection_object) { /* we are the first connection producing for the given Input Assembly */
-    return OpenMulticastConnection(kUdpCommuncationDirectionProducing,
-                                   connection_object,
-                                   common_packet_format_data);
-  } else {
-    /* we need to inform our originator on the correct connection id */
-    connection_object->cip_produced_connection_id = existing_connection_object
-                                                    ->
-                                                    cip_produced_connection_id;
-  }
-
-  /* we have a connection reuse the data and the socket */
-
-  if (kConnectionObjectInstanceTypeIOExclusiveOwner ==
-      connection_object->instance_type) {
-    /* exclusive owners take the socket and further manage the connection
-     * especially in the case of time outs.
-     */
-    connection_object->socket[kUdpCommuncationDirectionProducing] =
-      existing_connection_object->socket[kUdpCommuncationDirectionProducing];
-    existing_connection_object->socket[kUdpCommuncationDirectionProducing] =
-      kEipInvalidSocket;
-  } else { /* this connection will not produce the data */
-    connection_object->socket[kUdpCommuncationDirectionProducing] =
-      kEipInvalidSocket;
-  }
-
-  common_packet_format_data->address_info_item[j].length = 16;
-
-  connection_object->remote_address.sin_family = AF_INET;
-  connection_object->remote_address.sin_port = common_packet_format_data
-                                               ->address_info_item[j].sin_port
-                                                 = port;
-  connection_object->remote_address.sin_addr.s_addr = common_packet_format_data
-                                                      ->address_info_item[j].
-                                                      sin_addr =
-                                                        g_multicast_configuration
-                                                        .
-                                                        starting_multicast_address;
-  memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
-  common_packet_format_data->address_info_item[j].sin_family = htons(AF_INET);
-
-  return kEipStatusOk;
-}
-
-/** @brief Open a Multicast connection dependent on @p direction.
- *
- * @param direction Flag to indicate if consuming or producing.
- * @param connection_object Pointer to registered Object in ConnectionManager.
- * @param common_packet_format_data Received CPF Data Item.
- * @return kEipStatusOk on success, otherwise kEipStatusError
- */
-EipStatus OpenMulticastConnection(
-  UdpCommuncationDirection direction,
-  CipConnectionObject *connection_object,
-  CipCommonPacketFormatData *common_packet_format_data
-  ) {
-  int j = -1;
-
-  int address_info_item_which_contains_o_to_t = -1;
-  int address_info_item_which_contains_t_to_o = -1;
-
-  if(kCipItemIdSocketAddressInfoOriginatorToTarget
-     == common_packet_format_data->address_info_item[0].type_id) {
-    address_info_item_which_contains_o_to_t = 0;
-  } else if(kCipItemIdSocketAddressInfoOriginatorToTarget
-            == common_packet_format_data->address_info_item[1].type_id) {
-    address_info_item_which_contains_o_to_t = 1;
-  } else {
-    OPENER_TRACE_INFO("No O->T Sockaddr info available\n");
-  }
-
-  if(kCipItemIdSocketAddressInfoTargetToOriginator
-     == common_packet_format_data->address_info_item[0].type_id) {
-    address_info_item_which_contains_t_to_o = 0;
-  } else if(kCipItemIdSocketAddressInfoTargetToOriginator
-            == common_packet_format_data->address_info_item[1].type_id) {
-    address_info_item_which_contains_t_to_o = 1;
-  } else {
-    OPENER_TRACE_INFO("No T->O Sockaddr info available\n");
-  }
-
-  if(kUdpCommuncationDirectionConsuming == direction) {
-    j = address_info_item_which_contains_o_to_t;
-  }
-
-  if(kUdpCommuncationDirectionProducing == direction) {
-    j = address_info_item_which_contains_t_to_o;
-  }
-
-  /*****************/
-
-  if (-1 == j) {
-    OPENER_TRACE_ERR(
-      "no suitable addr info item available / O->T: %d, T->O: %d, Selector: %d, direction: %d\n",
-      address_info_item_which_contains_o_to_t,
-      address_info_item_which_contains_t_to_o,
-      j,
-      direction);
-    return kEipStatusError;
-  }
-
-  if (kCipItemIdSocketAddressInfoTargetToOriginator ==
-      common_packet_format_data->address_info_item[j].type_id) {                                                  /* we are using an unused item initialize it with the default multicast address */
-    common_packet_format_data->address_info_item[j].sin_family = htons(
-      AF_INET);
-    common_packet_format_data->address_info_item[j].sin_port = htons(
-      kOpenerEipIoUdpPort);
-    common_packet_format_data->address_info_item[j].sin_addr =
-      g_multicast_configuration.starting_multicast_address;
-    memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
-    common_packet_format_data->address_info_item[j].length = 16;
-  }
-
-  if (htons(AF_INET)
-      != common_packet_format_data->address_info_item[j].sin_family) {
-    OPENER_TRACE_ERR(
-      "Sockaddr Info Item with wrong sin family value received\n");
-    return kEipStatusError;
-  }
-
-  /* allocate an unused sockaddr struct to use */
-  struct sockaddr_in socket_address = {0};
-  socket_address.sin_family = ntohs(
-    common_packet_format_data->address_info_item[j].sin_family);
-  socket_address.sin_addr.s_addr =
-    common_packet_format_data->address_info_item[j].sin_addr;
-  socket_address.sin_port = common_packet_format_data->address_info_item[j]
-                            .sin_port;
-
-  CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
-  int socket = CreateUdpSocket(direction, &socket_address, qos_for_socket); /* the address is only needed for bind used if consuming */
-  if (socket == kEipInvalidSocket) {
-    OPENER_TRACE_ERR("cannot create UDP socket in OpenMulticastConnection\n");
-    return kEipStatusError;
-  }
-  connection_object->socket[direction] = socket;
-
-  if (direction == kUdpCommuncationDirectionConsuming) {
-    common_packet_format_data->address_info_item[j].type_id =
-      kCipItemIdSocketAddressInfoOriginatorToTarget;
-    connection_object->originator_address = socket_address;
-  } else {
-    common_packet_format_data->address_info_item[j].type_id =
-      kCipItemIdSocketAddressInfoTargetToOriginator;
-    connection_object->remote_address = socket_address;
-  }
-
-  return kEipStatusOk;
-}
-
-EipUint16 HandleConfigData(CipConnectionObject *connection_object) {
-
-  CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
-  EipUint16 connection_manager_status = 0;
-  CipInstance *config_instance = GetCipInstance(
-    assembly_class, connection_object->configuration_path.instance_id);
-
-  if (0 != g_config_data_length) {
-    OPENER_ASSERT(NULL != config_instance)
-    if ( ConnectionWithSameConfigPointExists(
-           connection_object->configuration_path.instance_id) ) {
-      /* there is a connected connection with the same config point
-       * we have to have the same data as already present in the config point*/
-      CipAttributeStruct *attribute_three = GetCipAttribute(
-        config_instance,
-        3);
-      OPENER_ASSERT(NULL != attribute_three)
-      CipByteArray * attribute_three_data =
-        (CipByteArray *) attribute_three->data;
-      OPENER_ASSERT(NULL != attribute_three_data)
-      if (attribute_three_data->length != g_config_data_length) {
-        connection_manager_status =
-          kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
-        OPENER_TRACE_INFO(
-          "Hit an Ownership conflict in cipioconnection.c occurrence 1");
-      } else {
-        /*FIXME check if this is correct */
-        if ( memcmp(attribute_three_data->data, g_config_data_buffer,
-                    g_config_data_length) ) {
-          connection_manager_status =
-            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
-          OPENER_TRACE_INFO(
-            "Hit an Ownership conflict in cipioconnection.c occurrence 2");
-        }
-      }
-    } else {
-      /* put the data on the configuration assembly object with the current
-         design this can be done rather efficiently */
-      if ( kEipStatusOk
-           != NotifyAssemblyConnectedDataReceived(config_instance,
-                                                  g_config_data_buffer,
-                                                  g_config_data_length) ) {
-        OPENER_TRACE_WARN("Configuration data was invalid\n");
-        connection_manager_status =
-          kConnectionManagerExtendedStatusCodeInvalidConfigurationApplicationPath;
-      }
-    }
-  }
-  return connection_manager_status;
-}
-
-void CloseIoConnection(CipConnectionObject *connection_object) {
-
-  CheckIoConnectionEvent(connection_object->consumed_path.instance_id,
-                         connection_object->produced_path.instance_id,
-                         kIoConnectionEventClosed);
-  ConnectionObjectSetState(connection_object,
-                           kConnectionObjectStateNonExistent);
-
-  if ( kConnectionObjectInstanceTypeIOExclusiveOwner ==
-       ConnectionObjectGetInstanceType(connection_object)
-       || kConnectionObjectInstanceTypeIOInputOnly ==
-       ConnectionObjectGetInstanceType(connection_object) ) {
-    if ( ( kConnectionObjectConnectionTypeMulticast
-           == ConnectionObjectGetTToOConnectionType(connection_object) )
-         && (kEipInvalidSocket
-             != connection_object->socket[kUdpCommuncationDirectionProducing]) )
-    {
-      OPENER_TRACE_INFO(
-        "Exclusive Owner or Input Only connection closed - Instance type :%d\n",
-        ConnectionObjectGetInstanceType(connection_object) );
-      CipConnectionObject *next_non_control_master_connection =
-        GetNextNonControlMasterConnection(
-          connection_object->produced_path.instance_id);
-      if (NULL != next_non_control_master_connection) {
-
-        OPENER_TRACE_INFO("Transfer socket ownership\n");
-        next_non_control_master_connection->socket[
-          kUdpCommuncationDirectionProducing] =
-          connection_object->socket[kUdpCommuncationDirectionProducing];
-
-        connection_object->socket[kUdpCommuncationDirectionProducing] =
-          kEipInvalidSocket;
-        /* End */
-
-        memcpy( &(next_non_control_master_connection->remote_address),
-                &(connection_object->remote_address),
-                sizeof(next_non_control_master_connection->remote_address) );
-        next_non_control_master_connection->eip_level_sequence_count_producing
-          =
-            connection_object->eip_level_sequence_count_producing;
-        next_non_control_master_connection->sequence_count_producing =
-          connection_object->sequence_count_producing;
-        next_non_control_master_connection->transmission_trigger_timer =
-          connection_object->transmission_trigger_timer;
-      } else { /* this was the last master connection close all listen only connections listening on the port */
-        CloseAllConnectionsForInputWithSameType(
-          connection_object->produced_path.instance_id,
-          kConnectionObjectInstanceTypeIOListenOnly);
-      }
-    }
-  }
-
-  CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
-    connection_object);
-}
-
-void HandleIoConnectionTimeOut(CipConnectionObject *connection_object) {
-  CheckIoConnectionEvent(connection_object->produced_path.instance_id,
-                         connection_object->consumed_path.instance_id,
-                         kIoConnectionEventTimedOut);
-
-  ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
-  if(connection_object->last_package_watchdog_timer ==
-     connection_object->inactivity_watchdog_timer) {
-    CheckForTimedOutConnectionsAndCloseTCPConnections(connection_object,
-                                                      CloseEncapsulationSessionBySockAddr);
-  }
-
-  if ( kConnectionObjectConnectionTypeMulticast
-       == ConnectionObjectGetTToOConnectionType(connection_object) ) {
-    switch (ConnectionObjectGetInstanceType(connection_object) ) {
-      case kConnectionObjectInstanceTypeIOExclusiveOwner:
-        CloseAllConnectionsForInputWithSameType(
-          connection_object->produced_path.instance_id,
-          kConnectionObjectInstanceTypeIOInputOnly);
-        CloseAllConnectionsForInputWithSameType(
-          connection_object->produced_path.instance_id,
-          kConnectionObjectInstanceTypeIOListenOnly);
-        break;
-      case kConnectionObjectInstanceTypeIOInputOnly:
-        if (kEipInvalidSocket
-            != connection_object->socket[kUdpCommuncationDirectionProducing]) { /* we are the controlling input only connection find a new controller*/
-          CipConnectionObject *next_non_control_master_connection =
-            GetNextNonControlMasterConnection(
-              connection_object->produced_path.instance_id);
-          if (NULL != next_non_control_master_connection) {
-            next_non_control_master_connection->socket[
-              kUdpCommuncationDirectionProducing] =
-              connection_object->socket[kUdpCommuncationDirectionProducing];
-            connection_object->socket[kUdpCommuncationDirectionProducing] =
-              kEipInvalidSocket;
-            next_non_control_master_connection->transmission_trigger_timer =
-              connection_object->transmission_trigger_timer;
-          } else { /* this was the last master connection close all listen only connections listening on the port */
-            CloseAllConnectionsForInputWithSameType(
-              connection_object->produced_path.instance_id,
-              kConnectionObjectInstanceTypeIOListenOnly);
-          }
-        }
-        break;
-      default:
-        break;
-    }
-  }
-
-  ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
-}
-
-EipStatus SendConnectedData(CipConnectionObject *connection_object) {
-
-  /* TODO think of adding an own send buffer to each connection object in order to preset up the whole message on connection opening and just change the variable data items e.g., sequence number */
-
-  CipCommonPacketFormatData *common_packet_format_data =
-    &g_common_packet_format_data_item;
-  /* TODO think on adding a CPF data item to the S_CIP_ConnectionObject in order to remove the code here or even better allocate memory in the connection object for storing the message to send and just change the application data*/
-
-  connection_object->eip_level_sequence_count_producing++;
-
-  /* assembleCPFData */
-  common_packet_format_data->item_count = 2;
-  if ( kConnectionObjectTransportClassTriggerTransportClass0 !=
-       ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
-  {                                                                                /* use Sequenced Address Items if not Connection Class 0 */
-    common_packet_format_data->address_item.type_id =
-      kCipItemIdSequencedAddressItem;
-    common_packet_format_data->address_item.length = 8;
-    common_packet_format_data->address_item.data.sequence_number =
-      connection_object->eip_level_sequence_count_producing;
-  } else {
-    common_packet_format_data->address_item.type_id =
-      kCipItemIdConnectionAddress;
-    common_packet_format_data->address_item.length = 4;
-
-  }
-  common_packet_format_data->address_item.data.connection_identifier =
-    connection_object->cip_produced_connection_id;
-
-  common_packet_format_data->data_item.type_id = kCipItemIdConnectedDataItem;
-
-  CipByteArray *producing_instance_attributes =
-    (CipByteArray *) connection_object->producing_instance->attributes->data;
-  common_packet_format_data->data_item.length = 0;
-
-  /* notify the application that data will be sent immediately after the call */
-  if ( BeforeAssemblyDataSend(connection_object->producing_instance) ) {
-    /* the data has changed increase sequence counter */
-    connection_object->sequence_count_producing++;
-  }
-
-  /* set AddressInfo Items to invalid Type */
-  common_packet_format_data->address_info_item[0].type_id = 0;
-  common_packet_format_data->address_info_item[1].type_id = 0;
-
-  ENIPMessage outgoing_message = {0};
-  InitializeENIPMessage(&outgoing_message);
-  EipUint16 reply_length = AssembleIOMessage(common_packet_format_data,
-                                             &outgoing_message);
-
-
-  outgoing_message.current_message_position -= 2;
-  common_packet_format_data->data_item.length = producing_instance_attributes
-                                                ->length;
-#ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
-  common_packet_format_data->data_item.length += 4;
-#endif /* OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER */
-
-  if (kConnectionObjectTransportClassTriggerTransportClass1 ==
-      ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
-  {
-    common_packet_format_data->data_item.length += 2;
-    AddIntToMessage(common_packet_format_data->data_item.length,
-                    &outgoing_message.current_message_position);
-    AddIntToMessage(connection_object->sequence_count_producing,
-                    &outgoing_message.current_message_position);
-  } else {
-    AddIntToMessage(common_packet_format_data->data_item.length,
-                    &outgoing_message.current_message_position);
-  }
-
-#ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
-  AddDintToMessage( g_run_idle_state,
-                    &(outgoing_message.current_message_position) );
-#endif /* OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER */
-
-  memcpy(outgoing_message.current_message_position,
-         producing_instance_attributes->data,
-         producing_instance_attributes->length);
-
-  outgoing_message.used_message_length +=
-    common_packet_format_data->data_item.length;
-
-  return SendUdpData(
-    &connection_object->remote_address,
-    connection_object->socket[kUdpCommuncationDirectionProducing],
-    outgoing_message.message_buffer, outgoing_message.used_message_length);
-}
-
-EipStatus HandleReceivedIoConnectionData(
-  CipConnectionObject *connection_object,
-  const EipUint8 *data,
-  EipUint16 data_length
-  ) {
-
-  OPENER_TRACE_INFO("Starting data length: %d\n", data_length);
-  bool no_new_data = false;
-  /* check class 1 sequence number*/
-  if (kConnectionObjectTransportClassTriggerTransportClass1 ==
-      ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
-  {
-    EipUint16 sequence_buffer = GetIntFromMessage( &(data) );
-    if ( SEQ_LEQ16(sequence_buffer,
-                   connection_object->sequence_count_consuming) ) {
-      no_new_data = true;
-    }
-    connection_object->sequence_count_consuming = sequence_buffer;
-    data_length -= 2;
-  }
-
-  OPENER_TRACE_INFO("data length after sequence count: %d\n", data_length);
-  if (data_length > 0) {
-    /* we have no heartbeat connection */
-#ifdef OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER
-    EipUint32 nRunIdleBuf = GetDintFromMessage( &(data) );
-    OPENER_TRACE_INFO("Run/Idle handler: 0x%x", nRunIdleBuf);
-    const uint32_t kRunBitMask = 0x0001;
-    if( (kRunBitMask & nRunIdleBuf) == 1 ) {
-      CipIdentitySetExtendedDeviceStatus(kAtLeastOneIoConnectionInRunMode);
-    } else {
-      CipIdentitySetExtendedDeviceStatus(
-        kAtLeastOneIoConnectionEstablishedAllInIdleMode);
-    }
-    if (g_run_idle_state != nRunIdleBuf) {
-      RunIdleChanged(nRunIdleBuf);
-    }
-    g_run_idle_state = nRunIdleBuf;
-    data_length -= 4;
-#endif /* OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER */
-    if(no_new_data) {
-      return kEipStatusOk;
-    }
-
-    if (NotifyAssemblyConnectedDataReceived(
-          connection_object->consuming_instance, (EipUint8 *const)data,
-          data_length) != 0) {
-      return kEipStatusError;
-    }
-  }
-  return kEipStatusOk;
-}
-
-EipStatus OpenCommunicationChannels(CipConnectionObject *connection_object) {
-
-  EipStatus eip_status = kEipStatusOk;
-  /*get pointer to the CPF data, currently we have just one global instance of the struct. This may change in the future*/
-  CipCommonPacketFormatData *common_packet_format_data =
-    &g_common_packet_format_data_item;
-
-  ConnectionObjectConnectionType originator_to_target_connection_type =
-    ConnectionObjectGetOToTConnectionType(connection_object);
-
-  ConnectionObjectConnectionType target_to_originator_connection_type =
-    ConnectionObjectGetTToOConnectionType(connection_object);
-
-  /* open a connection "point to point" or "multicast" based on the ConnectionParameter */
-  if (originator_to_target_connection_type ==
-      kConnectionObjectConnectionTypeMulticast)                                         /* Multicast consuming */
-  {
-    if (OpenMulticastConnection(kUdpCommuncationDirectionConsuming,
-                                connection_object, common_packet_format_data)
-        == kEipStatusError) {
-      OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
-      return kCipErrorConnectionFailure;
-    }
-  } else if (originator_to_target_connection_type ==
-             kConnectionObjectConnectionTypePointToPoint)                                  /* Point to Point consuming */
-  {
-    if (OpenConsumingPointToPointConnection(connection_object,
-                                            common_packet_format_data)
-        == kEipStatusError) {
-      OPENER_TRACE_ERR("error in PointToPoint consuming connection\n");
-      return kCipErrorConnectionFailure;
-    }
-  }
-
-  if (target_to_originator_connection_type ==
-      kConnectionObjectConnectionTypeMulticast)                                         /* Multicast producing */
-  {
-    if (OpenProducingMulticastConnection(connection_object,
-                                         common_packet_format_data)
-        == kEipStatusError) {
-      OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
-      return kCipErrorConnectionFailure;
-    }
-  } else if (target_to_originator_connection_type ==
-             kConnectionObjectConnectionTypePointToPoint)                                  /* Point to Point producing */
-  {
-
-    if (OpenProducingPointToPointConnection(connection_object,
-                                            common_packet_format_data)
-        != kEipStatusOk) {
-      OPENER_TRACE_ERR("error in PointToPoint producing connection\n");
-      return kCipErrorConnectionFailure;
-    }
-  }
-  return eip_status;
-}
-
-void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
-  CipConnectionObject *connection_object) {
-  CloseUdpSocket(
-    connection_object->socket[kUdpCommuncationDirectionConsuming]);
-
-  connection_object->socket[kUdpCommuncationDirectionConsuming] =
-    kEipInvalidSocket;
-
-  CloseUdpSocket(
-    connection_object->socket[kUdpCommuncationDirectionProducing]);
-
-  connection_object->socket[kUdpCommuncationDirectionProducing] =
-    kEipInvalidSocket;
-
-  RemoveFromActiveConnections(connection_object);
-  ConnectionObjectInitializeEmpty(connection_object);
-}
+/*******************************************************************************
+ * Copyright (c) 2011, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdbool.h>
+
+#include "cipioconnection.h"
+
+#include "generic_networkhandler.h"
+#include "cipconnectionmanager.h"
+#include "cipassembly.h"
+#include "cipidentity.h"
+#include "ciptcpipinterface.h"
+#include "cipcommon.h"
+#include "appcontype.h"
+#include "cpf.h"
+#include "trace.h"
+#include "endianconv.h"
+
+
+/*The port to be used per default for I/O messages on UDP.*/
+const int kOpenerEipIoUdpPort = 0x08AE;
+
+/* producing multicast connection have to consider the rules that apply for
+ * application connection types.
+ */
+EipStatus OpenProducingMulticastConnection(
+  CipConnectionObject *connection_object,
+  CipCommonPacketFormatData *common_packet_format_data);
+
+EipStatus OpenMulticastConnection(
+  UdpCommuncationDirection direction,
+  CipConnectionObject *connection_object,
+  CipCommonPacketFormatData *common_packet_format_data);
+
+EipStatus OpenConsumingPointToPointConnection(
+  CipConnectionObject *const connection_object,
+  CipCommonPacketFormatData *const common_packet_format_data);
+
+EipStatus OpenProducingPointToPointConnection(
+  CipConnectionObject *connection_object,
+  CipCommonPacketFormatData *common_packet_format_data);
+
+EipUint16 HandleConfigData(CipConnectionObject *connection_object);
+
+/* Regularly close the IO connection. If it is an exclusive owner or input only
+ * connection and in charge of the connection a new owner will be searched
+ */
+void CloseIoConnection(CipConnectionObject *connection_object);
+
+void HandleIoConnectionTimeOut(CipConnectionObject *connection_object);
+
+/** @brief  Send the data from the produced CIP Object of the connection via the socket of the connection object
+ *   on UDP.
+ *      @param connection_object  pointer to the connection object
+ *      @return status  EIP_OK .. success
+ *                     EIP_ERROR .. error
+ */
+EipStatus SendConnectedData(CipConnectionObject *connection_object);
+
+EipStatus HandleReceivedIoConnectionData(
+  CipConnectionObject *connection_object,
+  const EipUint8 *data,
+  EipUint16 data_length);
+
+/**** Global variables ****/
+EipUint8 *g_config_data_buffer = NULL; /**< buffers for the config data coming with a forward open request. */
+unsigned int g_config_data_length = 0; /**< length of g_config_data_buffer. Initialized with 0 */
+
+EipUint32 g_run_idle_state = 0; /**< buffer for holding the run idle information. */
+
+EipUint16 ProcessProductionInhibitTime(CipConnectionObject *io_connection_object)
+{
+  if ( kConnectionObjectTransportClassTriggerProductionTriggerCyclic
+       == ConnectionObjectGetTransportClassTriggerProductionTrigger(
+         io_connection_object) ) {
+    if ( 256 ==
+         ConnectionObjectGetProductionInhibitTime(io_connection_object) ) {
+      OPENER_TRACE_INFO("No PIT segment available\n");
+      /* there was no PIT segment in the connection path; set PIT to one fourth of RPI */
+      ConnectionObjectSetProductionInhibitTime(io_connection_object,
+                                               ConnectionObjectGetTToORequestedPacketInterval(
+                                                 io_connection_object)
+                                               / 4000);
+    } else {
+      /* If a production inhibit time is provided, it needs to be smaller than the Requested Packet Interval */
+      if ( ConnectionObjectGetProductionInhibitTime(io_connection_object)
+           > (ConnectionObjectGetTToORequestedPacketInterval(
+                io_connection_object)
+              / 1000) ) {
+        /* see section C-1.4.3.3 */
+        return kConnectionManagerExtendedStatusCodeRpiNotSupported; /**< RPI not supported. Extended Error code deprecated */
+      }
+    }
+  }
+  return kConnectionManagerExtendedStatusCodeSuccess;
+}
+
+void SetIoConnectionCallbacks(CipConnectionObject *const io_connection_object) {
+  io_connection_object->connection_close_function = CloseIoConnection;
+  io_connection_object->connection_timeout_function = HandleIoConnectionTimeOut;
+  io_connection_object->connection_send_data_function = SendConnectedData;
+  io_connection_object->connection_receive_data_function =
+    HandleReceivedIoConnectionData;
+}
+
+EipUint16 SetupIoConnectionOriginatorToTargetConnectionPoint(
+  CipConnectionObject *const io_connection_object,
+  CipConnectionObject *const RESTRICT connection_object
+  ) {
+  CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
+  CipInstance *instance = NULL;
+  if ( NULL
+       != ( instance =
+              GetCipInstance(
+                assembly_class,
+                io_connection_object->consumed_path.instance_id) ) ) {
+    /* consuming Connection Point is present */
+    io_connection_object->consuming_instance = instance;
+    io_connection_object->consumed_connection_path_length = 6;
+    /*io_connection_object->consumed_path.class_id =
+       io_connection_object->connection_path.class_id;
+       io_connection_object->consumed_connection_path.instance_number =
+       io_connection_object->connection_path.connection_point[
+        kConnectionPointConsumer];*/
+    io_connection_object->consumed_path.attribute_id_or_connection_point = 3;
+    int data_size = ConnectionObjectGetOToTConnectionSize(io_connection_object);
+    int diff_size = 0;
+
+    /* an assembly object should always have an attribute 3 */
+    CipAttributeStruct *attribute = GetCipAttribute(instance,
+                                                    io_connection_object->consumed_path.attribute_id_or_connection_point);
+    OPENER_ASSERT(attribute != NULL)
+    bool is_heartbeat = ( ( (CipByteArray *) attribute->data )->length == 0 );
+    if ( kConnectionObjectTransportClassTriggerTransportClass1
+         == ConnectionObjectGetTransportClassTriggerTransportClass(
+           io_connection_object) ) {
+      /* class 1 connection */
+      data_size -= 2; /* remove 16-bit sequence count length */
+      diff_size += 2;
+    }
+#ifdef OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER
+    if ( (data_size > 0) && (!is_heartbeat) ) {
+      /* we only have an run idle header if it is not an heartbeat connection */
+      data_size -= 4; /* remove the 4 bytes needed for run/idle header */
+      diff_size += 4;
+    }
+#endif
+    if ( ( (CipByteArray *) attribute->data )->length != data_size ) {
+      /*wrong connection size */
+      connection_object->correct_originator_to_target_size =
+        ( (CipByteArray *) attribute->data )->length + diff_size;
+      return kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionSize;
+    }
+  } else {
+    return kConnectionManagerExtendedStatusCodeInvalidConsumingApplicationPath;
+  }
+  return kConnectionManagerExtendedStatusCodeSuccess;
+}
+
+EipUint16 SetupIoConnectionTargetToOriginatorConnectionPoint(
+  CipConnectionObject *const io_connection_object,
+  CipConnectionObject *const RESTRICT connection_object
+  ) {
+  DoublyLinkedListNode *node = connection_list.first;
+  while (NULL != node &&
+         kConnectionObjectConnectionTypeMulticast ==
+         ConnectionObjectGetTToOConnectionType(io_connection_object) ) {
+    CipConnectionObject *iterator = node->data;
+    if(io_connection_object->produced_path.instance_id ==
+       iterator->produced_path.instance_id) {
+      //Check parameters
+      if( ConnectionObjectGetTToORequestedPacketInterval(io_connection_object)
+          !=
+          ConnectionObjectGetTToORequestedPacketInterval(iterator) ) {
+        return kConnectionManagerExtendedStatusCodeErrorRpiValuesNotAcceptable;
+      }
+      if( ConnectionObjectGetTToOConnectionSizeType(
+            io_connection_object) !=
+          ConnectionObjectGetTToOConnectionSizeType(
+            iterator) ) {
+        return
+          kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionFixVar;
+      }
+      if ( ConnectionObjectGetTToOPriority(io_connection_object) !=
+           ConnectionObjectGetTToOPriority(iterator) ) {
+        return
+          kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionPriority;
+      }
+
+      if( ConnectionObjectGetTransportClassTriggerTransportClass(
+            io_connection_object) !=
+          ConnectionObjectGetTransportClassTriggerTransportClass(iterator) ) {
+        return kConnectionManagerExtendedStatusCodeMismatchedTransportClass;
+      }
+
+
+      if( ConnectionObjectGetTransportClassTriggerProductionTrigger(
+            io_connection_object) !=
+          ConnectionObjectGetTransportClassTriggerProductionTrigger(iterator) )
+      {
+        return
+          kConnectionManagerExtendedStatusCodeMismatchedTToOProductionTrigger;
+      }
+
+      if( ConnectionObjectGetProductionInhibitTime(io_connection_object) !=
+          ConnectionObjectGetProductionInhibitTime(iterator) ) {
+        return
+          kConnectionManagerExtendedStatusCodeMismatchedTToOProductionInhibitTimeSegment;
+      }
+
+    }
+
+    node = node->next;
+  }
+
+  /*setup producer side*/
+  CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
+  CipInstance *instance = NULL;
+  if ( NULL
+       != ( instance =
+              GetCipInstance(
+                assembly_class,
+                io_connection_object->produced_path.instance_id) ) ) {
+
+    io_connection_object->producing_instance = instance;
+    int data_size = ConnectionObjectGetTToOConnectionSize(io_connection_object);
+    int diff_size = 0;
+    /* an assembly object should always have an attribute 3 */
+    io_connection_object->produced_path.attribute_id_or_connection_point = 3;
+    CipAttributeStruct *attribute = GetCipAttribute(instance,
+                                                    io_connection_object->produced_path.attribute_id_or_connection_point);
+    OPENER_ASSERT(attribute != NULL)
+    bool is_heartbeat = ( ( (CipByteArray *) attribute->data )->length == 0 );
+    if ( kConnectionObjectTransportClassTriggerTransportClass1 ==
+         ConnectionObjectGetTransportClassTriggerTransportClass(
+           io_connection_object) ) {
+      /* class 1 connection */
+      data_size -= 2; /* remove 16-bit sequence count length */
+      diff_size += 2;
+    }
+#ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
+    if ( (data_size > 0) && (!is_heartbeat) ) {
+      /* we only have an run idle header if it is not an heartbeat connection */
+      data_size -= 4; /* remove the 4 bytes needed for run/idle header */
+      diff_size += 4;
+    }
+#endif
+    if ( ( (CipByteArray *) attribute->data )->length != data_size ) {
+      /*wrong connection size*/
+      connection_object->correct_target_to_originator_size =
+        ( (CipByteArray *) attribute->data )->length + diff_size;
+      return kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionSize;
+    }
+  } else {
+    return kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
+  }
+  return kConnectionManagerExtendedStatusCodeSuccess;
+}
+
+/** @brief Establishes a new IO Type 1 Connection
+ *
+ * This function needs the guarantee that no Null request will be passed to it.
+ * It will generate a new IO connection based on the data parsed in the Forward Open service
+ *
+ * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
+ * @param extended_error the extended error code in case an error happened
+ * @return general status on the establishment
+ *    - kEipStatusOk ... on success
+ *    - On an error the general status code to be put into the response
+ */
+EipStatus EstablishIoConnection(
+  CipConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error
+  ) {
+  EipStatus eip_status = kEipStatusOk;
+
+  CipConnectionObject *io_connection_object = GetIoConnectionForConnectionData(
+    connection_object,
+    extended_error);
+  if(NULL == io_connection_object) {
+    return kCipErrorConnectionFailure;
+  }
+
+  *extended_error = ProcessProductionInhibitTime(io_connection_object);
+
+  if(0 != *extended_error) {
+    return kCipErrorConnectionFailure;
+  }
+
+  SetIoConnectionCallbacks(io_connection_object);
+
+  ConnectionObjectGeneralConfiguration(io_connection_object);
+
+  ConnectionObjectConnectionType originator_to_target_connection_type =
+    ConnectionObjectGetOToTConnectionType(io_connection_object);
+  ConnectionObjectConnectionType target_to_originator_connection_type =
+    ConnectionObjectGetTToOConnectionType(io_connection_object);
+
+  /** Already handled by forward open */
+  OPENER_ASSERT( !(originator_to_target_connection_type ==
+                   kConnectionObjectConnectionTypeNull &&
+                   target_to_originator_connection_type ==
+                   kConnectionObjectConnectionTypeNull) )
+
+  io_connection_object->consuming_instance = NULL;
+  io_connection_object->consumed_connection_path_length = 0;
+  io_connection_object->producing_instance = NULL;
+  io_connection_object->produced_connection_path_length = 0;
+
+
+  /* we don't need to check for zero as this is handled in the connection path parsing */
+
+  if (originator_to_target_connection_type !=
+      kConnectionObjectConnectionTypeNull) {                                         /*setup consumer side*/
+    *extended_error = SetupIoConnectionOriginatorToTargetConnectionPoint(
+      io_connection_object,
+      connection_object);
+    if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
+      return kCipErrorConnectionFailure;
+    }
+  }
+
+
+  if (target_to_originator_connection_type !=
+      kConnectionObjectConnectionTypeNull) {                                         /*setup producer side*/
+    *extended_error = SetupIoConnectionTargetToOriginatorConnectionPoint(
+      io_connection_object,
+      connection_object);
+    if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
+      return kCipErrorConnectionFailure;
+    }
+  }
+
+
+  if (NULL != g_config_data_buffer) { /* config data has been sent with this forward open request */
+    *extended_error = HandleConfigData(io_connection_object);
+    if (kConnectionManagerExtendedStatusCodeSuccess != *extended_error) {
+      return kCipErrorConnectionFailure;
+    }
+  }
+
+  eip_status = OpenCommunicationChannels(io_connection_object);
+  if (kEipStatusOk != eip_status) {
+    *extended_error = 0; /*TODO find out the correct extended error code*/
+    return eip_status;
+  }
+
+  AddNewActiveConnection(io_connection_object);
+  CheckIoConnectionEvent(
+    io_connection_object->consumed_path.instance_id,
+    io_connection_object->produced_path.instance_id,
+    kIoConnectionEventOpened);
+  return eip_status;
+}
+
+/** @brief Open a Point2Point connection dependent on pa_direction.
+ *
+ * @param connection_object Pointer to registered Object in ConnectionManager.
+ * @param common_packet_format_data Index of the connection object
+ * @return kEipStatusOk on success, otherwise kEipStatusError
+ */
+EipStatus OpenConsumingPointToPointConnection(
+  CipConnectionObject *const connection_object,
+  CipCommonPacketFormatData *const common_packet_format_data
+  ) {
+
+  int j = 0;
+
+  if (common_packet_format_data->address_info_item[0].type_id == 0) { /* it is not used yet */
+    j = 0;
+  } else if (common_packet_format_data->address_info_item[1].type_id == 0) {
+    j = 1;
+  }
+
+  struct sockaddr_in addr =
+  { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(
+      kOpenerEipIoUdpPort) };
+
+  CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
+  int socket = CreateUdpSocket(kUdpCommuncationDirectionConsuming,
+                               &addr,
+                               qos_for_socket);                                            /* the address is only needed for bind used if consuming */
+  if (socket == kEipInvalidSocket) {
+    OPENER_TRACE_ERR(
+      "cannot create UDP socket in OpenPointToPointConnection\n");
+    return kEipStatusError;
+  }
+
+  connection_object->originator_address = addr; /* store the address of the originator for packet scanning */
+  addr.sin_addr.s_addr = INADDR_ANY; /* restore the address */
+  connection_object->socket[kUdpCommuncationDirectionConsuming] = socket;
+
+  common_packet_format_data->address_info_item[j].length = 16;
+  common_packet_format_data->address_info_item[j].type_id =
+    kCipItemIdSocketAddressInfoOriginatorToTarget;
+
+  common_packet_format_data->address_info_item[j].sin_port = addr.sin_port;
+  /*TODO should we add our own address here? */
+  common_packet_format_data->address_info_item[j].sin_addr = addr.sin_addr
+                                                             .s_addr;
+  memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
+  common_packet_format_data->address_info_item[j].sin_family = htons(AF_INET);
+
+  return kEipStatusOk;
+}
+
+EipStatus OpenProducingPointToPointConnection(
+  CipConnectionObject *connection_object,
+  CipCommonPacketFormatData *common_packet_format_data
+  ) {
+  in_port_t port = htons(kOpenerEipIoUdpPort); /* the default port to be used if no port information is part of the forward open request */
+
+  if (kCipItemIdSocketAddressInfoTargetToOriginator
+      == common_packet_format_data->address_info_item[0].type_id) {
+    port = common_packet_format_data->address_info_item[0].sin_port;
+  } else {
+    if (kCipItemIdSocketAddressInfoTargetToOriginator
+        == common_packet_format_data->address_info_item[1].type_id) {
+      port = common_packet_format_data->address_info_item[1].sin_port;
+    }
+  }
+
+  connection_object->remote_address.sin_family = AF_INET;
+  connection_object->remote_address.sin_addr.s_addr = 0; /* we don't know the address of the originate will be set in the IApp_CreateUDPSocket */
+  connection_object->remote_address.sin_port = port;
+
+  CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
+  int socket = CreateUdpSocket(kUdpCommuncationDirectionProducing,
+                               &connection_object->remote_address,
+                               qos_for_socket);                                     /* the address is only needed for bind used if consuming */
+  if (socket == kEipInvalidSocket) {
+    OPENER_TRACE_ERR(
+      "cannot create UDP socket in OpenPointToPointConnection\n");
+    /* *pa_pnExtendedError = 0x0315; miscellaneous*/
+    return kCipErrorConnectionFailure;
+  }
+  connection_object->socket[kUdpCommuncationDirectionProducing] = socket;
+
+  return kEipStatusOk;
+}
+
+EipStatus OpenProducingMulticastConnection(
+  CipConnectionObject *connection_object,
+  CipCommonPacketFormatData *common_packet_format_data
+  ) {
+  CipConnectionObject *existing_connection_object =
+    GetExistingProducerMulticastConnection(
+      connection_object->produced_path.instance_id);
+
+  int j = 0; /* allocate an unused sockaddr struct to use */
+  if (g_common_packet_format_data_item.address_info_item[0].type_id == 0) { /* it is not used yet */
+    j = 0;
+  } else if (g_common_packet_format_data_item.address_info_item[1].type_id
+             == 0) {
+    j = 1;
+  }
+
+  int port = htons(kOpenerEipIoUdpPort);
+  if(kCipItemIdSocketAddressInfoTargetToOriginator !=
+     common_packet_format_data->address_info_item[j].type_id) {
+    port = common_packet_format_data->address_info_item[j].sin_port;
+  }
+
+  common_packet_format_data->address_info_item[j].type_id =
+    kCipItemIdSocketAddressInfoTargetToOriginator;
+
+  if (NULL == existing_connection_object) { /* we are the first connection producing for the given Input Assembly */
+    return OpenMulticastConnection(kUdpCommuncationDirectionProducing,
+                                   connection_object,
+                                   common_packet_format_data);
+  } else {
+    /* we need to inform our originator on the correct connection id */
+    connection_object->cip_produced_connection_id = existing_connection_object
+                                                    ->
+                                                    cip_produced_connection_id;
+  }
+
+  /* we have a connection reuse the data and the socket */
+
+  if (kConnectionObjectInstanceTypeIOExclusiveOwner ==
+      connection_object->instance_type) {
+    /* exclusive owners take the socket and further manage the connection
+     * especially in the case of time outs.
+     */
+    connection_object->socket[kUdpCommuncationDirectionProducing] =
+      existing_connection_object->socket[kUdpCommuncationDirectionProducing];
+    existing_connection_object->socket[kUdpCommuncationDirectionProducing] =
+      kEipInvalidSocket;
+  } else { /* this connection will not produce the data */
+    connection_object->socket[kUdpCommuncationDirectionProducing] =
+      kEipInvalidSocket;
+  }
+
+  common_packet_format_data->address_info_item[j].length = 16;
+
+  connection_object->remote_address.sin_family = AF_INET;
+  connection_object->remote_address.sin_port = common_packet_format_data
+                                               ->address_info_item[j].sin_port
+                                                 = port;
+  connection_object->remote_address.sin_addr.s_addr = common_packet_format_data
+                                                      ->address_info_item[j].
+                                                      sin_addr =
+                                                        g_multicast_configuration
+                                                        .
+                                                        starting_multicast_address;
+  memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
+  common_packet_format_data->address_info_item[j].sin_family = htons(AF_INET);
+
+  return kEipStatusOk;
+}
+
+/** @brief Open a Multicast connection dependent on @p direction.
+ *
+ * @param direction Flag to indicate if consuming or producing.
+ * @param connection_object Pointer to registered Object in ConnectionManager.
+ * @param common_packet_format_data Received CPF Data Item.
+ * @return kEipStatusOk on success, otherwise kEipStatusError
+ */
+EipStatus OpenMulticastConnection(
+  UdpCommuncationDirection direction,
+  CipConnectionObject *connection_object,
+  CipCommonPacketFormatData *common_packet_format_data
+  ) {
+  int j = -1;
+
+  int address_info_item_which_contains_o_to_t = -1;
+  int address_info_item_which_contains_t_to_o = -1;
+
+  if(kCipItemIdSocketAddressInfoOriginatorToTarget
+     == common_packet_format_data->address_info_item[0].type_id) {
+    address_info_item_which_contains_o_to_t = 0;
+  } else if(kCipItemIdSocketAddressInfoOriginatorToTarget
+            == common_packet_format_data->address_info_item[1].type_id) {
+    address_info_item_which_contains_o_to_t = 1;
+  } else {
+    OPENER_TRACE_INFO("No O->T Sockaddr info available\n");
+  }
+
+  if(kCipItemIdSocketAddressInfoTargetToOriginator
+     == common_packet_format_data->address_info_item[0].type_id) {
+    address_info_item_which_contains_t_to_o = 0;
+  } else if(kCipItemIdSocketAddressInfoTargetToOriginator
+            == common_packet_format_data->address_info_item[1].type_id) {
+    address_info_item_which_contains_t_to_o = 1;
+  } else {
+    OPENER_TRACE_INFO("No T->O Sockaddr info available\n");
+  }
+
+  if(kUdpCommuncationDirectionConsuming == direction) {
+    j = address_info_item_which_contains_o_to_t;
+  }
+
+  if(kUdpCommuncationDirectionProducing == direction) {
+    j = address_info_item_which_contains_t_to_o;
+  }
+
+  /*****************/
+
+  if (-1 == j) {
+    OPENER_TRACE_ERR(
+      "no suitable addr info item available / O->T: %d, T->O: %d, Selector: %d, direction: %d\n",
+      address_info_item_which_contains_o_to_t,
+      address_info_item_which_contains_t_to_o,
+      j,
+      direction);
+    return kEipStatusError;
+  }
+
+  if (kCipItemIdSocketAddressInfoTargetToOriginator ==
+      common_packet_format_data->address_info_item[j].type_id) {                                                  /* we are using an unused item initialize it with the default multicast address */
+    common_packet_format_data->address_info_item[j].sin_family = htons(
+      AF_INET);
+    common_packet_format_data->address_info_item[j].sin_port = htons(
+      kOpenerEipIoUdpPort);
+    common_packet_format_data->address_info_item[j].sin_addr =
+      g_multicast_configuration.starting_multicast_address;
+    memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
+    common_packet_format_data->address_info_item[j].length = 16;
+  }
+
+  if (htons(AF_INET)
+      != common_packet_format_data->address_info_item[j].sin_family) {
+    OPENER_TRACE_ERR(
+      "Sockaddr Info Item with wrong sin family value received\n");
+    return kEipStatusError;
+  }
+
+  /* allocate an unused sockaddr struct to use */
+  struct sockaddr_in socket_address = {0};
+  socket_address.sin_family = ntohs(
+    common_packet_format_data->address_info_item[j].sin_family);
+  socket_address.sin_addr.s_addr =
+    common_packet_format_data->address_info_item[j].sin_addr;
+  socket_address.sin_port = common_packet_format_data->address_info_item[j]
+                            .sin_port;
+
+  CipUsint qos_for_socket = ConnectionObjectGetTToOPriority(connection_object);
+  int socket = CreateUdpSocket(direction, &socket_address, qos_for_socket); /* the address is only needed for bind used if consuming */
+  if (socket == kEipInvalidSocket) {
+    OPENER_TRACE_ERR("cannot create UDP socket in OpenMulticastConnection\n");
+    return kEipStatusError;
+  }
+  connection_object->socket[direction] = socket;
+
+  if (direction == kUdpCommuncationDirectionConsuming) {
+    common_packet_format_data->address_info_item[j].type_id =
+      kCipItemIdSocketAddressInfoOriginatorToTarget;
+    connection_object->originator_address = socket_address;
+  } else {
+    common_packet_format_data->address_info_item[j].type_id =
+      kCipItemIdSocketAddressInfoTargetToOriginator;
+    connection_object->remote_address = socket_address;
+  }
+
+  return kEipStatusOk;
+}
+
+EipUint16 HandleConfigData(CipConnectionObject *connection_object) {
+
+  CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
+  EipUint16 connection_manager_status = 0;
+  CipInstance *config_instance = GetCipInstance(
+    assembly_class, connection_object->configuration_path.instance_id);
+
+  if (0 != g_config_data_length) {
+    OPENER_ASSERT(NULL != config_instance)
+    if ( ConnectionWithSameConfigPointExists(
+           connection_object->configuration_path.instance_id) ) {
+      /* there is a connected connection with the same config point
+       * we have to have the same data as already present in the config point*/
+      CipAttributeStruct *attribute_three = GetCipAttribute(
+        config_instance,
+        3);
+      OPENER_ASSERT(NULL != attribute_three)
+      CipByteArray * attribute_three_data =
+        (CipByteArray *) attribute_three->data;
+      OPENER_ASSERT(NULL != attribute_three_data)
+      if (attribute_three_data->length != g_config_data_length) {
+        connection_manager_status =
+          kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
+        OPENER_TRACE_INFO(
+          "Hit an Ownership conflict in cipioconnection.c occurrence 1");
+      } else {
+        /*FIXME check if this is correct */
+        if ( memcmp(attribute_three_data->data, g_config_data_buffer,
+                    g_config_data_length) ) {
+          connection_manager_status =
+            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
+          OPENER_TRACE_INFO(
+            "Hit an Ownership conflict in cipioconnection.c occurrence 2");
+        }
+      }
+    } else {
+      /* put the data on the configuration assembly object with the current
+         design this can be done rather efficiently */
+      if ( kEipStatusOk
+           != NotifyAssemblyConnectedDataReceived(config_instance,
+                                                  g_config_data_buffer,
+                                                  g_config_data_length) ) {
+        OPENER_TRACE_WARN("Configuration data was invalid\n");
+        connection_manager_status =
+          kConnectionManagerExtendedStatusCodeInvalidConfigurationApplicationPath;
+      }
+    }
+  }
+  return connection_manager_status;
+}
+
+void CloseIoConnection(CipConnectionObject *connection_object) {
+
+  CheckIoConnectionEvent(connection_object->consumed_path.instance_id,
+                         connection_object->produced_path.instance_id,
+                         kIoConnectionEventClosed);
+  ConnectionObjectSetState(connection_object,
+                           kConnectionObjectStateNonExistent);
+
+  if ( kConnectionObjectInstanceTypeIOExclusiveOwner ==
+       ConnectionObjectGetInstanceType(connection_object)
+       || kConnectionObjectInstanceTypeIOInputOnly ==
+       ConnectionObjectGetInstanceType(connection_object) ) {
+    if ( ( kConnectionObjectConnectionTypeMulticast
+           == ConnectionObjectGetTToOConnectionType(connection_object) )
+         && (kEipInvalidSocket
+             != connection_object->socket[kUdpCommuncationDirectionProducing]) )
+    {
+      OPENER_TRACE_INFO(
+        "Exclusive Owner or Input Only connection closed - Instance type :%d\n",
+        ConnectionObjectGetInstanceType(connection_object) );
+      CipConnectionObject *next_non_control_master_connection =
+        GetNextNonControlMasterConnection(
+          connection_object->produced_path.instance_id);
+      if (NULL != next_non_control_master_connection) {
+
+        OPENER_TRACE_INFO("Transfer socket ownership\n");
+        next_non_control_master_connection->socket[
+          kUdpCommuncationDirectionProducing] =
+          connection_object->socket[kUdpCommuncationDirectionProducing];
+
+        connection_object->socket[kUdpCommuncationDirectionProducing] =
+          kEipInvalidSocket;
+        /* End */
+
+        memcpy( &(next_non_control_master_connection->remote_address),
+                &(connection_object->remote_address),
+                sizeof(next_non_control_master_connection->remote_address) );
+        next_non_control_master_connection->eip_level_sequence_count_producing
+          =
+            connection_object->eip_level_sequence_count_producing;
+        next_non_control_master_connection->sequence_count_producing =
+          connection_object->sequence_count_producing;
+        next_non_control_master_connection->transmission_trigger_timer =
+          connection_object->transmission_trigger_timer;
+      } else { /* this was the last master connection close all listen only connections listening on the port */
+        CloseAllConnectionsForInputWithSameType(
+          connection_object->produced_path.instance_id,
+          kConnectionObjectInstanceTypeIOListenOnly);
+      }
+    }
+  }
+
+  CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
+    connection_object);
+}
+
+void HandleIoConnectionTimeOut(CipConnectionObject *connection_object) {
+  CheckIoConnectionEvent(connection_object->produced_path.instance_id,
+                         connection_object->consumed_path.instance_id,
+                         kIoConnectionEventTimedOut);
+
+  ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
+  if(connection_object->last_package_watchdog_timer ==
+     connection_object->inactivity_watchdog_timer) {
+    CheckForTimedOutConnectionsAndCloseTCPConnections(connection_object,
+                                                      CloseEncapsulationSessionBySockAddr);
+  }
+
+  if ( kConnectionObjectConnectionTypeMulticast
+       == ConnectionObjectGetTToOConnectionType(connection_object) ) {
+    switch (ConnectionObjectGetInstanceType(connection_object) ) {
+      case kConnectionObjectInstanceTypeIOExclusiveOwner:
+        CloseAllConnectionsForInputWithSameType(
+          connection_object->produced_path.instance_id,
+          kConnectionObjectInstanceTypeIOInputOnly);
+        CloseAllConnectionsForInputWithSameType(
+          connection_object->produced_path.instance_id,
+          kConnectionObjectInstanceTypeIOListenOnly);
+        break;
+      case kConnectionObjectInstanceTypeIOInputOnly:
+        if (kEipInvalidSocket
+            != connection_object->socket[kUdpCommuncationDirectionProducing]) { /* we are the controlling input only connection find a new controller*/
+          CipConnectionObject *next_non_control_master_connection =
+            GetNextNonControlMasterConnection(
+              connection_object->produced_path.instance_id);
+          if (NULL != next_non_control_master_connection) {
+            next_non_control_master_connection->socket[
+              kUdpCommuncationDirectionProducing] =
+              connection_object->socket[kUdpCommuncationDirectionProducing];
+            connection_object->socket[kUdpCommuncationDirectionProducing] =
+              kEipInvalidSocket;
+            next_non_control_master_connection->transmission_trigger_timer =
+              connection_object->transmission_trigger_timer;
+          } else { /* this was the last master connection close all listen only connections listening on the port */
+            CloseAllConnectionsForInputWithSameType(
+              connection_object->produced_path.instance_id,
+              kConnectionObjectInstanceTypeIOListenOnly);
+          }
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
+}
+
+EipStatus SendConnectedData(CipConnectionObject *connection_object) {
+
+  /* TODO think of adding an own send buffer to each connection object in order to preset up the whole message on connection opening and just change the variable data items e.g., sequence number */
+
+  CipCommonPacketFormatData *common_packet_format_data =
+    &g_common_packet_format_data_item;
+  /* TODO think on adding a CPF data item to the S_CIP_ConnectionObject in order to remove the code here or even better allocate memory in the connection object for storing the message to send and just change the application data*/
+
+  connection_object->eip_level_sequence_count_producing++;
+
+  /* assembleCPFData */
+  common_packet_format_data->item_count = 2;
+  if ( kConnectionObjectTransportClassTriggerTransportClass0 !=
+       ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
+  {                                                                                /* use Sequenced Address Items if not Connection Class 0 */
+    common_packet_format_data->address_item.type_id =
+      kCipItemIdSequencedAddressItem;
+    common_packet_format_data->address_item.length = 8;
+    common_packet_format_data->address_item.data.sequence_number =
+      connection_object->eip_level_sequence_count_producing;
+  } else {
+    common_packet_format_data->address_item.type_id =
+      kCipItemIdConnectionAddress;
+    common_packet_format_data->address_item.length = 4;
+
+  }
+  common_packet_format_data->address_item.data.connection_identifier =
+    connection_object->cip_produced_connection_id;
+
+  common_packet_format_data->data_item.type_id = kCipItemIdConnectedDataItem;
+
+  CipByteArray *producing_instance_attributes =
+    (CipByteArray *) connection_object->producing_instance->attributes->data;
+  common_packet_format_data->data_item.length = 0;
+
+  /* notify the application that data will be sent immediately after the call */
+  if ( BeforeAssemblyDataSend(connection_object->producing_instance) ) {
+    /* the data has changed increase sequence counter */
+    connection_object->sequence_count_producing++;
+  }
+
+  /* set AddressInfo Items to invalid Type */
+  common_packet_format_data->address_info_item[0].type_id = 0;
+  common_packet_format_data->address_info_item[1].type_id = 0;
+
+  ENIPMessage outgoing_message = {0};
+  InitializeENIPMessage(&outgoing_message);
+  EipUint16 reply_length = AssembleIOMessage(common_packet_format_data,
+                                             &outgoing_message);
+
+
+  outgoing_message.current_message_position -= 2;
+  common_packet_format_data->data_item.length = producing_instance_attributes
+                                                ->length;
+#ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
+  common_packet_format_data->data_item.length += 4;
+#endif /* OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER */
+
+  if (kConnectionObjectTransportClassTriggerTransportClass1 ==
+      ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
+  {
+    common_packet_format_data->data_item.length += 2;
+    AddIntToMessage(common_packet_format_data->data_item.length,
+                    &outgoing_message.current_message_position);
+    AddIntToMessage(connection_object->sequence_count_producing,
+                    &outgoing_message.current_message_position);
+  } else {
+    AddIntToMessage(common_packet_format_data->data_item.length,
+                    &outgoing_message.current_message_position);
+  }
+
+#ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
+  AddDintToMessage( g_run_idle_state,
+                    &(outgoing_message.current_message_position) );
+#endif /* OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER */
+
+  memcpy(outgoing_message.current_message_position,
+         producing_instance_attributes->data,
+         producing_instance_attributes->length);
+
+  outgoing_message.used_message_length +=
+    common_packet_format_data->data_item.length;
+
+  return SendUdpData(
+    &connection_object->remote_address,
+    connection_object->socket[kUdpCommuncationDirectionProducing],
+    outgoing_message.message_buffer, outgoing_message.used_message_length);
+}
+
+EipStatus HandleReceivedIoConnectionData(
+  CipConnectionObject *connection_object,
+  const EipUint8 *data,
+  EipUint16 data_length
+  ) {
+
+  OPENER_TRACE_INFO("Starting data length: %d\n", data_length);
+  bool no_new_data = false;
+  /* check class 1 sequence number*/
+  if (kConnectionObjectTransportClassTriggerTransportClass1 ==
+      ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
+  {
+    EipUint16 sequence_buffer = GetIntFromMessage( &(data) );
+    if ( SEQ_LEQ16(sequence_buffer,
+                   connection_object->sequence_count_consuming) ) {
+      no_new_data = true;
+    }
+    connection_object->sequence_count_consuming = sequence_buffer;
+    data_length -= 2;
+  }
+
+  OPENER_TRACE_INFO("data length after sequence count: %d\n", data_length);
+  if (data_length > 0) {
+    /* we have no heartbeat connection */
+#ifdef OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER
+    EipUint32 nRunIdleBuf = GetDintFromMessage( &(data) );
+    OPENER_TRACE_INFO("Run/Idle handler: 0x%x", nRunIdleBuf);
+    const uint32_t kRunBitMask = 0x0001;
+    if( (kRunBitMask & nRunIdleBuf) == 1 ) {
+      CipIdentitySetExtendedDeviceStatus(kAtLeastOneIoConnectionInRunMode);
+    } else {
+      CipIdentitySetExtendedDeviceStatus(
+        kAtLeastOneIoConnectionEstablishedAllInIdleMode);
+    }
+    if (g_run_idle_state != nRunIdleBuf) {
+      RunIdleChanged(nRunIdleBuf);
+    }
+    g_run_idle_state = nRunIdleBuf;
+    data_length -= 4;
+#endif /* OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER */
+    if(no_new_data) {
+      return kEipStatusOk;
+    }
+
+    if (NotifyAssemblyConnectedDataReceived(
+          connection_object->consuming_instance, (EipUint8 *const)data,
+          data_length) != 0) {
+      return kEipStatusError;
+    }
+  }
+  return kEipStatusOk;
+}
+
+EipStatus OpenCommunicationChannels(CipConnectionObject *connection_object) {
+
+  EipStatus eip_status = kEipStatusOk;
+  /*get pointer to the CPF data, currently we have just one global instance of the struct. This may change in the future*/
+  CipCommonPacketFormatData *common_packet_format_data =
+    &g_common_packet_format_data_item;
+
+  ConnectionObjectConnectionType originator_to_target_connection_type =
+    ConnectionObjectGetOToTConnectionType(connection_object);
+
+  ConnectionObjectConnectionType target_to_originator_connection_type =
+    ConnectionObjectGetTToOConnectionType(connection_object);
+
+  /* open a connection "point to point" or "multicast" based on the ConnectionParameter */
+  if (originator_to_target_connection_type ==
+      kConnectionObjectConnectionTypeMulticast)                                         /* Multicast consuming */
+  {
+    if (OpenMulticastConnection(kUdpCommuncationDirectionConsuming,
+                                connection_object, common_packet_format_data)
+        == kEipStatusError) {
+      OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
+      return kCipErrorConnectionFailure;
+    }
+  } else if (originator_to_target_connection_type ==
+             kConnectionObjectConnectionTypePointToPoint)                                  /* Point to Point consuming */
+  {
+    if (OpenConsumingPointToPointConnection(connection_object,
+                                            common_packet_format_data)
+        == kEipStatusError) {
+      OPENER_TRACE_ERR("error in PointToPoint consuming connection\n");
+      return kCipErrorConnectionFailure;
+    }
+  }
+
+  if (target_to_originator_connection_type ==
+      kConnectionObjectConnectionTypeMulticast)                                         /* Multicast producing */
+  {
+    if (OpenProducingMulticastConnection(connection_object,
+                                         common_packet_format_data)
+        == kEipStatusError) {
+      OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
+      return kCipErrorConnectionFailure;
+    }
+  } else if (target_to_originator_connection_type ==
+             kConnectionObjectConnectionTypePointToPoint)                                  /* Point to Point producing */
+  {
+
+    if (OpenProducingPointToPointConnection(connection_object,
+                                            common_packet_format_data)
+        != kEipStatusOk) {
+      OPENER_TRACE_ERR("error in PointToPoint producing connection\n");
+      return kCipErrorConnectionFailure;
+    }
+  }
+  return eip_status;
+}
+
+void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
+  CipConnectionObject *connection_object) {
+  CloseUdpSocket(
+    connection_object->socket[kUdpCommuncationDirectionConsuming]);
+
+  connection_object->socket[kUdpCommuncationDirectionConsuming] =
+    kEipInvalidSocket;
+
+  CloseUdpSocket(
+    connection_object->socket[kUdpCommuncationDirectionProducing]);
+
+  connection_object->socket[kUdpCommuncationDirectionProducing] =
+    kEipInvalidSocket;
+
+  RemoveFromActiveConnections(connection_object);
+  ConnectionObjectInitializeEmpty(connection_object);
+}

+ 81 - 81
source/src/cip/cipioconnection.h

@@ -1,81 +1,81 @@
-/*******************************************************************************
- * Copyright (c) 2011, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-
-/**
- * @file cipioconnection.h
- * CIP I/O Connection implementation
- * =================================
- *
- *
- * I/O Connection Object State Transition Diagram
- * ----------------------------------------------
- * @dot
- *   digraph IOConnectionObjectStateTransition {
- *     A[label="Any State"]
- *     N[label="Non-existent"]
- *     C[label="Configuring"]
- *     E[label="Established"]
- *     W[label="Waiting for Connection ID"]
- *     T[label="Timed Out"]
- *
- *     A->N [label="Delete"]
- *     N->C [label="Create"]
- *     C->C [label="Get/Set/Apply Attribute"]
- *     C->W [label="Apply Attribute"]
- *     W->W [label="Get/Set Attribute"]
- *     C->E [label="Apply Attribute"]
- *     E->E [label="Get/Set/Apply Attribute, Reset, Message Produced/Consumed"]
- *     W->E [label="Apply Attribute"]
- *     E->T [label="Inactivity/Watchdog"]
- *     T->E [label="Reset"]
- *     T->N [label="Delete"]
- *   }
- * @enddot
- *
- */
-
-#ifndef OPENER_CIPIOCONNECTION_H_
-#define OPENER_CIPIOCONNECTION_H_
-
-#include "opener_api.h"
-#include "cipconnectionmanager.h"
-#include "cipconnectionobject.h"
-
-/** @brief Setup all data in order to establish an IO connection
- *
- * This function can be called after all data has been parsed from the forward open request
- * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
- * @param extended_error the extended error code in case an error happened
- * @return general status on the establishment
- *    - EIP_OK ... on success
- *    - On an error the general status code to be put into the response
- */
-EipStatus EstablishIoConnection(
-  CipConnectionObject *RESTRICT const connection_object,
-  EipUint16 *const extended_error);
-
-/** @brief Take the data given in the connection object structure and open the necessary communication channels
- *
- * This function will use the g_stCPFDataItem!
- * @param connection_object pointer to the connection object data
- * @return general status on the open process
- *    - EIP_OK ... on success
- *    - On an error the general status code to be put into the response
- */
-EipStatus OpenCommunicationChannels(CipConnectionObject *connection_object);
-
-/** @brief close the communication channels of the given connection and remove it
- * from the active connections list.
- *
- * @param connection_object pointer to the connection object data
- */
-void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
-  CipConnectionObject *connection_object);
-
-extern EipUint8 *g_config_data_buffer;
-extern unsigned int g_config_data_length;
-
-#endif /* OPENER_CIPIOCONNECTION_H_ */
+/*******************************************************************************
+ * Copyright (c) 2011, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+/**
+ * @file cipioconnection.h
+ * CIP I/O Connection implementation
+ * =================================
+ *
+ *
+ * I/O Connection Object State Transition Diagram
+ * ----------------------------------------------
+ * @dot
+ *   digraph IOConnectionObjectStateTransition {
+ *     A[label="Any State"]
+ *     N[label="Non-existent"]
+ *     C[label="Configuring"]
+ *     E[label="Established"]
+ *     W[label="Waiting for Connection ID"]
+ *     T[label="Timed Out"]
+ *
+ *     A->N [label="Delete"]
+ *     N->C [label="Create"]
+ *     C->C [label="Get/Set/Apply Attribute"]
+ *     C->W [label="Apply Attribute"]
+ *     W->W [label="Get/Set Attribute"]
+ *     C->E [label="Apply Attribute"]
+ *     E->E [label="Get/Set/Apply Attribute, Reset, Message Produced/Consumed"]
+ *     W->E [label="Apply Attribute"]
+ *     E->T [label="Inactivity/Watchdog"]
+ *     T->E [label="Reset"]
+ *     T->N [label="Delete"]
+ *   }
+ * @enddot
+ *
+ */
+
+#ifndef OPENER_CIPIOCONNECTION_H_
+#define OPENER_CIPIOCONNECTION_H_
+
+#include "opener_api.h"
+#include "cipconnectionmanager.h"
+#include "cipconnectionobject.h"
+
+/** @brief Setup all data in order to establish an IO connection
+ *
+ * This function can be called after all data has been parsed from the forward open request
+ * @param connection_object pointer to the connection object structure holding the parsed data from the forward open request
+ * @param extended_error the extended error code in case an error happened
+ * @return general status on the establishment
+ *    - EIP_OK ... on success
+ *    - On an error the general status code to be put into the response
+ */
+EipStatus EstablishIoConnection(
+  CipConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error);
+
+/** @brief Take the data given in the connection object structure and open the necessary communication channels
+ *
+ * This function will use the g_stCPFDataItem!
+ * @param connection_object pointer to the connection object data
+ * @return general status on the open process
+ *    - EIP_OK ... on success
+ *    - On an error the general status code to be put into the response
+ */
+EipStatus OpenCommunicationChannels(CipConnectionObject *connection_object);
+
+/** @brief close the communication channels of the given connection and remove it
+ * from the active connections list.
+ *
+ * @param connection_object pointer to the connection object data
+ */
+void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
+  CipConnectionObject *connection_object);
+
+extern EipUint8 *g_config_data_buffer;
+extern unsigned int g_config_data_length;
+
+#endif /* OPENER_CIPIOCONNECTION_H_ */

+ 920 - 920
source/src/enet_encap/encap.c

@@ -1,920 +1,920 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-#include "encap.h"
-
-#include "opener_api.h"
-#include "opener_user_conf.h"
-#include "cpf.h"
-#include "endianconv.h"
-#include "cipcommon.h"
-#include "cipmessagerouter.h"
-#include "cipconnectionmanager.h"
-#include "cipidentity.h"
-#include "generic_networkhandler.h"
-#include "trace.h"
-#include "socket_timer.h"
-#include "opener_error.h"
-
-/*Identity data from cipidentity.c*/
-extern CipUint vendor_id_;
-extern CipUint device_type_;
-extern CipUint product_code_;
-extern CipRevision revision_;
-extern CipWord status_;
-extern CipUdint serial_number_;
-extern CipShortString product_name_;
-
-/* IP address data taken from TCPIPInterfaceObject*/
-extern CipTcpIpNetworkInterfaceConfiguration interface_configuration_;
-
-const int kSupportedProtocolVersion = 1; /**< Supported Encapsulation protocol version */
-
-const int kEncapsulationHeaderOptionsFlag = 0x00; /**< Mask of which options are supported as of the current CIP specs no other option value as 0 should be supported.*/
-
-const int kEncapsulationHeaderSessionHandlePosition = 4; /**< the position of the session handle within the encapsulation header*/
-
-const int kListIdentityDefaultDelayTime = 2000; /**< Default delay time for List Identity response */
-const int kListIdentityMinimumDelayTime = 500; /**< Minimum delay time for List Identity response */
-
-typedef enum {
-  kSessionStatusInvalid = -1, kSessionStatusValid = 0
-} SessionStatus;
-
-const int kSenderContextSize = 8; /**< size of sender context in encapsulation header*/
-
-/** @brief definition of known encapsulation commands */
-typedef enum {
-  kEncapsulationCommandNoOperation = 0x0000,       /**< only allowed for TCP */
-  kEncapsulationCommandListServices = 0x0004,       /**< allowed for both UDP and TCP */
-  kEncapsulationCommandListIdentity = 0x0063,       /**< allowed for both UDP and TCP */
-  kEncapsulationCommandListInterfaces = 0x0064,       /**< optional, allowed for both UDP and TCP */
-  kEncapsulationCommandRegisterSession = 0x0065,       /**< only allowed for TCP */
-  kEncapsulationCommandUnregisterSession = 0x0066,       /**< only allowed for TCP */
-  kEncapsulationCommandSendRequestReplyData = 0x006F,       /**< only allowed for TCP */
-  kEncapsulationCommandSendUnitData = 0x0070       /**< only allowed for TCP */
-} EncapsulationCommand;
-
-/** @brief definition of capability flags */
-typedef enum {
-  kCapabilityFlagsCipTcp = 0x0020, kCapabilityFlagsCipUdpClass0or1 = 0x0100
-} CapabilityFlags;
-
-#define ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES 2 /**< According to EIP spec at least 2 delayed message requests should be supported */
-
-#define ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE ( ENCAPSULATION_HEADER_LENGTH + \
-                                               39 + sizeof(OPENER_DEVICE_NAME) )                             /* currently we only have the size of an encapsulation message */
-
-/* Encapsulation layer data  */
-
-/** @brief Delayed Encapsulation Message structure */
-typedef struct {
-  EipInt32 time_out;       /**< time out in milli seconds */
-  int socket;       /**< associated socket */
-  struct sockaddr_in receiver;
-  ENIPMessage outgoing_message;
-} DelayedEncapsulationMessage;
-
-EncapsulationInterfaceInformation g_interface_information;
-
-int g_registered_sessions[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
-
-DelayedEncapsulationMessage g_delayed_encapsulation_messages[
-  ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES];
-
-/*** private functions ***/
-void HandleReceivedListIdentityCommandTcp(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message);
-
-void HandleReceivedListIdentityCommandUdp(const int socket,
-                                          const struct sockaddr_in *const from_address,
-                                          const EncapsulationData *const receive_data,
-                                          ENIPMessage *const outgoing_message);
-
-EipStatus HandleReceivedUnregisterSessionCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message);
-
-EipStatus HandleReceivedSendUnitDataCommand(
-  const EncapsulationData *const receive_data,
-  const struct sockaddr *const originator_address,
-  ENIPMessage *const outgoing_message);
-
-EipStatus HandleReceivedInvalidCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message);
-
-int GetFreeSessionIndex(void);
-
-SessionStatus CheckRegisteredSessions(
-  const EncapsulationData *const receive_data);
-
-void DetermineDelayTime(const EipByte *const buffer_start,
-                        DelayedEncapsulationMessage *const delayed_message_buffer);
-
-/*   @brief Initializes session list and interface information. */
-void EncapsulationInit(void) {
-
-  DetermineEndianess();
-
-  /*initialize random numbers for random delayed response message generation
-   * we use the ip address as seed as suggested in the spec */
-  srand(interface_configuration_.ip_address);
-
-  /* initialize Sessions to invalid == free session */
-  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; i++) {
-    g_registered_sessions[i] = kEipInvalidSocket;
-  }
-
-  for (size_t i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
-       i++) {
-    g_delayed_encapsulation_messages[i].socket = kEipInvalidSocket;
-  }
-
-  /*TODO make the interface information configurable*/
-  /* initialize interface information */
-  g_interface_information.type_code = kCipItemIdListServiceResponse;
-  g_interface_information.length = sizeof(g_interface_information);
-  g_interface_information.encapsulation_protocol_version = 1;
-  g_interface_information.capability_flags = kCapabilityFlagsCipTcp
-                                             | kCapabilityFlagsCipUdpClass0or1;
-  snprintf( (char *) g_interface_information.name_of_service,
-            sizeof(g_interface_information.name_of_service),
-            "Communications" );
-}
-
-int HandleReceivedExplictTcpData(int socket,
-                                 EipUint8 *buffer,
-                                 size_t length,
-                                 int *remaining_bytes,
-                                 struct sockaddr *originator_address,
-                                 ENIPMessage *const outgoing_message) {
-  OPENER_TRACE_INFO("Handles data for TCP socket: %d\n", socket);
-  EipStatus return_value = kEipStatusOk;
-  EncapsulationData encapsulation_data = { 0 };
-  /* eat the encapsulation header*/
-  /* the structure contains a pointer to the encapsulated data*/
-  /* returns how many bytes are left after the encapsulated data*/
-  *remaining_bytes = CreateEncapsulationStructure(buffer, length,
-                                                  &encapsulation_data);
-
-  if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options)       /*TODO generate appropriate error response*/
-  {
-    if (*remaining_bytes >= 0)             /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
-    {
-      /* full package or more received */
-      encapsulation_data.status = kEncapsulationProtocolSuccess;
-      return_value = kEipStatusOkSend;
-      /* most of these functions need a reply to be send */
-      switch (encapsulation_data.command_code) {
-        case (kEncapsulationCommandNoOperation):
-          OPENER_TRACE_INFO("NOP\n");
-          /* NOP needs no reply and does nothing */
-          return_value = kEipStatusOk;
-          break;
-
-        case (kEncapsulationCommandListServices):
-          OPENER_TRACE_INFO("List services\n");
-          HandleReceivedListServicesCommand(&encapsulation_data,
-                                            outgoing_message);
-          break;
-
-        case (kEncapsulationCommandListIdentity):
-          OPENER_TRACE_INFO("List identity\n");
-          HandleReceivedListIdentityCommandTcp(&encapsulation_data,
-                                               outgoing_message);
-          break;
-
-        case (kEncapsulationCommandListInterfaces):
-          OPENER_TRACE_INFO("List interfaces\n");
-          HandleReceivedListInterfacesCommand(&encapsulation_data,
-                                              outgoing_message);
-          break;
-
-        case (kEncapsulationCommandRegisterSession):
-          OPENER_TRACE_INFO("Register session\n");
-          HandleReceivedRegisterSessionCommand(socket,
-                                               &encapsulation_data,
-                                               outgoing_message);
-          break;
-
-        case (kEncapsulationCommandUnregisterSession):
-          OPENER_TRACE_INFO("unregister session\n");
-          return_value = HandleReceivedUnregisterSessionCommand(
-            &encapsulation_data, outgoing_message);
-          break;
-
-        case (kEncapsulationCommandSendRequestReplyData):
-          OPENER_TRACE_INFO("Send Request/Reply Data\n");
-          return_value = HandleReceivedSendRequestResponseDataCommand(
-            &encapsulation_data, originator_address, outgoing_message);
-          break;
-
-        case (kEncapsulationCommandSendUnitData):
-          OPENER_TRACE_INFO("Send Unit Data\n");
-          return_value = HandleReceivedSendUnitDataCommand(
-            &encapsulation_data, originator_address, outgoing_message);
-          break;
-
-        default:
-          return_value = HandleReceivedInvalidCommand(&encapsulation_data,
-                                                      outgoing_message);
-          break;
-      }
-    }
-  }
-
-  return return_value;
-}
-
-int HandleReceivedExplictUdpData(const int socket,
-                                 const struct sockaddr_in *from_address,
-                                 const EipUint8 *buffer,
-                                 const size_t buffer_length,
-                                 int *number_of_remaining_bytes,
-                                 bool unicast,
-                                 ENIPMessage *const outgoing_message) {
-  EipStatus status = kEipStatusOk;
-  EncapsulationData encapsulation_data = { 0 };
-  /* eat the encapsulation header*/
-  /* the structure contains a pointer to the encapsulated data*/
-  /* returns how many bytes are left after the encapsulated data*/
-  *number_of_remaining_bytes = CreateEncapsulationStructure(buffer,
-                                                            buffer_length,
-                                                            &encapsulation_data);
-
-  if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options)       /*TODO generate appropriate error response*/
-  {
-    if (*number_of_remaining_bytes >= 0)             /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
-    {
-      /* full package or more received */
-      encapsulation_data.status = kEncapsulationProtocolSuccess;
-      status = kEipStatusOkSend;
-      /* most of these functions need a reply to be send */
-      switch (encapsulation_data.command_code) {
-        case (kEncapsulationCommandListServices):
-          OPENER_TRACE_INFO("List Service\n");
-          HandleReceivedListServicesCommand(&encapsulation_data,
-                                            outgoing_message);
-          break;
-
-        case (kEncapsulationCommandListIdentity):
-          OPENER_TRACE_INFO("List Identity\n");
-          if (unicast == true) {
-            HandleReceivedListIdentityCommandTcp(&encapsulation_data,
-                                                 outgoing_message);
-          } else {
-            HandleReceivedListIdentityCommandUdp(socket,
-                                                 from_address,
-                                                 &encapsulation_data,
-                                                 outgoing_message);
-            status = kEipStatusOk;
-          }                       /* as the response has to be delayed do not send it now */
-          break;
-
-        case (kEncapsulationCommandListInterfaces):
-          OPENER_TRACE_INFO("List Interfaces\n");
-          HandleReceivedListInterfacesCommand(&encapsulation_data,
-                                              outgoing_message);
-          break;
-
-        /* The following commands are not to be sent via UDP */
-        case (kEncapsulationCommandNoOperation):
-        case (kEncapsulationCommandRegisterSession):
-        case (kEncapsulationCommandUnregisterSession):
-        case (kEncapsulationCommandSendRequestReplyData):
-        case (kEncapsulationCommandSendUnitData):
-        default:
-          OPENER_TRACE_INFO("No command\n");
-          //TODO: Check this
-          encapsulation_data.status =
-            kEncapsulationProtocolInvalidCommand;
-          encapsulation_data.data_length = 0;
-          break;
-      }
-
-      if (kEipStatusOk < status) {
-        /* if status is greater than 0 data has to be sent */
-        //status = EncapsulateData(&encapsulation_data);
-      }
-    }
-  }
-  return outgoing_message->used_message_length;
-}
-
-void SkipEncapsulationHeader(ENIPMessage *const outgoing_message) {
-  MoveMessageNOctets(ENCAPSULATION_HEADER_LENGTH,
-                     &outgoing_message->current_message_position);
-}
-
-void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
-                                 const size_t command_specific_data_length,
-                                 const size_t session_handle,
-                                 const EncapsulationProtocolErrorCode encapsulation_protocol_status,
-                                 ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    receive_data->command_code,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    command_specific_data_length,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(session_handle,
-                                                            &outgoing_message->current_message_position); //Session handle
-  outgoing_message->used_message_length += AddDintToMessage(
-    encapsulation_protocol_status,
-    &outgoing_message->current_message_position);                                                         //Status
-  memcpy(outgoing_message->current_message_position,
-         receive_data->sender_context, kSenderContextSize);                // sender context
-  outgoing_message->current_message_position += kSenderContextSize;
-  outgoing_message->used_message_length += kSenderContextSize;
-  outgoing_message->used_message_length += AddDintToMessage(0,
-                                                            &outgoing_message->current_message_position); // options
-}
-
-/** @brief generate reply with "Communications Services" + compatibility Flags.
- *  @param receive_data pointer to structure with received data
- *  @param outgoing_message The outgoing ENIP message
- */
-void HandleReceivedListServicesCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message) {
-
-  /* Create encapsulation header */
-  const size_t kListServicesCommandSpecificDataLength = sizeof(CipUint)
-                                                        + sizeof(
-    g_interface_information);
-  GenerateEncapsulationHeader(receive_data,
-                              kListServicesCommandSpecificDataLength,
-                              0, /* Session handle will be ignored */
-                              kEncapsulationProtocolSuccess,                             /* Protocol status */
-                              outgoing_message);
-
-  /* Command specific data copy Interface data to msg for sending */
-  outgoing_message->used_message_length += AddIntToMessage(1,
-                                                           &outgoing_message->current_message_position); // Item count
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_interface_information.type_code,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    (EipUint16) (g_interface_information.length - 4),
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_interface_information.encapsulation_protocol_version,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_interface_information.capability_flags,
-    &outgoing_message->current_message_position);
-  memcpy(outgoing_message->current_message_position,
-         g_interface_information.name_of_service,
-         sizeof(g_interface_information.name_of_service) );
-  outgoing_message->used_message_length +=
-    sizeof(g_interface_information.name_of_service);
-}
-
-void HandleReceivedListInterfacesCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message) {
-
-  /* Encapsulation header */
-  const size_t kListInterfacesCommandSpecificDataLength = sizeof(CipUint)
-                                                          + sizeof(
-    g_interface_information);
-  GenerateEncapsulationHeader(receive_data,
-                              kListInterfacesCommandSpecificDataLength,
-                              0, /* Session handle will be ignored */
-                              kEncapsulationProtocolSuccess,
-                              outgoing_message);
-  /* Command specific data */
-  outgoing_message->used_message_length += AddIntToMessage(0x0000,
-                                                           &outgoing_message->current_message_position); /* Reply 0 for no information being returned */
-}
-
-void HandleReceivedListIdentityCommandTcp(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message) {
-  EncapsulateListIdentityResponseMessage(receive_data, outgoing_message);
-}
-
-void HandleReceivedListIdentityCommandUdp(const int socket,
-                                          const struct sockaddr_in *const from_address,
-                                          const EncapsulationData *const receive_data,
-                                          ENIPMessage *const outgoing_message) {
-  DelayedEncapsulationMessage *delayed_message_buffer = NULL;
-  ENIPMessage* p_outgoing_message = NULL;
-
-  for (size_t i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
-       i++) {
-    if (kEipInvalidSocket == g_delayed_encapsulation_messages[i].socket) {
-      delayed_message_buffer = &(g_delayed_encapsulation_messages[i]);
-
-      p_outgoing_message = &(delayed_message_buffer->outgoing_message);
-      InitializeENIPMessage(p_outgoing_message);
-      break;
-    }
-  }
-
-  if (NULL != delayed_message_buffer) {
-    delayed_message_buffer->socket = socket;
-    memcpy( (&delayed_message_buffer->receiver), from_address,
-            sizeof(struct sockaddr_in) );
-
-    DetermineDelayTime(receive_data->communication_buffer_start,
-                       delayed_message_buffer);
-
-    EncapsulateListIdentityResponseMessage(receive_data, p_outgoing_message);
-  }
-}
-
-void EncapsulateListIdentityResponseMessage(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message) {
-
-
-  const CipUint kEncapsulationCommandListIdentityCommandSpecificLength =
-    sizeof(CipUint) + sizeof(CipInt) + sizeof(CipUint) + sizeof(CipUdint) +
-    8 *
-    sizeof(CipUsint) + sizeof(CipUint) + sizeof(CipUint) + sizeof(CipUint) + 2 *
-    sizeof(CipUsint) + sizeof(CipWord) + sizeof(CipUdint) +
-    sizeof(
-      CipUsint) + product_name_.length + sizeof(CipUsint);
-  const CipUint kEncapsulationCommandListIdentityLength =
-    kEncapsulationCommandListIdentityCommandSpecificLength + sizeof(CipUint) +
-    sizeof(CipUint)
-    + sizeof(CipUint);               /* Last element is item count */
-
-  GenerateEncapsulationHeader(receive_data,
-                              kEncapsulationCommandListIdentityLength,
-                              0,   /* Session handle will be ignored by receiver */
-                              kEncapsulationProtocolSuccess,
-                              outgoing_message);
-
-  outgoing_message->used_message_length += AddIntToMessage(1,
-                                                           &outgoing_message->current_message_position); /* Item count: one item */
-
-  /* Item ID*/
-  const CipUint kItemIDCipIdentity = 0x0C;
-  outgoing_message->used_message_length += AddIntToMessage(
-    kItemIDCipIdentity,
-    &outgoing_message->current_message_position);
-
-  outgoing_message->used_message_length += AddIntToMessage(
-    kEncapsulationCommandListIdentityCommandSpecificLength,
-    &outgoing_message->current_message_position);
-
-  outgoing_message->used_message_length += AddIntToMessage(
-    kSupportedProtocolVersion,
-    &outgoing_message->current_message_position);
-
-  outgoing_message->used_message_length += EncapsulateIpAddress(
-    htons(kOpenerEthernetPort), interface_configuration_.ip_address,
-    &outgoing_message->current_message_position);
-
-  /** Array of USINT - length 8 shall be set to zero */
-  memset(outgoing_message->current_message_position, 0, 8);
-  outgoing_message->used_message_length += MoveMessageNOctets(8,
-                                                              (const CipOctet **) &outgoing_message->current_message_position);
-
-  outgoing_message->used_message_length += AddIntToMessage(vendor_id_,
-                                                           &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(device_type_,
-                                                           &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(product_code_,
-                                                           &outgoing_message->current_message_position);
-  *(outgoing_message->current_message_position)++ = revision_.major_revision;
-  outgoing_message->used_message_length++;
-  *(outgoing_message->current_message_position)++ = revision_.minor_revision;
-  outgoing_message->used_message_length++;
-  outgoing_message->used_message_length += AddIntToMessage(status_,
-                                                           &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(serial_number_,
-                                                            &outgoing_message->current_message_position);
-  *outgoing_message->current_message_position++ =
-    (unsigned char) product_name_.length;
-  outgoing_message->used_message_length++;
-
-  memcpy(outgoing_message->current_message_position, product_name_.string,
-         product_name_.length);
-  outgoing_message->current_message_position += product_name_.length;
-  outgoing_message->used_message_length += product_name_.length;
-
-  *outgoing_message->current_message_position++ = 0xFF;
-  outgoing_message->used_message_length++;
-
-}
-
-void DetermineDelayTime(const EipByte *const buffer_start,
-                        DelayedEncapsulationMessage *const delayed_message_buffer)
-{
-
-  MoveMessageNOctets(12, (const CipOctet **) &buffer_start);       /* start of the sender context */
-  EipUint16 maximum_delay_time = GetIntFromMessage(
-    (const EipUint8 **const ) &buffer_start);
-
-  if (0 == maximum_delay_time) {
-    maximum_delay_time = kListIdentityDefaultDelayTime;
-  } else if (kListIdentityMinimumDelayTime > maximum_delay_time) {       /* if maximum_delay_time is between 1 and 500ms set it to 500ms */
-    maximum_delay_time = kListIdentityMinimumDelayTime;
-  }
-
-  delayed_message_buffer->time_out = rand() % maximum_delay_time ;
-}
-
-void EncapsulateRegisterSessionCommandResponseMessage(
-  const EncapsulationData *const receive_data,
-  const size_t session_handle,
-  const EncapsulationProtocolErrorCode encapsulation_protocol_status,
-  ENIPMessage *const outgoing_message) {
-
-  /* Encapsulation header */
-  const size_t kListInterfacesCommandSpecificDataLength = sizeof(CipUint)
-                                                          + sizeof(CipUint);
-  assert(kListInterfacesCommandSpecificDataLength == 4);
-  GenerateEncapsulationHeader(receive_data,
-                              kListInterfacesCommandSpecificDataLength,
-                              session_handle,
-                              encapsulation_protocol_status,
-                              outgoing_message);
-
-  outgoing_message->used_message_length += AddIntToMessage(1,
-                                                           &outgoing_message->current_message_position); /* protocol version*/
-  outgoing_message->used_message_length += AddIntToMessage(
-    0,
-    &outgoing_message->current_message_position);                     /* Options flag, shall be set to zero */
-}
-
-/* @brief Check supported protocol, generate session handle, send replay back to originator.
- * @param socket Socket this request is associated to. Needed for double register check
- * @param receive_data Pointer to received data with request/response.
- */
-void HandleReceivedRegisterSessionCommand(int socket,
-                                          const EncapsulationData *const receive_data,
-                                          ENIPMessage *const outgoing_message) {
-  int session_index = 0;
-  size_t session_handle = 0;
-  EncapsulationProtocolErrorCode encapsulation_protocol_status =
-    kEncapsulationProtocolSuccess;
-
-  EipUint16 protocol_version =
-    GetIntFromMessage(
-      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);
-  EipUint16 option_flag =
-    GetIntFromMessage(
-      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);
-
-  /* check if requested protocol version is supported and the register session option flag is zero*/
-  if ( (0 < protocol_version)
-       && (protocol_version <= kSupportedProtocolVersion)
-       && (0 == option_flag) ) {                 /*Option field should be zero*/
-    /* check if the socket has already a session open */
-    for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
-      if (g_registered_sessions[i] == socket) {
-        /* the socket has already registered a session this is not allowed*/
-        OPENER_TRACE_INFO(
-          "Error: A session is already registered at socket %d\n",
-          socket);
-        session_handle = i + 1; /*return the already assigned session back, the cip spec is not clear about this needs to be tested*/
-        encapsulation_protocol_status = kEncapsulationProtocolInvalidCommand;
-        session_index = kSessionStatusInvalid;
-        break;
-      }
-    }
-
-    if (kSessionStatusInvalid != session_index) {
-      session_index = GetFreeSessionIndex();
-      if (kSessionStatusInvalid == session_index)                   /* no more sessions available */
-      {
-        encapsulation_protocol_status =
-          kEncapsulationProtocolInsufficientMemory;
-      } else {                   /* successful session registered */
-        SocketTimer *socket_timer = SocketTimerArrayGetEmptySocketTimer(
-          g_timestamps,
-          OPENER_NUMBER_OF_SUPPORTED_SESSIONS);
-        SocketTimerSetSocket(socket_timer, socket);
-        SocketTimerSetLastUpdate(socket_timer, g_actual_time);
-        g_registered_sessions[session_index] = socket;                         /* store associated socket */
-        session_handle = session_index + 1;
-        encapsulation_protocol_status = kEncapsulationProtocolSuccess;
-      }
-    }
-  } else {       /* protocol not supported */
-    encapsulation_protocol_status = kEncapsulationProtocolUnsupportedProtocol;
-  }
-
-  EncapsulateRegisterSessionCommandResponseMessage(receive_data,
-                                                   session_handle,
-                                                   encapsulation_protocol_status,
-                                                   outgoing_message);
-
-}
-
-/*   TODO: Update and doxyfy
- * INT8 UnregisterSession(struct S_Encapsulation_Data *pa_S_ReceiveData)
- *   close all corresponding TCP connections and delete session handle.
- *      pa_S_ReceiveData pointer to unregister session request with corresponding socket handle.
- */
-EipStatus HandleReceivedUnregisterSessionCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message) {
-  OPENER_TRACE_INFO("encap.c: Unregister Session Command\n");
-  if ( (0 < receive_data->session_handle) && (receive_data->session_handle <=
-                                              OPENER_NUMBER_OF_SUPPORTED_SESSIONS) )
-  {
-    size_t i = receive_data->session_handle - 1;
-    if (kEipInvalidSocket != g_registered_sessions[i]) {
-      CloseTcpSocket(g_registered_sessions[i]);
-      g_registered_sessions[i] = kEipInvalidSocket;
-      CloseClass3ConnectionBasedOnSession(i + 1);
-      return kEipStatusOk;
-    }
-  }
-
-  /* no such session registered */
-  GenerateEncapsulationHeader(receive_data,
-                              0,
-                              receive_data->session_handle,
-                              kEncapsulationProtocolInvalidSessionHandle,
-                              outgoing_message);
-  return kEipStatusOkSend;
-}
-
-/** @brief Call Connection Manager.
- *  @param receive_data Pointer to structure with data and header information.
- *  @param originator_address Address of the originator as received from socket
- *  @param outgoing_message The outgoing ENIP message
- */
-EipStatus HandleReceivedSendUnitDataCommand(
-  const EncapsulationData *const receive_data,
-  const struct sockaddr *const originator_address,
-  ENIPMessage *const outgoing_message) {
-  EipStatus return_value = kEipStatusOkSend;
-
-  if (receive_data->data_length >= 6) {
-    /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
-    /* don't use the data yet */
-    GetDintFromMessage(
-      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over null interface handle*/
-    GetIntFromMessage(
-      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over unused timeout value*/
-    ( (EncapsulationData *const)receive_data )->data_length -= 6;             /* the rest is in CPF format*/
-
-    if (kSessionStatusValid == CheckRegisteredSessions(receive_data) )            /* see if the EIP session is registered*/
-    {
-      EipInt16 send_size =
-        NotifyConnectedCommonPacketFormat(receive_data,
-                                          originator_address,
-                                          outgoing_message);
-
-      return_value = send_size;
-
-      if (send_size < 0) {                   /* need to send reply */
-        return_value = kEipStatusError;
-      }
-    } else {             /* received a package with non registered session handle */
-      InitializeENIPMessage(outgoing_message);
-      GenerateEncapsulationHeader(receive_data,
-                                  0,
-                                  receive_data->session_handle,
-                                  kEncapsulationProtocolInvalidSessionHandle,
-                                  outgoing_message);
-    }
-  }
-  return return_value;
-}
-
-/** @brief Call UCMM or Message Router if UCMM not implemented.
- *  @param receive_data Pointer to structure with data and header information.
- *  @param originator_address Address of the originator as received from socket
- *  @param outgoing_message The outgoing ENIP message
- *  @return status      kEipStatusOk .. success.
- *                      kEipStatusError .. error
- */
-EipStatus HandleReceivedSendRequestResponseDataCommand(
-  const EncapsulationData *const receive_data,
-  const struct sockaddr *const originator_address,
-  ENIPMessage *const outgoing_message) {
-  EipStatus return_value = kEipStatusOkSend;
-
-  if (receive_data->data_length >= 6) {
-    /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
-    /* don't use the data yet */
-    GetDintFromMessage(
-      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over null interface handle*/
-    GetIntFromMessage(
-      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over unused timeout value*/
-    ( (EncapsulationData *const)receive_data )->data_length -= 6;             /* the rest is in CPF format*/
-
-    if (kSessionStatusValid == CheckRegisteredSessions(receive_data) )            /* see if the EIP session is registered*/
-    {
-      EipInt16 send_size =
-        NotifyCommonPacketFormat(receive_data,
-                                 originator_address,
-                                 outgoing_message);
-      return_value = send_size;
-
-      if (send_size < 0) {                   /* need to send reply */
-        return_value = kEipStatusError;
-      }
-    } else {             /* received a package with non registered session handle */
-      InitializeENIPMessage(outgoing_message);
-      GenerateEncapsulationHeader(receive_data,
-                                  0,
-                                  receive_data->session_handle,
-                                  kEncapsulationProtocolInvalidSessionHandle,
-                                  outgoing_message);
-    }
-  }
-  return return_value;
-}
-
-EipStatus HandleReceivedInvalidCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message) {
-
-  /* Encapsulation header */
-  GenerateEncapsulationHeader(receive_data,
-                              0,
-                              receive_data->session_handle,
-                              kEncapsulationProtocolInvalidCommand,
-                              outgoing_message);
-  return outgoing_message->used_message_length;
-
-}
-
-/** @brief search for available sessions an return index.
- *  @return return index of free session in anRegisteredSessions.
- *                      kInvalidSession .. no free session available
- */
-int GetFreeSessionIndex(void) {
-  for (size_t session_index = 0;
-       session_index < OPENER_NUMBER_OF_SUPPORTED_SESSIONS;
-       session_index++) {
-    if (kEipInvalidSocket == g_registered_sessions[session_index]) {
-      return session_index;
-    }
-  }
-  return kSessionStatusInvalid;
-}
-
-/** @brief copy data from pa_buf in little endian to host in structure.
- * @param receive_buffer Received message
- * @param receive_buffer_length Length of the data in receive_buffer. Might be more than one message
- * @param encapsulation_data	structure to which data shall be copied
- * @return return difference between bytes in pa_buf an data_length
- *              0 .. full package received
- *                      >0 .. more than one packet received
- *                      <0 .. only fragment of data portion received
- */
-EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
-                                      int receive_buffer_length,
-                                      EncapsulationData *const encapsulation_data)
-{
-  encapsulation_data->communication_buffer_start =
-    (EipUint8 *) receive_buffer;
-  encapsulation_data->command_code = GetIntFromMessage(&receive_buffer);
-  encapsulation_data->data_length = GetIntFromMessage(&receive_buffer);
-  encapsulation_data->session_handle = GetDintFromMessage(&receive_buffer);
-  encapsulation_data->status = GetDintFromMessage(&receive_buffer);
-
-  memcpy(encapsulation_data->sender_context, receive_buffer,
-         kSenderContextSize);
-  receive_buffer += kSenderContextSize;
-  encapsulation_data->options = GetDintFromMessage(&receive_buffer);
-  encapsulation_data->current_communication_buffer_position =
-    (EipUint8 *) receive_buffer;
-  return (receive_buffer_length - ENCAPSULATION_HEADER_LENGTH
-          - encapsulation_data->data_length);
-}
-
-/** @brief Check if received package belongs to registered session.
- *  @param receive_data Received data.
- *  @return 0 .. Session registered
- *              kInvalidSession .. invalid session -> return unsupported command received
- */
-SessionStatus CheckRegisteredSessions(
-  const EncapsulationData *const receive_data) {
-  if ( (0 < receive_data->session_handle) && (receive_data->session_handle <=
-                                              OPENER_NUMBER_OF_SUPPORTED_SESSIONS) )
-  {
-    if (kEipInvalidSocket
-        != g_registered_sessions[receive_data->session_handle - 1]) {
-      return kSessionStatusValid;
-    }
-  }
-  return kSessionStatusInvalid;
-}
-
-void CloseSessionBySessionHandle(
-  const CipConnectionObject *const connection_object) {
-  OPENER_TRACE_INFO("encap.c: Close session by handle\n");
-  size_t session_handle = connection_object->associated_encapsulation_session;
-  CloseTcpSocket(g_registered_sessions[session_handle - 1]);
-  g_registered_sessions[session_handle - 1] = kEipInvalidSocket;
-  OPENER_TRACE_INFO("encap.c: Close session by handle done\n");
-}
-
-void CloseSession(int socket) {
-  OPENER_TRACE_INFO("encap.c: Close session\n");
-  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
-    if (g_registered_sessions[i] == socket) {
-      CloseTcpSocket(socket);
-      g_registered_sessions[i] = kEipInvalidSocket;
-      CloseClass3ConnectionBasedOnSession(i + 1);
-      break;
-    }
-  }
-  OPENER_TRACE_INFO("encap.c: Close session done\n");
-}
-
-void RemoveSession(const int socket) {
-  OPENER_TRACE_INFO("encap.c: Removing session\n");
-  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
-    if (g_registered_sessions[i] == socket) {
-      g_registered_sessions[i] = kEipInvalidSocket;
-      CloseClass3ConnectionBasedOnSession(i + 1);
-      break;
-    }
-  }
-  OPENER_TRACE_INFO("encap.c: Session removed\n");
-}
-
-void EncapsulationShutDown(void) {
-  OPENER_TRACE_INFO("encap.c: Encapsulation shutdown\n");
-  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
-    if (kEipInvalidSocket != g_registered_sessions[i]) {
-      CloseTcpSocket(g_registered_sessions[i]);
-      g_registered_sessions[i] = kEipInvalidSocket;
-    }
-  }
-}
-
-void ManageEncapsulationMessages(const MilliSeconds elapsed_time) {
-  for (size_t i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
-       i++) {
-    if (kEipInvalidSocket != g_delayed_encapsulation_messages[i].socket) {
-      g_delayed_encapsulation_messages[i].time_out -= elapsed_time;
-      if (0 >= g_delayed_encapsulation_messages[i].time_out) {
-        /* If delay is reached or passed, send the UDP message */
-        sendto(g_delayed_encapsulation_messages[i].socket,
-                    (char *) g_delayed_encapsulation_messages[i].outgoing_message.message_buffer,
-                    g_delayed_encapsulation_messages[i].outgoing_message.used_message_length, 0,
-                    (struct sockaddr *) &(g_delayed_encapsulation_messages[i].receiver), 
-                    sizeof(struct sockaddr));
-        g_delayed_encapsulation_messages[i].socket = kEipInvalidSocket;
-      }
-    }
-  }
-}
-
-void CloseEncapsulationSessionBySockAddr(
-  const CipConnectionObject *const connection_object) {
-  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
-    if (kEipInvalidSocket != g_registered_sessions[i]) {
-      struct sockaddr_in encapsulation_session_addr = { 0 };
-      socklen_t addrlength = sizeof(encapsulation_session_addr);
-      if (getpeername(g_registered_sessions[i],
-                      &encapsulation_session_addr, &addrlength) < 0) {                   /* got error */
-        int error_code = GetSocketErrorNumber();
-        char *error_message = GetErrorMessage(error_code);
-        OPENER_TRACE_ERR(
-          "encap.c: error on getting peer name on closing session: %d - %s\n",
-          error_code, error_message);
-        FreeErrorMessage(error_message);
-      }
-      if (encapsulation_session_addr.sin_addr.s_addr
-          == connection_object->originator_address.sin_addr.s_addr) {
-        CloseSession(g_registered_sessions[i]);
-      }
-    }
-  }
-}
-
-size_t GetSessionFromSocket(const int socket_handle) {
-  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
-    if (socket_handle == g_registered_sessions[i]) {
-      return i;
-    }
-  }
-  return OPENER_NUMBER_OF_SUPPORTED_SESSIONS;
-}
-
-void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle) {
-  DoublyLinkedListNode *node = connection_list.first;
-  while (NULL != node) {
-    CipConnectionObject *connection_object = node->data;
-    if (kConnectionObjectTransportClassTriggerTransportClass3
-        == ConnectionObjectGetTransportClassTriggerTransportClass(
-          connection_object)
-        && connection_object->associated_encapsulation_session
-        == encapsulation_session_handle) {
-      connection_object->connection_close_function(connection_object);
-    }
-    node = node->next;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "encap.h"
+
+#include "opener_api.h"
+#include "opener_user_conf.h"
+#include "cpf.h"
+#include "endianconv.h"
+#include "cipcommon.h"
+#include "cipmessagerouter.h"
+#include "cipconnectionmanager.h"
+#include "cipidentity.h"
+#include "generic_networkhandler.h"
+#include "trace.h"
+#include "socket_timer.h"
+#include "opener_error.h"
+
+/*Identity data from cipidentity.c*/
+extern CipUint vendor_id_;
+extern CipUint device_type_;
+extern CipUint product_code_;
+extern CipRevision revision_;
+extern CipWord status_;
+extern CipUdint serial_number_;
+extern CipShortString product_name_;
+
+/* IP address data taken from TCPIPInterfaceObject*/
+extern CipTcpIpNetworkInterfaceConfiguration interface_configuration_;
+
+const int kSupportedProtocolVersion = 1; /**< Supported Encapsulation protocol version */
+
+const int kEncapsulationHeaderOptionsFlag = 0x00; /**< Mask of which options are supported as of the current CIP specs no other option value as 0 should be supported.*/
+
+const int kEncapsulationHeaderSessionHandlePosition = 4; /**< the position of the session handle within the encapsulation header*/
+
+const int kListIdentityDefaultDelayTime = 2000; /**< Default delay time for List Identity response */
+const int kListIdentityMinimumDelayTime = 500; /**< Minimum delay time for List Identity response */
+
+typedef enum {
+  kSessionStatusInvalid = -1, kSessionStatusValid = 0
+} SessionStatus;
+
+const int kSenderContextSize = 8; /**< size of sender context in encapsulation header*/
+
+/** @brief definition of known encapsulation commands */
+typedef enum {
+  kEncapsulationCommandNoOperation = 0x0000,       /**< only allowed for TCP */
+  kEncapsulationCommandListServices = 0x0004,       /**< allowed for both UDP and TCP */
+  kEncapsulationCommandListIdentity = 0x0063,       /**< allowed for both UDP and TCP */
+  kEncapsulationCommandListInterfaces = 0x0064,       /**< optional, allowed for both UDP and TCP */
+  kEncapsulationCommandRegisterSession = 0x0065,       /**< only allowed for TCP */
+  kEncapsulationCommandUnregisterSession = 0x0066,       /**< only allowed for TCP */
+  kEncapsulationCommandSendRequestReplyData = 0x006F,       /**< only allowed for TCP */
+  kEncapsulationCommandSendUnitData = 0x0070       /**< only allowed for TCP */
+} EncapsulationCommand;
+
+/** @brief definition of capability flags */
+typedef enum {
+  kCapabilityFlagsCipTcp = 0x0020, kCapabilityFlagsCipUdpClass0or1 = 0x0100
+} CapabilityFlags;
+
+#define ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES 2 /**< According to EIP spec at least 2 delayed message requests should be supported */
+
+#define ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE ( ENCAPSULATION_HEADER_LENGTH + \
+                                               39 + sizeof(OPENER_DEVICE_NAME) )                             /* currently we only have the size of an encapsulation message */
+
+/* Encapsulation layer data  */
+
+/** @brief Delayed Encapsulation Message structure */
+typedef struct {
+  EipInt32 time_out;       /**< time out in milli seconds */
+  int socket;       /**< associated socket */
+  struct sockaddr_in receiver;
+  ENIPMessage outgoing_message;
+} DelayedEncapsulationMessage;
+
+EncapsulationInterfaceInformation g_interface_information;
+
+int g_registered_sessions[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
+
+DelayedEncapsulationMessage g_delayed_encapsulation_messages[
+  ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES];
+
+/*** private functions ***/
+void HandleReceivedListIdentityCommandTcp(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message);
+
+void HandleReceivedListIdentityCommandUdp(const int socket,
+                                          const struct sockaddr_in *const from_address,
+                                          const EncapsulationData *const receive_data,
+                                          ENIPMessage *const outgoing_message);
+
+EipStatus HandleReceivedUnregisterSessionCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message);
+
+EipStatus HandleReceivedSendUnitDataCommand(
+  const EncapsulationData *const receive_data,
+  const struct sockaddr *const originator_address,
+  ENIPMessage *const outgoing_message);
+
+EipStatus HandleReceivedInvalidCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message);
+
+int GetFreeSessionIndex(void);
+
+SessionStatus CheckRegisteredSessions(
+  const EncapsulationData *const receive_data);
+
+void DetermineDelayTime(const EipByte *const buffer_start,
+                        DelayedEncapsulationMessage *const delayed_message_buffer);
+
+/*   @brief Initializes session list and interface information. */
+void EncapsulationInit(void) {
+
+  DetermineEndianess();
+
+  /*initialize random numbers for random delayed response message generation
+   * we use the ip address as seed as suggested in the spec */
+  srand(interface_configuration_.ip_address);
+
+  /* initialize Sessions to invalid == free session */
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; i++) {
+    g_registered_sessions[i] = kEipInvalidSocket;
+  }
+
+  for (size_t i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
+       i++) {
+    g_delayed_encapsulation_messages[i].socket = kEipInvalidSocket;
+  }
+
+  /*TODO make the interface information configurable*/
+  /* initialize interface information */
+  g_interface_information.type_code = kCipItemIdListServiceResponse;
+  g_interface_information.length = sizeof(g_interface_information);
+  g_interface_information.encapsulation_protocol_version = 1;
+  g_interface_information.capability_flags = kCapabilityFlagsCipTcp
+                                             | kCapabilityFlagsCipUdpClass0or1;
+  snprintf( (char *) g_interface_information.name_of_service,
+            sizeof(g_interface_information.name_of_service),
+            "Communications" );
+}
+
+int HandleReceivedExplictTcpData(int socket,
+                                 EipUint8 *buffer,
+                                 size_t length,
+                                 int *remaining_bytes,
+                                 struct sockaddr *originator_address,
+                                 ENIPMessage *const outgoing_message) {
+  OPENER_TRACE_INFO("Handles data for TCP socket: %d\n", socket);
+  EipStatus return_value = kEipStatusOk;
+  EncapsulationData encapsulation_data = { 0 };
+  /* eat the encapsulation header*/
+  /* the structure contains a pointer to the encapsulated data*/
+  /* returns how many bytes are left after the encapsulated data*/
+  *remaining_bytes = CreateEncapsulationStructure(buffer, length,
+                                                  &encapsulation_data);
+
+  if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options)       /*TODO generate appropriate error response*/
+  {
+    if (*remaining_bytes >= 0)             /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
+    {
+      /* full package or more received */
+      encapsulation_data.status = kEncapsulationProtocolSuccess;
+      return_value = kEipStatusOkSend;
+      /* most of these functions need a reply to be send */
+      switch (encapsulation_data.command_code) {
+        case (kEncapsulationCommandNoOperation):
+          OPENER_TRACE_INFO("NOP\n");
+          /* NOP needs no reply and does nothing */
+          return_value = kEipStatusOk;
+          break;
+
+        case (kEncapsulationCommandListServices):
+          OPENER_TRACE_INFO("List services\n");
+          HandleReceivedListServicesCommand(&encapsulation_data,
+                                            outgoing_message);
+          break;
+
+        case (kEncapsulationCommandListIdentity):
+          OPENER_TRACE_INFO("List identity\n");
+          HandleReceivedListIdentityCommandTcp(&encapsulation_data,
+                                               outgoing_message);
+          break;
+
+        case (kEncapsulationCommandListInterfaces):
+          OPENER_TRACE_INFO("List interfaces\n");
+          HandleReceivedListInterfacesCommand(&encapsulation_data,
+                                              outgoing_message);
+          break;
+
+        case (kEncapsulationCommandRegisterSession):
+          OPENER_TRACE_INFO("Register session\n");
+          HandleReceivedRegisterSessionCommand(socket,
+                                               &encapsulation_data,
+                                               outgoing_message);
+          break;
+
+        case (kEncapsulationCommandUnregisterSession):
+          OPENER_TRACE_INFO("unregister session\n");
+          return_value = HandleReceivedUnregisterSessionCommand(
+            &encapsulation_data, outgoing_message);
+          break;
+
+        case (kEncapsulationCommandSendRequestReplyData):
+          OPENER_TRACE_INFO("Send Request/Reply Data\n");
+          return_value = HandleReceivedSendRequestResponseDataCommand(
+            &encapsulation_data, originator_address, outgoing_message);
+          break;
+
+        case (kEncapsulationCommandSendUnitData):
+          OPENER_TRACE_INFO("Send Unit Data\n");
+          return_value = HandleReceivedSendUnitDataCommand(
+            &encapsulation_data, originator_address, outgoing_message);
+          break;
+
+        default:
+          return_value = HandleReceivedInvalidCommand(&encapsulation_data,
+                                                      outgoing_message);
+          break;
+      }
+    }
+  }
+
+  return return_value;
+}
+
+int HandleReceivedExplictUdpData(const int socket,
+                                 const struct sockaddr_in *from_address,
+                                 const EipUint8 *buffer,
+                                 const size_t buffer_length,
+                                 int *number_of_remaining_bytes,
+                                 bool unicast,
+                                 ENIPMessage *const outgoing_message) {
+  EipStatus status = kEipStatusOk;
+  EncapsulationData encapsulation_data = { 0 };
+  /* eat the encapsulation header*/
+  /* the structure contains a pointer to the encapsulated data*/
+  /* returns how many bytes are left after the encapsulated data*/
+  *number_of_remaining_bytes = CreateEncapsulationStructure(buffer,
+                                                            buffer_length,
+                                                            &encapsulation_data);
+
+  if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options)       /*TODO generate appropriate error response*/
+  {
+    if (*number_of_remaining_bytes >= 0)             /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
+    {
+      /* full package or more received */
+      encapsulation_data.status = kEncapsulationProtocolSuccess;
+      status = kEipStatusOkSend;
+      /* most of these functions need a reply to be send */
+      switch (encapsulation_data.command_code) {
+        case (kEncapsulationCommandListServices):
+          OPENER_TRACE_INFO("List Service\n");
+          HandleReceivedListServicesCommand(&encapsulation_data,
+                                            outgoing_message);
+          break;
+
+        case (kEncapsulationCommandListIdentity):
+          OPENER_TRACE_INFO("List Identity\n");
+          if (unicast == true) {
+            HandleReceivedListIdentityCommandTcp(&encapsulation_data,
+                                                 outgoing_message);
+          } else {
+            HandleReceivedListIdentityCommandUdp(socket,
+                                                 from_address,
+                                                 &encapsulation_data,
+                                                 outgoing_message);
+            status = kEipStatusOk;
+          }                       /* as the response has to be delayed do not send it now */
+          break;
+
+        case (kEncapsulationCommandListInterfaces):
+          OPENER_TRACE_INFO("List Interfaces\n");
+          HandleReceivedListInterfacesCommand(&encapsulation_data,
+                                              outgoing_message);
+          break;
+
+        /* The following commands are not to be sent via UDP */
+        case (kEncapsulationCommandNoOperation):
+        case (kEncapsulationCommandRegisterSession):
+        case (kEncapsulationCommandUnregisterSession):
+        case (kEncapsulationCommandSendRequestReplyData):
+        case (kEncapsulationCommandSendUnitData):
+        default:
+          OPENER_TRACE_INFO("No command\n");
+          //TODO: Check this
+          encapsulation_data.status =
+            kEncapsulationProtocolInvalidCommand;
+          encapsulation_data.data_length = 0;
+          break;
+      }
+
+      if (kEipStatusOk < status) {
+        /* if status is greater than 0 data has to be sent */
+        //status = EncapsulateData(&encapsulation_data);
+      }
+    }
+  }
+  return outgoing_message->used_message_length;
+}
+
+void SkipEncapsulationHeader(ENIPMessage *const outgoing_message) {
+  MoveMessageNOctets(ENCAPSULATION_HEADER_LENGTH,
+                     &outgoing_message->current_message_position);
+}
+
+void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
+                                 const size_t command_specific_data_length,
+                                 const size_t session_handle,
+                                 const EncapsulationProtocolErrorCode encapsulation_protocol_status,
+                                 ENIPMessage *const outgoing_message) {
+  outgoing_message->used_message_length += AddIntToMessage(
+    receive_data->command_code,
+    &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddIntToMessage(
+    command_specific_data_length,
+    &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddDintToMessage(session_handle,
+                                                            &outgoing_message->current_message_position); //Session handle
+  outgoing_message->used_message_length += AddDintToMessage(
+    encapsulation_protocol_status,
+    &outgoing_message->current_message_position);                                                         //Status
+  memcpy(outgoing_message->current_message_position,
+         receive_data->sender_context, kSenderContextSize);                // sender context
+  outgoing_message->current_message_position += kSenderContextSize;
+  outgoing_message->used_message_length += kSenderContextSize;
+  outgoing_message->used_message_length += AddDintToMessage(0,
+                                                            &outgoing_message->current_message_position); // options
+}
+
+/** @brief generate reply with "Communications Services" + compatibility Flags.
+ *  @param receive_data pointer to structure with received data
+ *  @param outgoing_message The outgoing ENIP message
+ */
+void HandleReceivedListServicesCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message) {
+
+  /* Create encapsulation header */
+  const size_t kListServicesCommandSpecificDataLength = sizeof(CipUint)
+                                                        + sizeof(
+    g_interface_information);
+  GenerateEncapsulationHeader(receive_data,
+                              kListServicesCommandSpecificDataLength,
+                              0, /* Session handle will be ignored */
+                              kEncapsulationProtocolSuccess,                             /* Protocol status */
+                              outgoing_message);
+
+  /* Command specific data copy Interface data to msg for sending */
+  outgoing_message->used_message_length += AddIntToMessage(1,
+                                                           &outgoing_message->current_message_position); // Item count
+  outgoing_message->used_message_length += AddIntToMessage(
+    g_interface_information.type_code,
+    &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddIntToMessage(
+    (EipUint16) (g_interface_information.length - 4),
+    &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddIntToMessage(
+    g_interface_information.encapsulation_protocol_version,
+    &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddIntToMessage(
+    g_interface_information.capability_flags,
+    &outgoing_message->current_message_position);
+  memcpy(outgoing_message->current_message_position,
+         g_interface_information.name_of_service,
+         sizeof(g_interface_information.name_of_service) );
+  outgoing_message->used_message_length +=
+    sizeof(g_interface_information.name_of_service);
+}
+
+void HandleReceivedListInterfacesCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message) {
+
+  /* Encapsulation header */
+  const size_t kListInterfacesCommandSpecificDataLength = sizeof(CipUint)
+                                                          + sizeof(
+    g_interface_information);
+  GenerateEncapsulationHeader(receive_data,
+                              kListInterfacesCommandSpecificDataLength,
+                              0, /* Session handle will be ignored */
+                              kEncapsulationProtocolSuccess,
+                              outgoing_message);
+  /* Command specific data */
+  outgoing_message->used_message_length += AddIntToMessage(0x0000,
+                                                           &outgoing_message->current_message_position); /* Reply 0 for no information being returned */
+}
+
+void HandleReceivedListIdentityCommandTcp(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message) {
+  EncapsulateListIdentityResponseMessage(receive_data, outgoing_message);
+}
+
+void HandleReceivedListIdentityCommandUdp(const int socket,
+                                          const struct sockaddr_in *const from_address,
+                                          const EncapsulationData *const receive_data,
+                                          ENIPMessage *const outgoing_message) {
+  DelayedEncapsulationMessage *delayed_message_buffer = NULL;
+  ENIPMessage* p_outgoing_message = NULL;
+
+  for (size_t i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
+       i++) {
+    if (kEipInvalidSocket == g_delayed_encapsulation_messages[i].socket) {
+      delayed_message_buffer = &(g_delayed_encapsulation_messages[i]);
+
+      p_outgoing_message = &(delayed_message_buffer->outgoing_message);
+      InitializeENIPMessage(p_outgoing_message);
+      break;
+    }
+  }
+
+  if (NULL != delayed_message_buffer) {
+    delayed_message_buffer->socket = socket;
+    memcpy( (&delayed_message_buffer->receiver), from_address,
+            sizeof(struct sockaddr_in) );
+
+    DetermineDelayTime(receive_data->communication_buffer_start,
+                       delayed_message_buffer);
+
+    EncapsulateListIdentityResponseMessage(receive_data, p_outgoing_message);
+  }
+}
+
+void EncapsulateListIdentityResponseMessage(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message) {
+
+
+  const CipUint kEncapsulationCommandListIdentityCommandSpecificLength =
+    sizeof(CipUint) + sizeof(CipInt) + sizeof(CipUint) + sizeof(CipUdint) +
+    8 *
+    sizeof(CipUsint) + sizeof(CipUint) + sizeof(CipUint) + sizeof(CipUint) + 2 *
+    sizeof(CipUsint) + sizeof(CipWord) + sizeof(CipUdint) +
+    sizeof(
+      CipUsint) + product_name_.length + sizeof(CipUsint);
+  const CipUint kEncapsulationCommandListIdentityLength =
+    kEncapsulationCommandListIdentityCommandSpecificLength + sizeof(CipUint) +
+    sizeof(CipUint)
+    + sizeof(CipUint);               /* Last element is item count */
+
+  GenerateEncapsulationHeader(receive_data,
+                              kEncapsulationCommandListIdentityLength,
+                              0,   /* Session handle will be ignored by receiver */
+                              kEncapsulationProtocolSuccess,
+                              outgoing_message);
+
+  outgoing_message->used_message_length += AddIntToMessage(1,
+                                                           &outgoing_message->current_message_position); /* Item count: one item */
+
+  /* Item ID*/
+  const CipUint kItemIDCipIdentity = 0x0C;
+  outgoing_message->used_message_length += AddIntToMessage(
+    kItemIDCipIdentity,
+    &outgoing_message->current_message_position);
+
+  outgoing_message->used_message_length += AddIntToMessage(
+    kEncapsulationCommandListIdentityCommandSpecificLength,
+    &outgoing_message->current_message_position);
+
+  outgoing_message->used_message_length += AddIntToMessage(
+    kSupportedProtocolVersion,
+    &outgoing_message->current_message_position);
+
+  outgoing_message->used_message_length += EncapsulateIpAddress(
+    htons(kOpenerEthernetPort), interface_configuration_.ip_address,
+    &outgoing_message->current_message_position);
+
+  /** Array of USINT - length 8 shall be set to zero */
+  memset(outgoing_message->current_message_position, 0, 8);
+  outgoing_message->used_message_length += MoveMessageNOctets(8,
+                                                              (const CipOctet **) &outgoing_message->current_message_position);
+
+  outgoing_message->used_message_length += AddIntToMessage(vendor_id_,
+                                                           &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddIntToMessage(device_type_,
+                                                           &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddIntToMessage(product_code_,
+                                                           &outgoing_message->current_message_position);
+  *(outgoing_message->current_message_position)++ = revision_.major_revision;
+  outgoing_message->used_message_length++;
+  *(outgoing_message->current_message_position)++ = revision_.minor_revision;
+  outgoing_message->used_message_length++;
+  outgoing_message->used_message_length += AddIntToMessage(status_,
+                                                           &outgoing_message->current_message_position);
+  outgoing_message->used_message_length += AddDintToMessage(serial_number_,
+                                                            &outgoing_message->current_message_position);
+  *outgoing_message->current_message_position++ =
+    (unsigned char) product_name_.length;
+  outgoing_message->used_message_length++;
+
+  memcpy(outgoing_message->current_message_position, product_name_.string,
+         product_name_.length);
+  outgoing_message->current_message_position += product_name_.length;
+  outgoing_message->used_message_length += product_name_.length;
+
+  *outgoing_message->current_message_position++ = 0xFF;
+  outgoing_message->used_message_length++;
+
+}
+
+void DetermineDelayTime(const EipByte *const buffer_start,
+                        DelayedEncapsulationMessage *const delayed_message_buffer)
+{
+
+  MoveMessageNOctets(12, (const CipOctet **) &buffer_start);       /* start of the sender context */
+  EipUint16 maximum_delay_time = GetIntFromMessage(
+    (const EipUint8 **const ) &buffer_start);
+
+  if (0 == maximum_delay_time) {
+    maximum_delay_time = kListIdentityDefaultDelayTime;
+  } else if (kListIdentityMinimumDelayTime > maximum_delay_time) {       /* if maximum_delay_time is between 1 and 500ms set it to 500ms */
+    maximum_delay_time = kListIdentityMinimumDelayTime;
+  }
+
+  delayed_message_buffer->time_out = rand() % maximum_delay_time ;
+}
+
+void EncapsulateRegisterSessionCommandResponseMessage(
+  const EncapsulationData *const receive_data,
+  const size_t session_handle,
+  const EncapsulationProtocolErrorCode encapsulation_protocol_status,
+  ENIPMessage *const outgoing_message) {
+
+  /* Encapsulation header */
+  const size_t kListInterfacesCommandSpecificDataLength = sizeof(CipUint)
+                                                          + sizeof(CipUint);
+  assert(kListInterfacesCommandSpecificDataLength == 4);
+  GenerateEncapsulationHeader(receive_data,
+                              kListInterfacesCommandSpecificDataLength,
+                              session_handle,
+                              encapsulation_protocol_status,
+                              outgoing_message);
+
+  outgoing_message->used_message_length += AddIntToMessage(1,
+                                                           &outgoing_message->current_message_position); /* protocol version*/
+  outgoing_message->used_message_length += AddIntToMessage(
+    0,
+    &outgoing_message->current_message_position);                     /* Options flag, shall be set to zero */
+}
+
+/* @brief Check supported protocol, generate session handle, send replay back to originator.
+ * @param socket Socket this request is associated to. Needed for double register check
+ * @param receive_data Pointer to received data with request/response.
+ */
+void HandleReceivedRegisterSessionCommand(int socket,
+                                          const EncapsulationData *const receive_data,
+                                          ENIPMessage *const outgoing_message) {
+  int session_index = 0;
+  size_t session_handle = 0;
+  EncapsulationProtocolErrorCode encapsulation_protocol_status =
+    kEncapsulationProtocolSuccess;
+
+  EipUint16 protocol_version =
+    GetIntFromMessage(
+      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);
+  EipUint16 option_flag =
+    GetIntFromMessage(
+      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);
+
+  /* check if requested protocol version is supported and the register session option flag is zero*/
+  if ( (0 < protocol_version)
+       && (protocol_version <= kSupportedProtocolVersion)
+       && (0 == option_flag) ) {                 /*Option field should be zero*/
+    /* check if the socket has already a session open */
+    for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+      if (g_registered_sessions[i] == socket) {
+        /* the socket has already registered a session this is not allowed*/
+        OPENER_TRACE_INFO(
+          "Error: A session is already registered at socket %d\n",
+          socket);
+        session_handle = i + 1; /*return the already assigned session back, the cip spec is not clear about this needs to be tested*/
+        encapsulation_protocol_status = kEncapsulationProtocolInvalidCommand;
+        session_index = kSessionStatusInvalid;
+        break;
+      }
+    }
+
+    if (kSessionStatusInvalid != session_index) {
+      session_index = GetFreeSessionIndex();
+      if (kSessionStatusInvalid == session_index)                   /* no more sessions available */
+      {
+        encapsulation_protocol_status =
+          kEncapsulationProtocolInsufficientMemory;
+      } else {                   /* successful session registered */
+        SocketTimer *socket_timer = SocketTimerArrayGetEmptySocketTimer(
+          g_timestamps,
+          OPENER_NUMBER_OF_SUPPORTED_SESSIONS);
+        SocketTimerSetSocket(socket_timer, socket);
+        SocketTimerSetLastUpdate(socket_timer, g_actual_time);
+        g_registered_sessions[session_index] = socket;                         /* store associated socket */
+        session_handle = session_index + 1;
+        encapsulation_protocol_status = kEncapsulationProtocolSuccess;
+      }
+    }
+  } else {       /* protocol not supported */
+    encapsulation_protocol_status = kEncapsulationProtocolUnsupportedProtocol;
+  }
+
+  EncapsulateRegisterSessionCommandResponseMessage(receive_data,
+                                                   session_handle,
+                                                   encapsulation_protocol_status,
+                                                   outgoing_message);
+
+}
+
+/*   TODO: Update and doxyfy
+ * INT8 UnregisterSession(struct S_Encapsulation_Data *pa_S_ReceiveData)
+ *   close all corresponding TCP connections and delete session handle.
+ *      pa_S_ReceiveData pointer to unregister session request with corresponding socket handle.
+ */
+EipStatus HandleReceivedUnregisterSessionCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message) {
+  OPENER_TRACE_INFO("encap.c: Unregister Session Command\n");
+  if ( (0 < receive_data->session_handle) && (receive_data->session_handle <=
+                                              OPENER_NUMBER_OF_SUPPORTED_SESSIONS) )
+  {
+    size_t i = receive_data->session_handle - 1;
+    if (kEipInvalidSocket != g_registered_sessions[i]) {
+      CloseTcpSocket(g_registered_sessions[i]);
+      g_registered_sessions[i] = kEipInvalidSocket;
+      CloseClass3ConnectionBasedOnSession(i + 1);
+      return kEipStatusOk;
+    }
+  }
+
+  /* no such session registered */
+  GenerateEncapsulationHeader(receive_data,
+                              0,
+                              receive_data->session_handle,
+                              kEncapsulationProtocolInvalidSessionHandle,
+                              outgoing_message);
+  return kEipStatusOkSend;
+}
+
+/** @brief Call Connection Manager.
+ *  @param receive_data Pointer to structure with data and header information.
+ *  @param originator_address Address of the originator as received from socket
+ *  @param outgoing_message The outgoing ENIP message
+ */
+EipStatus HandleReceivedSendUnitDataCommand(
+  const EncapsulationData *const receive_data,
+  const struct sockaddr *const originator_address,
+  ENIPMessage *const outgoing_message) {
+  EipStatus return_value = kEipStatusOkSend;
+
+  if (receive_data->data_length >= 6) {
+    /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
+    /* don't use the data yet */
+    GetDintFromMessage(
+      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over null interface handle*/
+    GetIntFromMessage(
+      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over unused timeout value*/
+    ( (EncapsulationData *const)receive_data )->data_length -= 6;             /* the rest is in CPF format*/
+
+    if (kSessionStatusValid == CheckRegisteredSessions(receive_data) )            /* see if the EIP session is registered*/
+    {
+      EipInt16 send_size =
+        NotifyConnectedCommonPacketFormat(receive_data,
+                                          originator_address,
+                                          outgoing_message);
+
+      return_value = send_size;
+
+      if (send_size < 0) {                   /* need to send reply */
+        return_value = kEipStatusError;
+      }
+    } else {             /* received a package with non registered session handle */
+      InitializeENIPMessage(outgoing_message);
+      GenerateEncapsulationHeader(receive_data,
+                                  0,
+                                  receive_data->session_handle,
+                                  kEncapsulationProtocolInvalidSessionHandle,
+                                  outgoing_message);
+    }
+  }
+  return return_value;
+}
+
+/** @brief Call UCMM or Message Router if UCMM not implemented.
+ *  @param receive_data Pointer to structure with data and header information.
+ *  @param originator_address Address of the originator as received from socket
+ *  @param outgoing_message The outgoing ENIP message
+ *  @return status      kEipStatusOk .. success.
+ *                      kEipStatusError .. error
+ */
+EipStatus HandleReceivedSendRequestResponseDataCommand(
+  const EncapsulationData *const receive_data,
+  const struct sockaddr *const originator_address,
+  ENIPMessage *const outgoing_message) {
+  EipStatus return_value = kEipStatusOkSend;
+
+  if (receive_data->data_length >= 6) {
+    /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
+    /* don't use the data yet */
+    GetDintFromMessage(
+      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over null interface handle*/
+    GetIntFromMessage(
+      (const EipUint8 **const ) &receive_data->current_communication_buffer_position);                            /* skip over unused timeout value*/
+    ( (EncapsulationData *const)receive_data )->data_length -= 6;             /* the rest is in CPF format*/
+
+    if (kSessionStatusValid == CheckRegisteredSessions(receive_data) )            /* see if the EIP session is registered*/
+    {
+      EipInt16 send_size =
+        NotifyCommonPacketFormat(receive_data,
+                                 originator_address,
+                                 outgoing_message);
+      return_value = send_size;
+
+      if (send_size < 0) {                   /* need to send reply */
+        return_value = kEipStatusError;
+      }
+    } else {             /* received a package with non registered session handle */
+      InitializeENIPMessage(outgoing_message);
+      GenerateEncapsulationHeader(receive_data,
+                                  0,
+                                  receive_data->session_handle,
+                                  kEncapsulationProtocolInvalidSessionHandle,
+                                  outgoing_message);
+    }
+  }
+  return return_value;
+}
+
+EipStatus HandleReceivedInvalidCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message) {
+
+  /* Encapsulation header */
+  GenerateEncapsulationHeader(receive_data,
+                              0,
+                              receive_data->session_handle,
+                              kEncapsulationProtocolInvalidCommand,
+                              outgoing_message);
+  return outgoing_message->used_message_length;
+
+}
+
+/** @brief search for available sessions an return index.
+ *  @return return index of free session in anRegisteredSessions.
+ *                      kInvalidSession .. no free session available
+ */
+int GetFreeSessionIndex(void) {
+  for (size_t session_index = 0;
+       session_index < OPENER_NUMBER_OF_SUPPORTED_SESSIONS;
+       session_index++) {
+    if (kEipInvalidSocket == g_registered_sessions[session_index]) {
+      return session_index;
+    }
+  }
+  return kSessionStatusInvalid;
+}
+
+/** @brief copy data from pa_buf in little endian to host in structure.
+ * @param receive_buffer Received message
+ * @param receive_buffer_length Length of the data in receive_buffer. Might be more than one message
+ * @param encapsulation_data	structure to which data shall be copied
+ * @return return difference between bytes in pa_buf an data_length
+ *              0 .. full package received
+ *                      >0 .. more than one packet received
+ *                      <0 .. only fragment of data portion received
+ */
+EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
+                                      int receive_buffer_length,
+                                      EncapsulationData *const encapsulation_data)
+{
+  encapsulation_data->communication_buffer_start =
+    (EipUint8 *) receive_buffer;
+  encapsulation_data->command_code = GetIntFromMessage(&receive_buffer);
+  encapsulation_data->data_length = GetIntFromMessage(&receive_buffer);
+  encapsulation_data->session_handle = GetDintFromMessage(&receive_buffer);
+  encapsulation_data->status = GetDintFromMessage(&receive_buffer);
+
+  memcpy(encapsulation_data->sender_context, receive_buffer,
+         kSenderContextSize);
+  receive_buffer += kSenderContextSize;
+  encapsulation_data->options = GetDintFromMessage(&receive_buffer);
+  encapsulation_data->current_communication_buffer_position =
+    (EipUint8 *) receive_buffer;
+  return (receive_buffer_length - ENCAPSULATION_HEADER_LENGTH
+          - encapsulation_data->data_length);
+}
+
+/** @brief Check if received package belongs to registered session.
+ *  @param receive_data Received data.
+ *  @return 0 .. Session registered
+ *              kInvalidSession .. invalid session -> return unsupported command received
+ */
+SessionStatus CheckRegisteredSessions(
+  const EncapsulationData *const receive_data) {
+  if ( (0 < receive_data->session_handle) && (receive_data->session_handle <=
+                                              OPENER_NUMBER_OF_SUPPORTED_SESSIONS) )
+  {
+    if (kEipInvalidSocket
+        != g_registered_sessions[receive_data->session_handle - 1]) {
+      return kSessionStatusValid;
+    }
+  }
+  return kSessionStatusInvalid;
+}
+
+void CloseSessionBySessionHandle(
+  const CipConnectionObject *const connection_object) {
+  OPENER_TRACE_INFO("encap.c: Close session by handle\n");
+  size_t session_handle = connection_object->associated_encapsulation_session;
+  CloseTcpSocket(g_registered_sessions[session_handle - 1]);
+  g_registered_sessions[session_handle - 1] = kEipInvalidSocket;
+  OPENER_TRACE_INFO("encap.c: Close session by handle done\n");
+}
+
+void CloseSession(int socket) {
+  OPENER_TRACE_INFO("encap.c: Close session\n");
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if (g_registered_sessions[i] == socket) {
+      CloseTcpSocket(socket);
+      g_registered_sessions[i] = kEipInvalidSocket;
+      CloseClass3ConnectionBasedOnSession(i + 1);
+      break;
+    }
+  }
+  OPENER_TRACE_INFO("encap.c: Close session done\n");
+}
+
+void RemoveSession(const int socket) {
+  OPENER_TRACE_INFO("encap.c: Removing session\n");
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if (g_registered_sessions[i] == socket) {
+      g_registered_sessions[i] = kEipInvalidSocket;
+      CloseClass3ConnectionBasedOnSession(i + 1);
+      break;
+    }
+  }
+  OPENER_TRACE_INFO("encap.c: Session removed\n");
+}
+
+void EncapsulationShutDown(void) {
+  OPENER_TRACE_INFO("encap.c: Encapsulation shutdown\n");
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if (kEipInvalidSocket != g_registered_sessions[i]) {
+      CloseTcpSocket(g_registered_sessions[i]);
+      g_registered_sessions[i] = kEipInvalidSocket;
+    }
+  }
+}
+
+void ManageEncapsulationMessages(const MilliSeconds elapsed_time) {
+  for (size_t i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
+       i++) {
+    if (kEipInvalidSocket != g_delayed_encapsulation_messages[i].socket) {
+      g_delayed_encapsulation_messages[i].time_out -= elapsed_time;
+      if (0 >= g_delayed_encapsulation_messages[i].time_out) {
+        /* If delay is reached or passed, send the UDP message */
+        sendto(g_delayed_encapsulation_messages[i].socket,
+                    (char *) g_delayed_encapsulation_messages[i].outgoing_message.message_buffer,
+                    g_delayed_encapsulation_messages[i].outgoing_message.used_message_length, 0,
+                    (struct sockaddr *) &(g_delayed_encapsulation_messages[i].receiver), 
+                    sizeof(struct sockaddr));
+        g_delayed_encapsulation_messages[i].socket = kEipInvalidSocket;
+      }
+    }
+  }
+}
+
+void CloseEncapsulationSessionBySockAddr(
+  const CipConnectionObject *const connection_object) {
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if (kEipInvalidSocket != g_registered_sessions[i]) {
+      struct sockaddr_in encapsulation_session_addr = { 0 };
+      socklen_t addrlength = sizeof(encapsulation_session_addr);
+      if (getpeername(g_registered_sessions[i],
+                      &encapsulation_session_addr, &addrlength) < 0) {                   /* got error */
+        int error_code = GetSocketErrorNumber();
+        char *error_message = GetErrorMessage(error_code);
+        OPENER_TRACE_ERR(
+          "encap.c: error on getting peer name on closing session: %d - %s\n",
+          error_code, error_message);
+        FreeErrorMessage(error_message);
+      }
+      if (encapsulation_session_addr.sin_addr.s_addr
+          == connection_object->originator_address.sin_addr.s_addr) {
+        CloseSession(g_registered_sessions[i]);
+      }
+    }
+  }
+}
+
+size_t GetSessionFromSocket(const int socket_handle) {
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if (socket_handle == g_registered_sessions[i]) {
+      return i;
+    }
+  }
+  return OPENER_NUMBER_OF_SUPPORTED_SESSIONS;
+}
+
+void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle) {
+  DoublyLinkedListNode *node = connection_list.first;
+  while (NULL != node) {
+    CipConnectionObject *connection_object = node->data;
+    if (kConnectionObjectTransportClassTriggerTransportClass3
+        == ConnectionObjectGetTransportClassTriggerTransportClass(
+          connection_object)
+        && connection_object->associated_encapsulation_session
+        == encapsulation_session_handle) {
+      connection_object->connection_close_function(connection_object);
+    }
+    node = node->next;
+  }
+}

+ 132 - 132
source/src/enet_encap/encap.h

@@ -1,132 +1,132 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-#ifndef OPENER_ENCAP_H_
-#define OPENER_ENCAP_H_
-
-#include "typedefs.h"
-#include "cipconnectionobject.h"
-
-/** @file encap.h
- * @brief This file contains the public interface of the encapsulation layer
- */
-
-/**  @defgroup ENCAP OpENer Ethernet encapsulation layer
- * The Ethernet encapsulation layer handles provides the abstraction between the Ethernet and the CIP layer.
- */
-
-/*** defines ***/
-
-#define ENCAPSULATION_HEADER_LENGTH     24
-
-/** @brief Ethernet/IP standard port */
-static const int kOpenerEthernetPort = 0xAF12;
-
-/** @brief definition of status codes in encapsulation protocol
- * All other codes are either legacy codes, or reserved for future use
- *  */
-typedef enum {
-  kEncapsulationProtocolSuccess = 0x0000,
-  kEncapsulationProtocolInvalidCommand = 0x0001,
-  kEncapsulationProtocolInsufficientMemory = 0x0002,
-  kEncapsulationProtocolIncorrectData = 0x0003,
-  kEncapsulationProtocolInvalidSessionHandle = 0x0064,
-  kEncapsulationProtocolInvalidLength = 0x0065,
-  kEncapsulationProtocolUnsupportedProtocol = 0x0069
-} EncapsulationProtocolErrorCode;
-
-/*** structs ***/
-typedef struct encapsulation_data {
-  CipUint command_code;
-  CipUint data_length;
-  CipUdint session_handle;
-  CipUdint status;
-  CipOctet sender_context[8]; /**< length of 8, according to the specification */
-  CipUdint options;
-  const EipUint8 *communication_buffer_start; /**< Pointer to the communication buffer used for this message */
-  const EipUint8 *current_communication_buffer_position; /**< The current position in the communication buffer during the decoding process */
-} EncapsulationData;
-
-typedef struct encapsulation_interface_information {
-  EipUint16 type_code;
-  EipUint16 length;
-  EipUint16 encapsulation_protocol_version;
-  EipUint16 capability_flags;
-  EipInt8 name_of_service[16];
-} EncapsulationInterfaceInformation;
-
-/*** global variables (public) ***/
-
-/*** public functions ***/
-/** @ingroup ENCAP
- * @brief Initialize the encapsulation layer.
- */
-void EncapsulationInit(void);
-
-/** @ingroup ENCAP
- * @brief Shutdown the encapsulation layer.
- *
- * This means that all open sessions including their sockets are closed.
- */
-void EncapsulationShutDown(void);
-
-/** @ingroup ENCAP
- * @brief Handle delayed encapsulation message responses
- *
- * Certain encapsulation message requests require a delayed sending of the response
- * message. This functions checks if messages need to be sent and performs the
- * sending.
- */
-void ManageEncapsulationMessages(const MilliSeconds elapsed_time);
-
-size_t GetSessionFromSocket(const int socket_handle);
-
-void RemoveSession(const int socket);
-
-void CloseSessionBySessionHandle(
-  const CipConnectionObject *const connection_object);
-
-void CloseEncapsulationSessionBySockAddr(
-  const CipConnectionObject *const connection_object);
-
-void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle);
-
-/* No reason to use this functions outside the encapsulation layer, they are here for testing */
-typedef struct enip_message ENIPMessage;
-
-void EncapsulateListIdentityResponseMessage(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message);
-
-EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
-                                      int receive_buffer_length,
-                                      EncapsulationData *const encapsulation_data);
-
-void SkipEncapsulationHeader(ENIPMessage *const outgoing_message);
-
-void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
-                                 const size_t command_specific_data_length,
-                                 const size_t session_handle,
-                                 const EncapsulationProtocolErrorCode encapsulation_protocol_status,
-                                 ENIPMessage *const outgoing_message);
-
-void HandleReceivedListServicesCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message);
-
-void HandleReceivedListInterfacesCommand(
-  const EncapsulationData *const receive_data,
-  ENIPMessage *const outgoing_message);
-
-void HandleReceivedRegisterSessionCommand(int socket,
-                                          const EncapsulationData *const receive_data,
-                                          ENIPMessage *const outgoing_message);
-
-EipStatus HandleReceivedSendRequestResponseDataCommand(
-  const EncapsulationData *const receive_data,
-  const struct sockaddr *const originator_address,
-  ENIPMessage *const outgoing_message);
-
-#endif /* OPENER_ENCAP_H_ */
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#ifndef OPENER_ENCAP_H_
+#define OPENER_ENCAP_H_
+
+#include "typedefs.h"
+#include "cipconnectionobject.h"
+
+/** @file encap.h
+ * @brief This file contains the public interface of the encapsulation layer
+ */
+
+/**  @defgroup ENCAP OpENer Ethernet encapsulation layer
+ * The Ethernet encapsulation layer handles provides the abstraction between the Ethernet and the CIP layer.
+ */
+
+/*** defines ***/
+
+#define ENCAPSULATION_HEADER_LENGTH     24
+
+/** @brief Ethernet/IP standard port */
+static const int kOpenerEthernetPort = 0xAF12;
+
+/** @brief definition of status codes in encapsulation protocol
+ * All other codes are either legacy codes, or reserved for future use
+ *  */
+typedef enum {
+  kEncapsulationProtocolSuccess = 0x0000,
+  kEncapsulationProtocolInvalidCommand = 0x0001,
+  kEncapsulationProtocolInsufficientMemory = 0x0002,
+  kEncapsulationProtocolIncorrectData = 0x0003,
+  kEncapsulationProtocolInvalidSessionHandle = 0x0064,
+  kEncapsulationProtocolInvalidLength = 0x0065,
+  kEncapsulationProtocolUnsupportedProtocol = 0x0069
+} EncapsulationProtocolErrorCode;
+
+/*** structs ***/
+typedef struct encapsulation_data {
+  CipUint command_code;
+  CipUint data_length;
+  CipUdint session_handle;
+  CipUdint status;
+  CipOctet sender_context[8]; /**< length of 8, according to the specification */
+  CipUdint options;
+  const EipUint8 *communication_buffer_start; /**< Pointer to the communication buffer used for this message */
+  const EipUint8 *current_communication_buffer_position; /**< The current position in the communication buffer during the decoding process */
+} EncapsulationData;
+
+typedef struct encapsulation_interface_information {
+  EipUint16 type_code;
+  EipUint16 length;
+  EipUint16 encapsulation_protocol_version;
+  EipUint16 capability_flags;
+  EipInt8 name_of_service[16];
+} EncapsulationInterfaceInformation;
+
+/*** global variables (public) ***/
+
+/*** public functions ***/
+/** @ingroup ENCAP
+ * @brief Initialize the encapsulation layer.
+ */
+void EncapsulationInit(void);
+
+/** @ingroup ENCAP
+ * @brief Shutdown the encapsulation layer.
+ *
+ * This means that all open sessions including their sockets are closed.
+ */
+void EncapsulationShutDown(void);
+
+/** @ingroup ENCAP
+ * @brief Handle delayed encapsulation message responses
+ *
+ * Certain encapsulation message requests require a delayed sending of the response
+ * message. This functions checks if messages need to be sent and performs the
+ * sending.
+ */
+void ManageEncapsulationMessages(const MilliSeconds elapsed_time);
+
+size_t GetSessionFromSocket(const int socket_handle);
+
+void RemoveSession(const int socket);
+
+void CloseSessionBySessionHandle(
+  const CipConnectionObject *const connection_object);
+
+void CloseEncapsulationSessionBySockAddr(
+  const CipConnectionObject *const connection_object);
+
+void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle);
+
+/* No reason to use this functions outside the encapsulation layer, they are here for testing */
+typedef struct enip_message ENIPMessage;
+
+void EncapsulateListIdentityResponseMessage(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message);
+
+EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
+                                      int receive_buffer_length,
+                                      EncapsulationData *const encapsulation_data);
+
+void SkipEncapsulationHeader(ENIPMessage *const outgoing_message);
+
+void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
+                                 const size_t command_specific_data_length,
+                                 const size_t session_handle,
+                                 const EncapsulationProtocolErrorCode encapsulation_protocol_status,
+                                 ENIPMessage *const outgoing_message);
+
+void HandleReceivedListServicesCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message);
+
+void HandleReceivedListInterfacesCommand(
+  const EncapsulationData *const receive_data,
+  ENIPMessage *const outgoing_message);
+
+void HandleReceivedRegisterSessionCommand(int socket,
+                                          const EncapsulationData *const receive_data,
+                                          ENIPMessage *const outgoing_message);
+
+EipStatus HandleReceivedSendRequestResponseDataCommand(
+  const EncapsulationData *const receive_data,
+  const struct sockaddr *const originator_address,
+  ENIPMessage *const outgoing_message);
+
+#endif /* OPENER_ENCAP_H_ */

+ 149 - 149
source/src/ports/POSIX/sample_application/opener_user_conf.h

@@ -1,149 +1,149 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-#ifndef OPENER_USER_CONF_H_
-#define OPENER_USER_CONF_H_
-
-/** @file POSIX/sample_application/opener_user_conf.h
- * @brief OpENer configuration setup
- *
- * This file contains the general application specific configuration for OpENer.
- *
- * Furthermore you have to specific platform specific network include files.
- * OpENer needs definitions for the following data-types
- * and functions:
- *    - struct sockaddr_in
- *    - AF_INET
- *    - INADDR_ANY
- *    - htons
- *    - ntohl
- *    - inet_addr
- */
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <sys/select.h>
-#include <assert.h>
-
-#include "typedefs.h"
-
-/** @brief Identity configuration of the device */
-#include "devicedata.h"
-
-/** @brief Define the number of objects that may be used in connections
- *
- *  This number needs only to consider additional objects. Connections to
- *  the connection manager object as well as to the assembly object are supported
- *  in any case.
- */
-#define OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS 1
-
-/** @brief Define the number of supported explicit connections.
- *  According to ODVA's PUB 70 this number should be equal or greater than 6.
- */
-#define OPENER_CIP_NUM_EXPLICIT_CONNS 6
-
-/** @brief Define the number of supported exclusive owner connections.
- *  Each of these connections has to be configured with the function
- *  void configureExclusiveOwnerConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
- *
- */
-#define OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS 1
-
-/** @brief  Define the number of supported input only connections.
- *  Each of these connections has to be configured with the function
- *  void configureInputOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
- *
- */
-#define OPENER_CIP_NUM_INPUT_ONLY_CONNS 1
-
-/** @brief Define the number of supported input only connections per connection path
- */
-#define OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH 3
-
-/** @brief Define the number of supported listen only connections.
- *  Each of these connections has to be configured with the function
- *  void configureListenOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
- *
- */
-#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS 1
-
-/** @brief Define the number of supported Listen only connections per connection path
- */
-#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH   3
-
-/** @brief The number of bytes used for the buffer that will be used for generating any
- *  reply data of messages. There are two uses in OpENer:
- *    1. Explicit messages will use this buffer to store the data generated by the request
- *    2. I/O Connections will use this buffer for the produced data
- */
-#define OPENER_MESSAGE_DATA_REPLY_BUFFER 100
-
-/** @brief Number of sessions that can be handled at the same time
- */
-#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 20
-
-/** @brief The time in ms of the timer used in this implementations, time base for time-outs and production timers
- */
-static const MilliSeconds kOpenerTimerTickInMilliSeconds = 10;
-
-#ifdef OPENER_WITH_TRACES
-/* If we have tracing enabled provide print tracing macro */
-#include <stdio.h>
-
-#define LOG_TRACE(...)  fprintf(stderr,__VA_ARGS__)
-
-/*#define PRINT_TRACE(args...)  fprintf(stderr,args);*/
-
-/** @brief A specialized assertion command that will log the assertion and block
- *  further execution in an while(1) loop.
- */
-#ifdef IDLING_ASSERT
-#define OPENER_ASSERT(assertion) \
-  do { \
-    if( !(assertion) ) { \
-      LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", \
-                # assertion, \
-                __FILE__, \
-                __LINE__); \
-      while(1) {  } \
-    } \
-  } while(0);
-
-/* else use standard assert() */
-//#include <assert.h>
-//#include <stdio.h>
-//#define OPENER_ASSERT(assertion) assert(assertion)
-#else
-#define OPENER_ASSERT(assertion) assert(assertion);
-#endif
-#else
-
-/* for release builds remove assertion */
-#define OPENER_ASSERT(assertion)
-
-/* if there are any strange timing issues, you can try the version below, where the assertion is performed but the assert
- * function is not used
- */
-//#define OPENER_ASSERT(assertion) (assertion)
-/* else if you still want assertions to stop execution but without tracing, use the following */
-//#define OPENER_ASSERT(assertion) do { if(!(assertion)) { while(1){;} } } while (0)
-/* else use standard assert() */
-//#include <assert.h>
-//#include <stdio.h>
-//#define OPENER_ASSERT(assertion) assert(assertion)
-
-#endif
-
-/** @brief The number of bytes used for the Ethernet message buffer on
- * the PC port. For different platforms it may makes sense to
- * have more than one buffer.
- *
- *  This buffer size will be used for any received message.
- *  The same buffer is used for the replied explicit message.
- */
-#define PC_OPENER_ETHERNET_BUFFER_SIZE 512
-
-#endif /*OPENER_USER_CONF_H_*/
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#ifndef OPENER_USER_CONF_H_
+#define OPENER_USER_CONF_H_
+
+/** @file POSIX/sample_application/opener_user_conf.h
+ * @brief OpENer configuration setup
+ *
+ * This file contains the general application specific configuration for OpENer.
+ *
+ * Furthermore you have to specific platform specific network include files.
+ * OpENer needs definitions for the following data-types
+ * and functions:
+ *    - struct sockaddr_in
+ *    - AF_INET
+ *    - INADDR_ANY
+ *    - htons
+ *    - ntohl
+ *    - inet_addr
+ */
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <assert.h>
+
+#include "typedefs.h"
+
+/** @brief Identity configuration of the device */
+#include "devicedata.h"
+
+/** @brief Define the number of objects that may be used in connections
+ *
+ *  This number needs only to consider additional objects. Connections to
+ *  the connection manager object as well as to the assembly object are supported
+ *  in any case.
+ */
+#define OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS 1
+
+/** @brief Define the number of supported explicit connections.
+ *  According to ODVA's PUB 70 this number should be equal or greater than 6.
+ */
+#define OPENER_CIP_NUM_EXPLICIT_CONNS 6
+
+/** @brief Define the number of supported exclusive owner connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureExclusiveOwnerConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS 1
+
+/** @brief  Define the number of supported input only connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureInputOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS 1
+
+/** @brief Define the number of supported input only connections per connection path
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH 3
+
+/** @brief Define the number of supported listen only connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureListenOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS 1
+
+/** @brief Define the number of supported Listen only connections per connection path
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH   3
+
+/** @brief The number of bytes used for the buffer that will be used for generating any
+ *  reply data of messages. There are two uses in OpENer:
+ *    1. Explicit messages will use this buffer to store the data generated by the request
+ *    2. I/O Connections will use this buffer for the produced data
+ */
+#define OPENER_MESSAGE_DATA_REPLY_BUFFER 100
+
+/** @brief Number of sessions that can be handled at the same time
+ */
+#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 20
+
+/** @brief The time in ms of the timer used in this implementations, time base for time-outs and production timers
+ */
+static const MilliSeconds kOpenerTimerTickInMilliSeconds = 10;
+
+#ifdef OPENER_WITH_TRACES
+/* If we have tracing enabled provide print tracing macro */
+#include <stdio.h>
+
+#define LOG_TRACE(...)  fprintf(stderr,__VA_ARGS__)
+
+/*#define PRINT_TRACE(args...)  fprintf(stderr,args);*/
+
+/** @brief A specialized assertion command that will log the assertion and block
+ *  further execution in an while(1) loop.
+ */
+#ifdef IDLING_ASSERT
+#define OPENER_ASSERT(assertion) \
+  do { \
+    if( !(assertion) ) { \
+      LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", \
+                # assertion, \
+                __FILE__, \
+                __LINE__); \
+      while(1) {  } \
+    } \
+  } while(0);
+
+/* else use standard assert() */
+//#include <assert.h>
+//#include <stdio.h>
+//#define OPENER_ASSERT(assertion) assert(assertion)
+#else
+#define OPENER_ASSERT(assertion) assert(assertion);
+#endif
+#else
+
+/* for release builds remove assertion */
+#define OPENER_ASSERT(assertion)
+
+/* if there are any strange timing issues, you can try the version below, where the assertion is performed but the assert
+ * function is not used
+ */
+//#define OPENER_ASSERT(assertion) (assertion)
+/* else if you still want assertions to stop execution but without tracing, use the following */
+//#define OPENER_ASSERT(assertion) do { if(!(assertion)) { while(1){;} } } while (0)
+/* else use standard assert() */
+//#include <assert.h>
+//#include <stdio.h>
+//#define OPENER_ASSERT(assertion) assert(assertion)
+
+#endif
+
+/** @brief The number of bytes used for the Ethernet message buffer on
+ * the PC port. For different platforms it may makes sense to
+ * have more than one buffer.
+ *
+ *  This buffer size will be used for any received message.
+ *  The same buffer is used for the replied explicit message.
+ */
+#define PC_OPENER_ETHERNET_BUFFER_SIZE 512
+
+#endif /*OPENER_USER_CONF_H_*/

+ 51 - 51
source/src/ports/WIN32/networkhandler.c

@@ -1,51 +1,51 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-#include <string.h>
-#include <stdlib.h>
-#include <winsock2.h>
-#include <windows.h>
-#include <Ws2tcpip.h>
-
-#include "networkhandler.h"
-
-#include "generic_networkhandler.h"
-
-MicroSeconds GetMicroSeconds() {
-  LARGE_INTEGER performance_counter;
-  LARGE_INTEGER performance_frequency;
-
-  QueryPerformanceCounter(&performance_counter);
-  QueryPerformanceFrequency(&performance_frequency);
-
-  return (MicroSeconds) (performance_counter.QuadPart * 1000000LL
-                         / performance_frequency.QuadPart);
-}
-
-MilliSeconds GetMilliSeconds(void) {
-  return (MilliSeconds) (GetMicroSeconds() / 1000ULL);
-}
-
-EipStatus NetworkHandlerInitializePlatform(void) {
-  WSADATA wsaData;
-  const WORD wVersionRequested = MAKEWORD(2, 2);
-  WSAStartup(wVersionRequested, &wsaData);
-
-  return kEipStatusOk;
-}
-
-void CloseSocketPlatform(int socket_handle) {
-  closesocket(socket_handle);
-}
-
-int SetSocketToNonBlocking(int socket_handle) {
-  u_long iMode = 1;
-  return ioctlsocket(socket_handle, FIONBIO, &iMode);
-}
-
-int SetQosOnSocket(const int socket,
-                   CipUsint qos_value) {
-  return 0; // Dummy implementation, until a working one is viable
-}
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include <stdlib.h>
+#include <winsock2.h>
+#include <windows.h>
+#include <Ws2tcpip.h>
+
+#include "networkhandler.h"
+
+#include "generic_networkhandler.h"
+
+MicroSeconds GetMicroSeconds() {
+  LARGE_INTEGER performance_counter;
+  LARGE_INTEGER performance_frequency;
+
+  QueryPerformanceCounter(&performance_counter);
+  QueryPerformanceFrequency(&performance_frequency);
+
+  return (MicroSeconds) (performance_counter.QuadPart * 1000000LL
+                         / performance_frequency.QuadPart);
+}
+
+MilliSeconds GetMilliSeconds(void) {
+  return (MilliSeconds) (GetMicroSeconds() / 1000ULL);
+}
+
+EipStatus NetworkHandlerInitializePlatform(void) {
+  WSADATA wsaData;
+  const WORD wVersionRequested = MAKEWORD(2, 2);
+  WSAStartup(wVersionRequested, &wsaData);
+
+  return kEipStatusOk;
+}
+
+void CloseSocketPlatform(int socket_handle) {
+  closesocket(socket_handle);
+}
+
+int SetSocketToNonBlocking(int socket_handle) {
+  u_long iMode = 1;
+  return ioctlsocket(socket_handle, FIONBIO, &iMode);
+}
+
+int SetQosOnSocket(const int socket,
+                   CipUsint qos_value) {
+  return 0; // Dummy implementation, until a working one is viable
+}

+ 148 - 148
source/src/ports/WIN32/sample_application/opener_user_conf.h

@@ -1,148 +1,148 @@
-/*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved.
- *
- ******************************************************************************/
-#ifndef OPENER_USER_CONF_H_
-#define OPENER_USER_CONF_H_
-
-/** @file WIN32/sample_application/opener_user_conf.h
- * @brief OpENer configuration setup
- *
- * This file contains the general application specific configuration for OpENer.
- *
- * Furthermore you have to specific platform specific network include files.
- * OpENer needs definitions for the following data-types
- * and functions:
- *    - struct sockaddr_in
- *    - AF_INET
- *    - INADDR_ANY
- *    - htons
- *    - ntohl
- *    - inet_addr
- */
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-typedef unsigned short in_port_t;
-
-/** @brief Identity configuration of the device */
-#include "devicedata.h"
-
-#include "typedefs.h"
-
-/** @brief Define the number of objects that may be used in connections
- *
- *  This number needs only to consider additional objects. Connections to
- *  the connection manager object as well as to the assembly object are supported
- *  in any case.
- */
-#define OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS 1
-
-/** @brief Define the number of supported explicit connections.
- *  According to ODVA's PUB 70 this number should be greater than 6.
- */
-#define OPENER_CIP_NUM_EXPLICIT_CONNS 6
-
-/** @brief Define the number of supported exclusive owner connections.
- *  Each of these connections has to be configured with the function
- *  void configureExclusiveOwnerConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
- *
- */
-#define OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS 1
-
-/** @brief Define the number of supported input only connections.
- *  Each of these connections has to be configured with the function
- *  void configureInputOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
- *
- */
-#define OPENER_CIP_NUM_INPUT_ONLY_CONNS 1
-
-/** @brief Define the number of supported input only connections per connection path
- */
-#define OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH 3
-
-/** @brief Define the number of supported listen only connections.
- *  Each of these connections has to be configured with the function
- *  void configureListenOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
- *
- */
-#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS 1
-
-/** @brief Define the number of supported Listen only connections per connection path
- */
-#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH   3
-
-/** @brief The number of bytes used for the buffer that will be used for generating any
- *  reply data of messages. There are two uses in OpENer:
- *    1. Explicit messages will use this buffer to store the data generated by the request
- *    2. I/O Connections will use this buffer for the produced data
- */
-#define OPENER_MESSAGE_DATA_REPLY_BUFFER 100
-
-/** @brief Number of sessions that can be handled at the same time
- */
-#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 20
-
-/** @brief  The time in ms of the timer used in this implementations
- */
-static const int kOpenerTimerTickInMilliSeconds = 10;
-
-#ifdef OPENER_WITH_TRACES
-/* If we have tracing enabled provide print tracing macro */
-#include <stdio.h>
-
-#define LOG_TRACE(...)  fprintf(stderr,__VA_ARGS__)
-
-/*#define PRINT_TRACE(args...)  fprintf(stderr,args);*/
-
-/** @brief A specialized assertion command that will log the assertion and block
- *  further execution in an while(1) loop.
- */
-#ifdef IDLING_ASSERT
-#define OPENER_ASSERT(assertion) \
-  do { \
-    if( !(assertion) ) { \
-      LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", \
-                # assertion, \
-                __FILE__, \
-                __LINE__); \
-      while(1) {;} \
-    } \
-  } while(0);
-#else
-#define OPENER_ASSERT(assertion) assert(assertion);
-#endif
-/* else use standard assert() */
-//#include <assert.h>
-//#include <stdio.h>
-//#define OPENER_ASSERT(assertion) assert(assertion)
-#else
-
-/* for release builds execute the assertion, but don't test it */
-#define OPENER_ASSERT(assertion) (assertion);
-
-/* the above may result in "statement with no effect" warnings.
- *  If you do not use assert()s to run functions, the an empty
- *  macro can be used as below
- */
-//#define OPENER_ASSERT(assertion)
-/* else if you still want assertions to stop execution but without tracing, use the following */
-//#define OPENER_ASSERT(assertion) do { if(!(assertion)) { while(1){;} } } while (0)
-/* else use standard assert() */
-//#include <assert.h>
-//#include <stdio.h>
-//#define OPENER_ASSERT(assertion) assert(assertion)
-
-#endif
-
-/** @brief The number of bytes used for the Ethernet message buffer on
- * the pc port. For different platforms it may makes sense to
- * have more than one buffer.
- *
- *  This buffer size will be used for any received message.
- *  The same buffer is used for the replied explicit message.
- */
-#define PC_OPENER_ETHERNET_BUFFER_SIZE 512
-
-#endif /*OPENER_USER_CONF_H_*/
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#ifndef OPENER_USER_CONF_H_
+#define OPENER_USER_CONF_H_
+
+/** @file WIN32/sample_application/opener_user_conf.h
+ * @brief OpENer configuration setup
+ *
+ * This file contains the general application specific configuration for OpENer.
+ *
+ * Furthermore you have to specific platform specific network include files.
+ * OpENer needs definitions for the following data-types
+ * and functions:
+ *    - struct sockaddr_in
+ *    - AF_INET
+ *    - INADDR_ANY
+ *    - htons
+ *    - ntohl
+ *    - inet_addr
+ */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+typedef unsigned short in_port_t;
+
+/** @brief Identity configuration of the device */
+#include "devicedata.h"
+
+#include "typedefs.h"
+
+/** @brief Define the number of objects that may be used in connections
+ *
+ *  This number needs only to consider additional objects. Connections to
+ *  the connection manager object as well as to the assembly object are supported
+ *  in any case.
+ */
+#define OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS 1
+
+/** @brief Define the number of supported explicit connections.
+ *  According to ODVA's PUB 70 this number should be greater than 6.
+ */
+#define OPENER_CIP_NUM_EXPLICIT_CONNS 6
+
+/** @brief Define the number of supported exclusive owner connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureExclusiveOwnerConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS 1
+
+/** @brief Define the number of supported input only connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureInputOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS 1
+
+/** @brief Define the number of supported input only connections per connection path
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH 3
+
+/** @brief Define the number of supported listen only connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureListenOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS 1
+
+/** @brief Define the number of supported Listen only connections per connection path
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH   3
+
+/** @brief The number of bytes used for the buffer that will be used for generating any
+ *  reply data of messages. There are two uses in OpENer:
+ *    1. Explicit messages will use this buffer to store the data generated by the request
+ *    2. I/O Connections will use this buffer for the produced data
+ */
+#define OPENER_MESSAGE_DATA_REPLY_BUFFER 100
+
+/** @brief Number of sessions that can be handled at the same time
+ */
+#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 20
+
+/** @brief  The time in ms of the timer used in this implementations
+ */
+static const int kOpenerTimerTickInMilliSeconds = 10;
+
+#ifdef OPENER_WITH_TRACES
+/* If we have tracing enabled provide print tracing macro */
+#include <stdio.h>
+
+#define LOG_TRACE(...)  fprintf(stderr,__VA_ARGS__)
+
+/*#define PRINT_TRACE(args...)  fprintf(stderr,args);*/
+
+/** @brief A specialized assertion command that will log the assertion and block
+ *  further execution in an while(1) loop.
+ */
+#ifdef IDLING_ASSERT
+#define OPENER_ASSERT(assertion) \
+  do { \
+    if( !(assertion) ) { \
+      LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", \
+                # assertion, \
+                __FILE__, \
+                __LINE__); \
+      while(1) {;} \
+    } \
+  } while(0);
+#else
+#define OPENER_ASSERT(assertion) assert(assertion);
+#endif
+/* else use standard assert() */
+//#include <assert.h>
+//#include <stdio.h>
+//#define OPENER_ASSERT(assertion) assert(assertion)
+#else
+
+/* for release builds execute the assertion, but don't test it */
+#define OPENER_ASSERT(assertion) (assertion);
+
+/* the above may result in "statement with no effect" warnings.
+ *  If you do not use assert()s to run functions, the an empty
+ *  macro can be used as below
+ */
+//#define OPENER_ASSERT(assertion)
+/* else if you still want assertions to stop execution but without tracing, use the following */
+//#define OPENER_ASSERT(assertion) do { if(!(assertion)) { while(1){;} } } while (0)
+/* else use standard assert() */
+//#include <assert.h>
+//#include <stdio.h>
+//#define OPENER_ASSERT(assertion) assert(assertion)
+
+#endif
+
+/** @brief The number of bytes used for the Ethernet message buffer on
+ * the pc port. For different platforms it may makes sense to
+ * have more than one buffer.
+ *
+ *  This buffer size will be used for any received message.
+ *  The same buffer is used for the replied explicit message.
+ */
+#define PC_OPENER_ETHERNET_BUFFER_SIZE 512
+
+#endif /*OPENER_USER_CONF_H_*/

Деякі файли не було показано, через те що забагато файлів було змінено