peda1337 8 лет назад
Родитель
Сommit
1745bf8051
71 измененных файлов с 3563 добавлено и 1424 удалено
  1. 1 1
      .travis.yml
  2. 12 2
      README.md
  3. 2 2
      source/contrib/msinttypes/inttypes.h
  4. 1 1
      source/src/cip/CMakeLists.txt
  5. 178 136
      source/src/cip/appcontype.c
  6. 9 6
      source/src/cip/appcontype.h
  7. 44 24
      source/src/cip/cipclass3connection.c
  8. 27 1
      source/src/cip/cipclass3connection.h
  9. 22 23
      source/src/cip/cipcommon.c
  10. 185 424
      source/src/cip/cipconnectionmanager.c
  11. 8 254
      source/src/cip/cipconnectionmanager.h
  12. 800 0
      source/src/cip/cipconnectionobject.c
  13. 420 0
      source/src/cip/cipconnectionobject.h
  14. 33 14
      source/src/cip/cipelectronickey.c
  15. 38 11
      source/src/cip/cipelectronickey.h
  16. 200 18
      source/src/cip/cipepath.c
  17. 41 6
      source/src/cip/cipepath.h
  18. 4 20
      source/src/cip/cipethernetlink.c
  19. 11 0
      source/src/cip/cipethernetlink.h
  20. 5 5
      source/src/cip/cipidentity.c
  21. 170 206
      source/src/cip/cipioconnection.c
  22. 4 3
      source/src/cip/cipioconnection.h
  23. 23 21
      source/src/cip/cipmessagerouter.c
  24. 8 9
      source/src/cip/cipqos.c
  25. 1 1
      source/src/cip/cipqos.h
  26. 8 67
      source/src/cip/ciptcpipinterface.c
  27. 2 0
      source/src/cip/ciptcpipinterface.h
  28. 2 30
      source/src/cip/ciptypes.h
  29. 2 3
      source/src/enet_encap/cpf.c
  30. 11 8
      source/src/enet_encap/encap.c
  31. 3 3
      source/src/enet_encap/endianconv.c
  32. 1 1
      source/src/enet_encap/endianconv.h
  33. 14 16
      source/src/opener_api.h
  34. 2 2
      source/src/ports/POSIX/CMakeLists.txt
  35. 13 16
      source/src/ports/POSIX/main.c
  36. 184 0
      source/src/ports/POSIX/networkconfig.c
  37. 14 0
      source/src/ports/POSIX/networkconfig.h
  38. 12 2
      source/src/ports/POSIX/networkhandler.c
  39. 2 1
      source/src/ports/POSIX/networkhandler.h
  40. 2 3
      source/src/ports/POSIX/sample_application/opener_user_conf.h
  41. 5 2
      source/src/ports/POSIX/sample_application/sampleapplication.c
  42. 1 1
      source/src/ports/WIN32/CMakeLists.txt
  43. 1 0
      source/src/ports/WIN32/main.c
  44. 73 0
      source/src/ports/WIN32/networkconfig.c
  45. 15 0
      source/src/ports/WIN32/networkconfig.h
  46. 1 1
      source/src/ports/WIN32/networkhandler.c
  47. 2 1
      source/src/ports/WIN32/networkhandler.h
  48. 5 2
      source/src/ports/WIN32/sample_application/sampleapplication.c
  49. 29 16
      source/src/ports/generic_networkhandler.c
  50. 0 3
      source/src/ports/generic_networkhandler.h
  51. 2 1
      source/src/ports/opener_error.h
  52. 4 2
      source/src/ports/socket_timer.c
  53. 4 2
      source/src/ports/socket_timer.h
  54. 1 1
      source/src/utils/CMakeLists.txt
  55. 139 0
      source/src/utils/doublylinkedlist.c
  56. 67 0
      source/src/utils/doublylinkedlist.h
  57. 4 5
      source/src/utils/random.c
  58. 4 5
      source/src/utils/random.h
  59. 4 5
      source/src/utils/xorshiftrandom.c
  60. 4 5
      source/src/utils/xorshiftrandom.h
  61. 2 1
      source/tests/OpENerTests.cpp
  62. 2 0
      source/tests/OpENerTests.h
  63. 1 1
      source/tests/cip/CMakeLists.txt
  64. 0 8
      source/tests/cip/cipconnectionmanagertest.cpp
  65. 359 0
      source/tests/cip/cipconnectionobjecttest.cpp
  66. 27 14
      source/tests/cip/cipelectronickeytest.cpp
  67. 6 4
      source/tests/cip/cipepathtest.cpp
  68. 2 2
      source/tests/enet_encap/endianconvtest.cpp
  69. 1 1
      source/tests/utils/CMakeLists.txt
  70. 278 0
      source/tests/utils/doublylinkedlistTests.cpp
  71. 1 1
      uncrustify.cfg

+ 1 - 1
.travis.yml

@@ -1,7 +1,7 @@
 # This will run on Travis' 'new' container-based infrastructure
 sudo: false
 os: linux
-dist: precise
+dist: trusty
 
 language: c
 

+ 12 - 2
README.md

@@ -1,4 +1,9 @@
 [![Build Status](https://travis-ci.org/EIPStackGroup/OpENer.svg?branch=master)](https://travis-ci.org/EIPStackGroup/OpENer)
+    <p><a href="https://scan.coverity.com/projects/opener">
+  <img alt="Coverity Scan Build Status"
+       src="https://scan.coverity.com/projects/14200/badge.svg?flat=1"/>
+</a>
+ </p>
 
 [![Stories in Ready](https://badge.waffle.io/EIPStackGroup/OpENer.svg?label=ready&title=Ready)](http://waffle.io/EIPStackGroup/OpENer)
 [![Stories in In Progress](https://badge.waffle.io/EIPStackGroup/OpENer.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/EIPStackGroup/OpENer)
@@ -55,9 +60,9 @@ Compile for POSIX:
 	3. Invoke make
 	4. For invoking opener type:
 
-		./OpENer ipaddress subnetmask gateway domainname hostaddress macaddress
+		./OpENer interface
 
-		e.g. ./OpENer 192.168.0.2 255.255.255.0 192.168.0.1 test.com testdevice 00 15 C5 BF D0 87
+		e.g. ./OpENer eth1
  
 2. Within Eclipse
 	1. For a standard configuration invoke setup_posix.sh, otherwise start
@@ -72,7 +77,12 @@ Compile for Windows XP/7/8:
 ---------------------------
 1. Invoke setup_windows.bat or configure via CMake
 2. Open Visual Studio solution in bin/win32
+3. For invoking opener type in command line:
 
+		OpENer ipaddress subnetmask gateway domainname hostaddress macaddress
+
+		e.g. OpENer 192.168.0.2 255.255.255.0 192.168.0.1 test.com testdevice 00 15 C5 BF D0 87
+ 
 Directory structure:
 --------------------
 - bin ...  The resulting binaries and make files for different ports

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

@@ -277,8 +277,8 @@ static
 #else // STATIC_IMAXDIV ][
 __inline
 #endif // STATIC_IMAXDIV ]
-imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
-{
+imaxdiv_t __cdecl imaxdiv(intmax_t numer,
+                          intmax_t denom) {
   imaxdiv_t result;
 
   result.quot = numer / denom;

+ 1 - 1
source/src/cip/CMakeLists.txt

@@ -12,6 +12,6 @@ opener_common_includes()
 #######################################
 opener_platform_support("INCLUDES")
 
-set( CIP_SRC appcontype.c cipassembly.c cipclass3connection.c cipcommon.c cipconnectionmanager.c ciperror.h cipethernetlink.c cipidentity.c cipioconnection.c cipmessagerouter.c ciptcpipinterface.c ciptypes.h cipepath.h cipepath.c cipelectronickey.h cipelectronickey.c cipqos.c )
+set( CIP_SRC appcontype.c cipassembly.c cipclass3connection.c cipcommon.c cipconnectionobject.c cipconnectionmanager.c ciperror.h cipethernetlink.c cipidentity.c cipioconnection.c cipmessagerouter.c ciptcpipinterface.c ciptypes.h cipepath.h cipepath.c cipelectronickey.h cipelectronickey.c cipqos.c )
 
 add_library( CIP ${CIP_SRC} )

+ 178 - 136
source/src/cip/appcontype.c

@@ -9,20 +9,18 @@
 #include "appcontype.h"
 
 #include "cipconnectionmanager.h"
+#include "cipconnectionobject.h"
 #include "opener_api.h"
 #include "assert.h"
 #include "trace.h"
-
-
-/** @brief External globals needed from connectionmanager.c */
-extern ConnectionObject *g_active_connection_list;
+#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 */
-  ConnectionObject connection_data; /**< the connection data, only one connection is allowed per O-to-T point*/
+  CipConnectionObject connection_data; /**< the connection data, only one connection is allowed per O-to-T point*/
 } ExclusiveOwnerConnection;
 
 /** @brief Input Only connection data */
@@ -30,7 +28,8 @@ 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 */
-  ConnectionObject connection_data[OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH]; /*< the connection data */
+  CipConnectionObject connection_data[
+    OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH];                                   /*< the connection data */
 } InputOnlyConnection;
 
 /** @brief Listen Only connection data */
@@ -38,7 +37,8 @@ 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 */
-  ConnectionObject connection_data[OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH
+  CipConnectionObject connection_data[
+    OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH
   ];                                                                               /**< the connection data */
 } ListenOnlyConnection;
 
@@ -56,8 +56,8 @@ ListenOnlyConnection g_listen_only_connections[OPENER_CIP_NUM_LISTEN_ONLY_CONNS]
  * @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
  */
-ConnectionObject *GetExclusiveOwnerConnection(
-  const ConnectionObject *RESTRICT connection_object,
+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,
@@ -67,8 +67,8 @@ ConnectionObject *GetExclusiveOwnerConnection(
  * @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
  */
-ConnectionObject *GetInputOnlyConnection(
-  const ConnectionObject *const RESTRICT connection_object,
+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,
@@ -78,8 +78,8 @@ ConnectionObject *GetInputOnlyConnection(
  * @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
  */
-ConnectionObject *GetListenOnlyConnection(
-  const ConnectionObject *const RESTRICT connection_object,
+CipConnectionObject *GetListenOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
   EipUint16 *const extended_error);
 
 void ConfigureExclusiveOwnerConnectionPoint(
@@ -124,102 +124,135 @@ void ConfigureListenOnlyConnectionPoint(const unsigned int connection_number,
   }
 }
 
-ConnectionObject *GetIoConnectionForConnectionData(
-  ConnectionObject *const RESTRICT connection_object,
+CipConnectionObject *GetIoConnectionForConnectionData(
+  CipConnectionObject *const RESTRICT connection_object,
   EipUint16 *const extended_error) {
 
   *extended_error = 0;
 
-  ConnectionObject *io_connection = GetExclusiveOwnerConnection(
+  CipConnectionObject *io_connection = GetExclusiveOwnerConnection(
     connection_object,
     extended_error);
   if (NULL == io_connection) {
-    if (0 == *extended_error) {
+    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 (0 == *extended_error) {
+        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) && (0 == *extended_error) ) {
             /* no application connection type was found that suits the given data */
-            /* TODO check error code VS */
             *extended_error =
               kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
           } else {
-            connection_object->instance_type = kConnectionTypeIoListenOnly;
+            ConnectionObjectSetInstanceType(connection_object,
+                                            kConnectionObjectInstanceTypeIOListenOnly);
+            OPENER_TRACE_INFO("IO Listen only connection requested\n");
+            //Is listen only connection
           }
         }
       } else {
-        connection_object->instance_type = kConnectionTypeIoInputOnly;
+        ConnectionObjectSetInstanceType(connection_object,
+                                        kConnectionObjectInstanceTypeIOInputOnly);
+        OPENER_TRACE_INFO("IO Input only connection requested\n");
+        //is Input only connection
       }
     }
   } else {
-    connection_object->instance_type = kConnectionTypeIoExclusiveOwner;
+    ConnectionObjectSetInstanceType(connection_object,
+                                    kConnectionObjectInstanceTypeIOExclusiveOwner);
+    OPENER_TRACE_INFO("IO Exclusive Owner connection requested\n");
+    //Is exclusive owner connection
   }
 
   if (NULL != io_connection) {
-    CopyConnectionData(io_connection, connection_object);
+    ConnectionObjectDeepCopy(io_connection, connection_object);
   }
 
   return io_connection;
 }
 
-ConnectionObject *GetExclusiveOwnerConnection(
-  const ConnectionObject *const RESTRICT connection_object,
+CipConnectionObject *GetExclusiveOwnerConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
   EipUint16 *const extended_error) {
-  ConnectionObject *exclusive_owner_connection = NULL;
 
-  for (int i = 0; i < OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS; i++) {
-    if ( (g_exlusive_owner_connections[i].output_assembly
-          == connection_object->connection_path.connection_point[0])
-         && (g_exlusive_owner_connections[i].input_assembly
-             == connection_object->connection_path.connection_point[1])
-         && (g_exlusive_owner_connections[i].config_assembly
-             == connection_object->connection_path.connection_point[2]) ) {
+  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
-           != GetConnectedOutputAssembly(
-             connection_object->connection_path.connection_point[0]) ) {
-        *extended_error =
-          kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
-        OPENER_TRACE_INFO("Hit an Ownership conflict in appcontype.c");
-        break;
+           != exclusive_owner ) {
+        if(kConnectionObjectStateEstablished ==
+           ConnectionObjectGetState(exclusive_owner) ) {
+          *extended_error =
+            kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
+          OPENER_TRACE_INFO("Hit an Ownership conflict in appcontype.c");
+          break;
+        }
+        if(kConnectionObjectStateTimedOut ==
+           ConnectionObjectGetState(exclusive_owner)
+           && EqualConnectionTriad(connection_object, exclusive_owner) ) {
+          exclusive_owner->connection_close_function(exclusive_owner);
+          return &(g_exlusive_owner_connections[i].connection_data);
+        }
       }
-      exclusive_owner_connection = &(g_exlusive_owner_connections[i]
-                                     .connection_data);
+      return &(g_exlusive_owner_connections[i].connection_data);
       break;
     }
   }
-  return exclusive_owner_connection;
+  return NULL;
 }
 
-ConnectionObject *GetInputOnlyConnection(
-  const ConnectionObject *const RESTRICT connection_object,
+CipConnectionObject *GetInputOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
   EipUint16 *const extended_error) {
-  ConnectionObject *input_only_connection = NULL; //TODO: This variable has no use
 
-  for (int i = 0; i < OPENER_CIP_NUM_INPUT_ONLY_CONNS; i++) {
+  for (size_t i = 0; i < OPENER_CIP_NUM_INPUT_ONLY_CONNS; ++i) {
     if (g_input_only_connections[i].output_assembly
-        == connection_object->connection_path.connection_point[0]) { /* we have the same output assembly */
+        == connection_object->consumed_path.instance_id) { /* we have the same output assembly */
       if (g_input_only_connections[i].input_assembly
-          != connection_object->connection_path.connection_point[1]) {
+          != connection_object->produced_path.instance_id) {
         *extended_error =
           kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
         break;
       }
       if (g_input_only_connections[i].config_assembly
-          != connection_object->connection_path.connection_point[2]) {
+          != connection_object->configuration_path.instance_id) {
         *extended_error =
           kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
         break;
       }
 
-      for (int j = 0; j < OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH; j++) {
-        if (kConnectionStateNonExistent
-            == g_input_only_connections[i].connection_data[j].state) {
+      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]) )
+            && EqualConnectionTriad(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]);
         }
       }
@@ -228,34 +261,32 @@ ConnectionObject *GetInputOnlyConnection(
       break;
     }
   }
-  return input_only_connection;
+  return NULL;
 }
 
-ConnectionObject *GetListenOnlyConnection(
-  const ConnectionObject *const RESTRICT connection_object,
+CipConnectionObject *GetListenOnlyConnection(
+  const CipConnectionObject *const RESTRICT connection_object,
   EipUint16 *const extended_error) {
-  ConnectionObject *listen_only_connection = NULL; //TODO: This variable has no use
 
-  if ( kForwardOpenConnectionTypeMulticastConnection
-       != (connection_object->t_to_o_network_connection_parameter
-           & kForwardOpenConnectionTypeMulticastConnection) ) {
+  if ( kConnectionObjectConnectionTypeMulticast
+       != ConnectionObjectGetTToOConnectionType(connection_object) ) {
     /* a listen only connection has to be a multicast connection. */
     *extended_error =
       kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened;   /* maybe not the best error message however there is no suitable definition in the cip spec */
     return NULL;
   }
 
-  for (int i = 0; i < OPENER_CIP_NUM_LISTEN_ONLY_CONNS; i++) {
+  for (size_t i = 0; i < OPENER_CIP_NUM_LISTEN_ONLY_CONNS; i++) {
     if (g_listen_only_connections[i].output_assembly
-        == connection_object->connection_path.connection_point[0]) { /* we have the same output assembly */
+        == connection_object->consumed_path.instance_id) { /* we have the same output assembly */
       if (g_listen_only_connections[i].input_assembly
-          != connection_object->connection_path.connection_point[1]) {
+          != connection_object->produced_path.instance_id) {
         *extended_error =
           kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
         break;
       }
       if (g_listen_only_connections[i].config_assembly
-          != connection_object->connection_path.connection_point[2]) {
+          != connection_object->configuration_path.instance_id) {
         *extended_error =
           kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
         break;
@@ -263,15 +294,33 @@ ConnectionObject *GetListenOnlyConnection(
 
       if ( NULL
            == GetExistingProducerMulticastConnection(
-             connection_object->connection_path.connection_point[1]) ) {
+             connection_object->produced_path.instance_id) ) {
         *extended_error =
           kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened;
         break;
       }
 
-      for (int j = 0; j < OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH; j++) {
-        if (kConnectionStateNonExistent
-            == g_listen_only_connections[i].connection_data[j].state) {
+      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]) )
+            && EqualConnectionTriad(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]);
         }
       }
@@ -280,118 +329,111 @@ ConnectionObject *GetListenOnlyConnection(
       break;
     }
   }
-  return listen_only_connection;
+  return NULL;
 }
 
-ConnectionObject *GetExistingProducerMulticastConnection(
+CipConnectionObject *GetExistingProducerMulticastConnection(
   const EipUint32 input_point) {
-  ConnectionObject *producer_multicast_connection = g_active_connection_list;
+  DoublyLinkedListNode *node = connection_list.first;
 
-  while (NULL != producer_multicast_connection) {
-    if ( (kConnectionTypeIoExclusiveOwner
-          == producer_multicast_connection->instance_type)
-         || (kConnectionTypeIoInputOnly
-             == producer_multicast_connection->instance_type) ) {
+  while (NULL != node) {
+    CipConnectionObject *producer_multicast_connection = node->data;
+    if ( true ==
+         ConnectionObjectIsTypeIOConnection(producer_multicast_connection) ) {
       if ( (input_point
-            == producer_multicast_connection->connection_path.connection_point[
-              1])
-           && ( kForwardOpenConnectionTypeMulticastConnection
-                == (producer_multicast_connection
-                    ->t_to_o_network_connection_parameter
-                    & kForwardOpenConnectionTypeMulticastConnection) )
+            == 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.
          */
-        break;
+        return producer_multicast_connection;
       }
     }
-    producer_multicast_connection = producer_multicast_connection
-                                    ->next_connection_object;
+    node = node->next;
   }
-  return producer_multicast_connection;
+  return NULL;
 }
 
-ConnectionObject *GetNextNonControlMasterConnection(const EipUint32 input_point)
-{
-  ConnectionObject *next_non_control_master_connection =
-    g_active_connection_list;
-
-  while (NULL != next_non_control_master_connection) {
-    if ( (kConnectionTypeIoExclusiveOwner
-          == next_non_control_master_connection->instance_type)
-         || (kConnectionTypeIoInputOnly
-             == next_non_control_master_connection->instance_type) ) {
-      if ( (input_point
-            == next_non_control_master_connection->connection_path
-            .connection_point[1])
-           && ( kForwardOpenConnectionTypeMulticastConnection
-                == (next_non_control_master_connection
-                    ->t_to_o_network_connection_parameter
-                    & kForwardOpenConnectionTypeMulticastConnection) )
-           && (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 manages the connection.
-         */
-        break;
-      }
+CipConnectionObject *GetNextNonControlMasterConnection(
+  const EipUint32 input_point) {
+  DoublyLinkedListNode *node = connection_list.first;
+
+  while (NULL != node) {
+    CipConnectionObject *next_non_control_master_connection =
+      node->data;
+    if ( true ==
+         ConnectionObjectIsTypeIOConnection(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;
     }
-    next_non_control_master_connection = next_non_control_master_connection
-                                         ->next_connection_object;
+    node = node->next;
   }
-  return next_non_control_master_connection;
+  return NULL;
 }
 
 void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
-                                             const ConnectionType instance_type)
+                                             const ConnectionObjectConnectionType instance_type)
 {
-  ConnectionObject *connection = g_active_connection_list;
 
-  while (NULL != connection) {
+  DoublyLinkedListNode *node = connection_list.first;
+
+  while (NULL != node) {
+    CipConnectionObject *connection = node->data;
     if ( (instance_type == connection->instance_type)
-         && (input_point == connection->connection_path.connection_point[1]) ) {
-      ConnectionObject *connection_to_delete = connection;
-      connection = connection->next_connection_object;
+         && (input_point == connection->produced_path.instance_id) ) {
+      CipConnectionObject *connection_to_delete = connection;
       CheckIoConnectionEvent(
-        connection_to_delete->connection_path.connection_point[0],
-        connection_to_delete->connection_path.connection_point[1],
+        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);
+      node = connection_list.first;
     } else {
-      connection = connection->next_connection_object;
+      node = node->next;
     }
   }
 }
 
 void CloseAllConnections(void) {
-  ConnectionObject *connection = g_active_connection_list;
-  while (NULL != connection) {
+  DoublyLinkedListNode *node = connection_list.first;
+  while (NULL != node) {
+    CipConnectionObject *connection = node->data;
     assert(connection->connection_close_function != NULL);
     connection->connection_close_function(connection);
-    CloseConnection(connection);
-    /* Close connection will remove the connection from the list therefore we
-     * need to get again the start until there is no connection left
-     */
-    connection = g_active_connection_list;
+    node = connection_list.first;
   }
 }
 
-EipBool8 ConnectionWithSameConfigPointExists(const EipUint32 config_point) {
-  ConnectionObject *connection = g_active_connection_list;
+bool ConnectionWithSameConfigPointExists(const EipUint32 config_point) {
+  DoublyLinkedListNode *node = connection_list.first;
 
-  while (NULL != connection) {
-    if (config_point == connection->connection_path.connection_point[2]) {
-      break;
+  while (NULL != node) {
+    CipConnectionObject *connection = node->data;
+    if (config_point == connection->configuration_path.instance_id) {
+      return (NULL != connection);
     }
-    connection = connection->next_connection_object;
+    node = node->next;
   }
-  return (NULL != connection);
+  return false;
 }
 
 void InitializeIoConnectionData(void) {

+ 9 - 6
source/src/cip/appcontype.h

@@ -8,6 +8,8 @@
 
 #include "cipconnectionmanager.h"
 
+extern DoublyLinkedList connection_list;
+
 void InitializeIoConnectionData(void);
 
 /** @brief check if for the given connection data received in a forward_open request
@@ -23,8 +25,8 @@ void InitializeIoConnectionData(void);
  *          data given in connection_object.
  *        - on error: NULL
  */
-ConnectionObject *GetIoConnectionForConnectionData(
-  ConnectionObject *const RESTRICT connection_object,
+CipConnectionObject *GetIoConnectionForConnectionData(
+  CipConnectionObject *const RESTRICT connection_object,
   EipUint16 *const extended_error);
 
 /** @brief Check if there exists already an exclusive owner or listen only connection
@@ -33,7 +35,7 @@ ConnectionObject *GetIoConnectionForConnectionData(
  *  @param input_point the Input point to be produced
  *  @return if a connection could be found a pointer to this connection if not NULL
  */
-ConnectionObject *GetExistingProducerMulticastConnection(
+CipConnectionObject *GetExistingProducerMulticastConnection(
   const EipUint32 input_point);
 
 /** @brief check if there exists an producing multicast exclusive owner or
@@ -44,7 +46,8 @@ ConnectionObject *GetExistingProducerMulticastConnection(
  * @return if a connection could be found the pointer to this connection
  *      otherwise NULL.
  */
-ConnectionObject *GetNextNonControlMasterConnection(const EipUint32 input_point);
+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).
@@ -53,7 +56,7 @@ ConnectionObject *GetNextNonControlMasterConnection(const EipUint32 input_point)
  * @param instance_type the connection application type
  */
 void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
-                                             const ConnectionType instance_type);
+                                             const ConnectionObjectConnectionType instance_type);
 
 /**@ brief close all open connections.
  *
@@ -68,6 +71,6 @@ void CloseAllConnections(void);
  * @param config_point The configuration point
  * @return true if connection was found, otherwise false
  */
-EipBool8 ConnectionWithSameConfigPointExists(const EipUint32 config_point);
+bool ConnectionWithSameConfigPointExists(const EipUint32 config_point);
 
 #endif /* OPENER_APPCONTYPE_H_ */

+ 44 - 24
source/src/cip/cipclass3connection.c

@@ -8,45 +8,41 @@
 
 #include "cipclass3connection.h"
 
-ConnectionObject *GetFreeExplicitConnection(void);
-
 /**** Global variables ****/
+extern CipConnectionObject explicit_connection_object_pool[
+  OPENER_CIP_NUM_EXPLICIT_CONNS];
 
-/** @brief Array of the available explicit connections */
-ConnectionObject g_explicit_connections[OPENER_CIP_NUM_EXPLICIT_CONNS];
+CipConnectionObject *GetFreeExplicitConnection(void);
 
 /**** Implementation ****/
 EipStatus EstablishClass3Connection(
-  ConnectionObject *RESTRICT const connection_object,
+  CipConnectionObject *RESTRICT const connection_object,
   EipUint16 *const extended_error) {
   EipStatus eip_status = kEipStatusOk;
 
   /*TODO add check for transport type trigger */
   /* if (0x03 == (g_stDummyConnectionObject.TransportTypeClassTrigger & 0x03)) */
 
-  ConnectionObject *explicit_connection = GetFreeExplicitConnection();
+  CipConnectionObject *explicit_connection = GetFreeExplicitConnection();
 
   if (NULL == explicit_connection) {
     eip_status = kCipErrorConnectionFailure;
     *extended_error =
       kConnectionManagerExtendedStatusCodeErrorNoMoreConnectionsAvailable;
   } else {
-    CopyConnectionData(explicit_connection, connection_object);
-
-    EipUint32 produced_connection_id_buffer =
-      explicit_connection->cip_produced_connection_id;
-    GeneralConnectionConfiguration(explicit_connection);
-    explicit_connection->cip_produced_connection_id =
-      produced_connection_id_buffer;
-    explicit_connection->instance_type = kConnectionTypeExplicit;
-    explicit_connection->socket[0] = explicit_connection->socket[1] =
-                                       kEipInvalidSocket;
+    ConnectionObjectDeepCopy(explicit_connection, connection_object);
+
+    ConnectionObjectGeneralConfiguration(explicit_connection);
+
+    ConnectionObjectSetInstanceType(explicit_connection,
+                                    kConnectionObjectInstanceTypeExplicitMessaging);
+
     /* set the connection call backs */
     explicit_connection->connection_close_function =
-      RemoveFromActiveConnections;
+      CloseConnection;
     /* explicit connection have to be closed on time out*/
     explicit_connection->connection_timeout_function =
-      RemoveFromActiveConnections;
+      CloseConnection;
 
     AddNewActiveConnection(explicit_connection);
   }
@@ -57,16 +53,40 @@ EipStatus EstablishClass3Connection(
  *
  * @return Free explicit connection slot, or NULL if no slot is free
  */
-ConnectionObject *GetFreeExplicitConnection(void) {
-  for (int i = 0; i < OPENER_CIP_NUM_EXPLICIT_CONNS; i++) {
-    if (g_explicit_connections[i].state == kConnectionStateNonExistent) {
-      return &(g_explicit_connections[i]);
+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( g_explicit_connections, 0,
-          OPENER_CIP_NUM_EXPLICIT_CONNS * sizeof(ConnectionObject) );
+  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;
+  }
 }

+ 27 - 1
source/src/cip/cipclass3connection.h

@@ -9,10 +9,36 @@
 
 /** @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.
  *
@@ -24,7 +50,7 @@
  *    - On an error the general status code to be put into the response
  */
 EipStatus EstablishClass3Connection(
-  ConnectionObject *RESTRICT const connection_object,
+  CipConnectionObject *RESTRICT const connection_object,
   EipUint16 *const extended_error);
 
 /** @brief Initializes the explicit connections mechanism

+ 22 - 23
source/src/cip/cipcommon.c

@@ -273,10 +273,10 @@ CipClass *CreateCipClass( const EipUint32 class_id,
                      kNotSetOrGetable ); /* optional service list - default = 0 */
     InsertAttribute( (CipInstance *) class, 6, kCipUint,
                      (void *) &meta_class->highest_attribute_number,
-                     kGetableSingle );                     /* max class attribute number*/
+                     kGetableSingle ); /* max class attribute number*/
     InsertAttribute( (CipInstance *) class, 7, kCipUint,
                      (void *) &class->highest_attribute_number,
-                     kGetableSingle );                     /* max instance attribute number*/
+                     kGetableSingle );                                          /* max instance attribute number*/
   } else {
     InitializeCipClass(class);
   }
@@ -327,8 +327,7 @@ void InsertAttribute(CipInstance *const instance,
     attribute++;
   }
   OPENER_TRACE_ERR(
-    "Tried to insert to many attributes into class: %" PRIu32 ", instance %"
-    PRIu32 "\n",
+    "Tried to insert to many attributes into class: %" PRIu32 ", instance %" PRIu32 "\n",
     instance->cip_class->class_instance.instance_number,
     instance->instance_number);
   OPENER_ASSERT(0);
@@ -400,20 +399,18 @@ EipStatus GetAttributeSingle(
   EipUint16 attribute_number = message_router_request->request_path
                                .attribute_number;
 
-
   if ( (NULL != attribute) && (NULL != attribute->data) ) {
     uint8_t get_bit_mask = 0;
     if (kGetAttributeAll == message_router_request->service) {
       get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                              attribute_number)
-                      ]);
+                                                              attribute_number)]);
       message_router_response->general_status = kCipErrorSuccess;
     } else {
       get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
                                                                  attribute_number)
                       ]);
     }
-    if ( 0 != ( get_bit_mask & ( 1 << ( attribute_number % 8 ) ) ) ) {
+    if ( 0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
       OPENER_TRACE_INFO("getAttribute %d\n",
                         message_router_request->request_path.attribute_number); /* create a reply message containing the data*/
 
@@ -711,7 +708,7 @@ EipStatus GetAttributeAll(CipInstance *instance,
           if ( attrNum < 32
                && ( (instance->cip_class->get_all_bit_mask[CalculateIndex(
                                                              attrNum)])
-                    & ( 1 << ( attrNum % 8 ) ) ) ) /* only return attributes that are flagged as being part of GetAttributeALl */
+                    & ( 1 << (attrNum % 8) ) ) ) /* only return attributes that are flagged as being part of GetAttributeALl */
           {
             message_router_request->request_path.attribute_number = attrNum;
             if ( kEipStatusOkSend
@@ -869,8 +866,7 @@ int DecodePaddedEPath(CipEpath *epath,
 void AllocateAttributeMasks(CipClass *target_class) {
   size_t size = 1 + CalculateIndex(target_class->highest_attribute_number);
   OPENER_TRACE_INFO(">>> Allocate memory for %s %lu bytes times 3 for masks\n",
-                    target_class->class_name,
-                    size);
+                    target_class->class_name, size);
   target_class->get_single_bit_mask = CipCalloc( size, sizeof(uint8_t) );
   target_class->set_bit_mask = CipCalloc( size, sizeof(uint8_t) );
   target_class->get_all_bit_mask = CipCalloc( size, sizeof(uint8_t) );
@@ -896,9 +892,6 @@ size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
     case (kCipDint):
       return sizeof(CipDint);
       break;
-    case (kCipLint):
-      return sizeof(CipLint);
-      break;
     case (kCipUsint):
       return sizeof(CipUsint);
       break;
@@ -908,15 +901,27 @@ size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
     case (kCipUdint):
       return sizeof(CipUdint);
       break;
-    case (kCipUlint):
-      return sizeof(CipUlint);
-      break;
     case (kCipReal):
       return sizeof(CipReal);
       break;
     case (kCipLreal):
       return sizeof(CipLreal);
       break;
+#ifdef OPENER_SUPPORT_64BIT_DATATYPES
+    case (kCipUlint):
+      return sizeof(CipUlint);
+      break;
+    case (kCipLint):
+      return sizeof(CipLint);
+      break;
+    case (kCipLword):
+      return sizeof(CipLword);
+      break;
+    case (kCipLtime):
+      return sizeof(CipLint);
+      break;
+#endif /* OPENER_SUPPORT_64BIT_DATATYPES */
+
     case (kCipStime):
       return sizeof(CipDint);
       break;
@@ -943,9 +948,6 @@ size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
     case (kCipDword):
       return sizeof(CipDword);
       break;
-    case (kCipLword):
-      return sizeof(CipLword);
-      break;
     case (kCipString2): {
       CipString *data = (CipString *) attribute_struct->data;
       return sizeof(CipUint) + 2 * (data->length) * sizeof(CipOctet);
@@ -954,9 +956,6 @@ size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
     case (kCipFtime):
       return sizeof(CipDint);
       break;
-    case (kCipLtime):
-      return sizeof(CipLint);
-      break;
     case (kCipItime):
       return sizeof(CipInt);
       break;

Разница между файлами не показана из-за своего большого размера
+ 185 - 424
source/src/cip/cipconnectionmanager.c


+ 8 - 254
source/src/cip/cipconnectionmanager.h

@@ -10,6 +10,7 @@
 #include "opener_api.h"
 #include "typedefs.h"
 #include "ciptypes.h"
+#include "cipconnectionobject.h"
 
 /**
  * @brief Connection Type constants of the Forward Open service request
@@ -18,19 +19,6 @@
  * - Point-to-point connection request (unicast)
  * - Multicast connection request
  */
-typedef enum {
-  kForwardOpenConnectionTypeNull = 0x0000,
-  kForwardOpenConnectionTypePointToPointConnection = 0x4000,
-  kForwardOpenConnectionTypeMulticastConnection = 0x2000,
-  kForwardOpenConnectionTypeReserved = 0x6000 /**< Reserved and therefore invalid type*/
-} ForwardOpenConnectionType;
-
-typedef enum {
-  kForwardOpenPriorityLow = 0x000,
-  kForwardOpenPriorityHigh = 0x400,
-  kForwardOpenPriorityScheduled = 0x800,
-  kForwardOpenPriorityUrgent = 0xC00
-} ForwardOpenPriority;
 
 typedef enum {
   kConnectionManagerGeneralStatusSuccess = 0x00, /**< General Status - Everything is ok */
@@ -153,37 +141,6 @@ typedef enum {
   kConnectionManagerExtendedStatusWrongCloser
 } ConnectionManagerExtendedStatusCode;
 
-typedef enum {
-  kConnectionTriggerTypeProductionTriggerMask = 0x70,
-  kConnectionTriggerTypeCyclicConnection = 0x0,
-  kConnectionTriggerTypeChangeOfStateTriggeredConnection = 0x10,
-  kConnectionTriggerTypeApplicationTriggeredConnection = 0x20
-} ConnectionTriggerType;
-
-typedef enum ProductionTrigger {
-  kProductionTriggerInvalid = -1,
-  kProductionTriggerCyclic = 0,
-  kProductionTriggerChangeOfState = 1,
-  kProductionTriggerApplicationObjectTriggered = 2
-} ProductionTrigger;
-
-ProductionTrigger GetProductionTrigger(
-  const ConnectionObject *const connection_object);
-
-void SetProductionTrigger(
-  const ProductionTrigger production_trigger,
-  ConnectionObject *connection_object);
-
-CipUint GetProductionInhibitTime(
-  const ConnectionObject *const connection_object);
-
-void SetProductionInhibitTime(
-  const EipUint16 production_inhibit_time,
-  ConnectionObject *const connection_object);
-
-CipUdint GetTargetToOriginatorRequestedPackedInterval(
-  const ConnectionObject *const connection_object);
-
 /** @brief macros for comparing sequence numbers according to CIP spec vol
  * 2 3-4.2 for int type variables
  * @define SEQ_LEQ32(a, b) Checks if sequence number a is less or equal than b
@@ -203,163 +160,6 @@ CipUdint GetTargetToOriginatorRequestedPackedInterval(
 #define SEQ_LEQ16(a, b) ( (short)( (a) - (b) ) <= 0 )
 #define SEQ_GEQ16(a, b) ( (short)( (a) - (b) ) >= 0 )
 
-/** @brief States of a connection */
-typedef enum {
-  kConnectionStateNonExistent = 0,
-  kConnectionStateConfiguring = 1,
-  kConnectionStateWaitingForConnectionId = 2 /**< only used in DeviceNet */,
-  kConnectionStateEstablished = 3,
-  kConnectionStateTimedOut = 4,
-  kConnectionStateDeferredDelete = 5 /**< only used in DeviceNet */,
-  kConnectionStateClosing
-} ConnectionState;
-
-/** @brief instance_type attributes */
-typedef enum {
-  kConnectionTypeExplicit = 0,
-  kConnectionTypeIoExclusiveOwner = 0x01,
-  kConnectionTypeIoInputOnly = 0x11,
-  kConnectionTypeIoListenOnly = 0x21
-} ConnectionType;
-
-typedef enum {
-  kConnectionObjectFixedConnectionSize,
-  kConnectionObjectVariableConnectionSize
-} ConnectionObjectFixedVariable;
-
-/** @brief Possible values for the watch dog time out action of a connection */
-typedef enum {
-  kWatchdogTimeoutActionTransitionToTimedOut = 0, /**< , invalid for explicit message connections */
-  kWatchdogTimeoutActionAutoDelete = 1, /**< Default for explicit message connections,
-                                           default for I/O connections on EIP */
-  kWatchdogTimeoutActionAutoReset = 2, /**< Invalid for explicit message connections */
-  kWatchdogTimeoutActionDeferredDelete = 3 /**< Only valid for DeviceNet, invalid for I/O connections */
-} WatchdogTimeoutAction;
-
-typedef struct {
-  ConnectionState state;
-  EipUint16 connection_id;
-/*TODO think if this is needed anymore
-   TCMReceiveDataFunc m_ptfuncReceiveData; */
-} LinkConsumer;
-
-typedef struct {
-  ConnectionState state;
-  EipUint16 connection_id;
-} LinkProducer;
-
-typedef struct {
-  LinkConsumer consumer;
-  LinkProducer producer;
-} LinkObject;
-
-/** The data needed for handling connections. This data is strongly related to
- * the connection object defined in the CIP-specification. However the full
- * functionality of the connection object is not implemented. Therefore this
- * data can not be accessed with CIP means.
- */
-typedef struct connection_object {
-  ConnectionState state; /**< state of the object */
-  ConnectionType instance_type; /**< Indicates either I/O or Messaging connection */
-  EipByte transport_type_class_trigger;
-  /* conditional
-     EipUint16 device_net_produced_connection_id;
-     EipUint16 device_net_consumed_connection_id;
-     EipByte device_net_initial_comm_characteristcs;
-   */
-
-  EipUint16 produced_connection_size;
-  EipUint16 consumed_connection_size;
-  EipUint16 expected_packet_rate;
-
-  /*conditional*/
-  EipUint32 cip_produced_connection_id;
-  EipUint32 cip_consumed_connection_id;
-  /**/
-  EipUint8 watchdog_timeout_action; /**< see enum WatchdogTimeoutAction */
-  EipUint16 produced_connection_path_length;
-  CipEpath produced_connection_path; /**< Packed EPATH */
-  EipUint16 consumed_connection_path_length;
-  CipEpath consumed_connection_path; /**< Packed EPATH */
-  /** @brief Minimal time between the production of two application triggered
-   * or change of state triggered I/O connection messages
-   */
-  EipUint16 production_inhibit_time;
-  EipUint16 connection_timeout_multiplier;
-  /* Conditional
-   * connection_binding_list < STRUCT OF UINT, Array of UINT
-   */
-  /* non CIP Attributes, only relevant for opened connections */
-  EipByte priority_timetick;
-  EipUint8 timeout_ticks;
-  EipUint16 connection_serial_number;
-  EipUint16 originator_vendor_id;
-  EipUint32 originator_serial_number;
-
-  EipUint32 o_to_t_requested_packet_interval;
-  EipUint16 o_to_t_network_connection_parameter;
-  EipUint32 t_to_o_requested_packet_interval;
-  EipUint16 t_to_o_network_connection_parameter;
-
-  EipUint8 connection_path_size;
-  CipElectronicKey electronic_key;
-  CipConnectionPath connection_path; /* padded EPATH*/
-  LinkObject link_object;
-
-  CipInstance *consuming_instance;
-  /*S_CIP_CM_Object *p_stConsumingCMObject; */
-
-  CipInstance *producing_instance;
-  /*S_CIP_CM_Object *p_stProducingCMObject; */
-
-  EipUint32 eip_level_sequence_count_producing; /* the EIP level sequence Count
-                                                   for Class 0/1
-                                                   Producing Connections may have a
-                                                   different
-                                                   value than SequenceCountProducing */
-  EipUint32 eip_level_sequence_count_consuming; /* the EIP level sequence Count
-                                                   for Class 0/1
-                                                   Producing Connections may have a
-                                                   different
-                                                   value than SequenceCountProducing */
-
-  EipUint16 sequence_count_producing; /* sequence Count for Class 1 Producing
-                                         Connections */
-  EipUint16 sequence_count_consuming; /* sequence Count for Class 1 Producing
-                                         Connections */
-
-  EipInt32 transmission_trigger_timer;
-  uint64_t inactivity_watchdog_timer;
-
-
-
-  /** @brief Timer for the production inhibition of application triggered or
-   * change-of-state I/O connections.
-   */
-  EipInt32 production_inhibit_timer;
-
-  struct sockaddr_in remote_address; /* socket address for produce */
-  struct sockaddr_in originator_address; /* the address of the originator that
-                                            established the connection. needed
-                                            for scanning if the right packet is
-                                            arriving */
-  int socket[2]; /* socket handles, indexed by kConsuming or kProducing */
-
-  /* pointers to connection handling functions */
-  ConnectionCloseFunction connection_close_function;
-  ConnectionTimeoutFunction connection_timeout_function;
-  ConnectionSendDataFunction connection_send_data_function;
-  ConnectionReceiveDataFunction connection_receive_data_function;
-
-  /* pointers to be used in the active connection list */
-  struct connection_object *next_connection_object;
-  struct connection_object *first_connection_object;
-
-  EipUint16 correct_originator_to_target_size;
-  EipUint16 correct_target_to_originator_size;
-  struct sockaddr_in original_opener_ip_address;
-} ConnectionObject;
-
 /** @brief Connection Manager class code */
 static const int g_kCipConnectionManagerClassCode = 0x06;
 
@@ -378,7 +178,7 @@ EipStatus ConnectionManagerInit(EipUint16 unique_connection_id);
  *   @return pointer to connected Object
  *           0 .. connection not present in device
  */
-ConnectionObject *GetConnectedObject(EipUint32 connection_id);
+CipConnectionObject *GetConnectedObject(const EipUint32 connection_id);
 
 /**  Get a connection object for a given output assembly.
  *
@@ -387,16 +187,8 @@ ConnectionObject *GetConnectedObject(EipUint32 connection_id);
  *   @return pointer to connected Object
  *           0 .. connection not present in device
  */
-ConnectionObject *GetConnectedOutputAssembly(EipUint32 output_assembly_id);
-
-/** @brief Copy the given connection data from source to destination
- *
- * @param destination Destination of the copy operation
- * @param osurce Source of the copy operation
- */
-void CopyConnectionData(
-  ConnectionObject *RESTRICT destination,
-  const ConnectionObject *RESTRICT const source);
+CipConnectionObject *GetConnectedOutputAssembly(
+  const EipUint32 output_assembly_id);
 
 /** @brief Close the given connection
  *
@@ -405,19 +197,11 @@ void CopyConnectionData(
  * @param connection_object pointer to the connection object structure to be
  * closed
  */
-void CloseConnection(ConnectionObject *RESTRICT connection_object);
+void CloseConnection(CipConnectionObject *RESTRICT connection_object);
 
 /* TODO: Missing documentation */
 EipBool8 IsConnectedOutputAssembly(const EipUint32 instance_number);
 
-/** @brief Generate the ConnectionIDs and set the general configuration
- * parameter in the given connection object.
- *
- * @param connection_object pointer to the connection object that should be set
- * up.
- */
-void GeneralConnectionConfiguration(ConnectionObject *connection_object);
-
 /** @brief Insert the given connection object to the list of currently active
  *  and managed connections.
  *
@@ -427,45 +211,15 @@ void GeneralConnectionConfiguration(ConnectionObject *connection_object);
  *
  * @param connection_object pointer to the connection object to be added.
  */
-void AddNewActiveConnection(ConnectionObject *connection_object);
+void AddNewActiveConnection(const CipConnectionObject *const connection_object);
 
 /** @brief Removes connection from the list of active connections
  *
  * @param connection_object Connection object to be removed from the active connection list
  */
-void RemoveFromActiveConnections(ConnectionObject *connection_object);
-
-/** @brief returns the connection type of the supplied network connection parameter
- *
- */
-ForwardOpenConnectionType GetConnectionType(
-  EipUint16 network_connection_parameter);
-
-ForwardOpenPriority GetConnectionObjectTToOPriority(
-  const ConnectionObject *const connection_object);
-
-ProductionTrigger GetProductionTrigger(
-  const ConnectionObject *const connection_object);
-
-void SetProductionTrigger(
-  const ProductionTrigger production_trigger,
-  ConnectionObject *connection_object);
-
-CipUint GetProductionInhibitTime(
-  const ConnectionObject *const connection_object);
-
-void SetProductionInhibitTime(
-  const EipUint16 production_inhibit_time,
-  ConnectionObject *const connection_object);
-
-CipUdint GetTargetToOriginatorRequestedPackedInterval(
-  const ConnectionObject *const RESTRICT connection_object);
+void RemoveFromActiveConnections(CipConnectionObject *const connection_object);
 
-ConnectionObjectFixedVariable
-GetConnectionObjectTargetToOriginatorFixedOrVariableConnectionSize(
-  const ConnectionObject *const RESTRICT connection_object);
 
-EipUint32 GetConnectionObjectInactivityWatchdogTimerValue(
-  ConnectionObject *connection_object);
+CipUint GetConnectionId(void);
 
 #endif /* OPENER_CIPCONNECTIONMANAGER_H_ */

+ 800 - 0
source/src/cip/cipconnectionobject.c

@@ -0,0 +1,800 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "cipconnectionobject.h"
+
+#include "endianconv.h"
+#include "trace.h"
+#include "cipconnectionmanager.h"
+
+#define CIP_CONNECTION_OBJECT_STATE_NON_EXISTENT 0U
+#define CIP_CONNECTION_OBJECT_STATE_CONFIGURING 1U
+#define CIP_CONNECTION_OBJECT_STATE_WAITING_FOR_CONNECTION_ID 2U
+#define CIP_CONNECTION_OBJECT_STATE_ESTABLISHED 3U
+#define CIP_CONNECTION_OBJECT_STATE_TIMEOUT 4U
+#define CIP_CONNECTION_OBJECT_STATE_DEFERRED_DELETE 5U
+#define CIP_CONNECTION_OBJECT_STATE_CLOSING 6U
+
+#define CIP_CONNECTION_OBJECT_INSTANCE_TYPE_EXPLICIT_MESSAGING 0
+#define CIP_CONNECTION_OBJECT_INSTANCE_TYPE_IO 1
+#define CIP_CONNECTION_OBJECT_INSTANCE_TYPE_CIP_BRIDGED 2
+
+#define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CYCLIC ( \
+    0 << 4)
+#define \
+  CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CHANGE_OF_STATE ( \
+    1 << 4)
+#define \
+  CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_APPLICATION_OBJECT ( \
+    2 << 4)
+
+#define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_0 0
+#define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_1 1
+#define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_2 2
+#define CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_3 3
+
+#define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_TRANSITION_TO_TIMED_OUT 0
+#define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_DELETE 1
+#define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_RESET 2
+#define CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_DEFERRED_DELETE 3
+
+#define CIP_CONNECTION_OBJECT_CONNECTION_TYPE_NULL 0
+#define CIP_CONNECTION_OBJECT_CONNECTION_TYPE_MULTICAST (1 << 13)
+#define CIP_CONNECTION_OBJECT_CONNECTION_TYPE_POINT_TO_POINT (1 << 14)
+
+#define CIP_CONNECTION_OBJECT_PRIORITY_LOW 0
+#define CIP_CONNECTION_OBJECT_PRIORITY_HIGH (1 << 10)
+#define CIP_CONNECTION_OBJECT_PRIORITY_SCHEDULED (1 << 11)
+#define CIP_CONNECTION_OBJECT_PRIORITY_URGENT (3 << 10)
+
+DoublyLinkedList connection_list;
+
+/** @brief Array of the available explicit connections */
+CipConnectionObject explicit_connection_object_pool[
+  OPENER_CIP_NUM_EXPLICIT_CONNS];
+
+DoublyLinkedListNode *CipConnectionObjectListArrayAllocator() {
+  enum {kNodesAmount = OPENER_CIP_NUM_EXPLICIT_CONNS +
+                       OPENER_CIP_NUM_INPUT_ONLY_CONNS +
+                       OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS +
+                       OPENER_CIP_NUM_LISTEN_ONLY_CONNS};
+  static DoublyLinkedListNode nodes[kNodesAmount] = {0};
+  for(size_t i = 0; i < kNodesAmount; ++i) {
+    if(nodes[i].previous == NULL && nodes[i].next == NULL && nodes[i].data ==
+       NULL) {
+      return &nodes[i];
+    }
+  }
+  return NULL;
+}
+
+void CipConnectionObjectListArrayFree(DoublyLinkedListNode **node) {
+
+  if(NULL != *node && NULL != node) {
+    memset( *node, 0, sizeof(DoublyLinkedListNode) );
+    *node = NULL;
+  } else {
+    OPENER_TRACE_ERR("Attempt to delete NULL pointer to node\n");
+  }
+
+}
+
+
+/* Private methods declaration */
+uint64_t ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetInitialInactivityWatchdogTimerValue(
+  CipConnectionObject *const connection_object);
+/* End private methods declaration */
+
+void ConnectionObjectInitializeEmpty(
+  CipConnectionObject *const connection_object) {
+  memset( connection_object, 0, sizeof(*connection_object) );
+  ConnectionObjectSetState(connection_object,
+                           kConnectionObjectStateNonExistent);
+  connection_object->socket[0] = kEipInvalidSocket;
+  connection_object->socket[1] = kEipInvalidSocket;
+}
+
+CipConnectionObject *CipConnectionObjectCreate(const CipOctet *message) {
+  assert(false); /* NOT IMLEMENTED */
+  return NULL;
+}
+
+void ConnectionObjectInitializeFromMessage(
+  const CipOctet **message,
+  CipConnectionObject *const connection_object) {
+  /* For unconnected send - can be ignored by targets, and is ignored here */
+  CipByte priority_timetick = GetSintFromMessage(message);
+  CipUsint timeout_ticks = GetSintFromMessage(message);
+
+  /* O_to_T Conn ID */
+  ConnectionObjectSetCipConsumedConnectionID(connection_object,
+                                             GetDintFromMessage(message) );
+  /* T_to_O Conn ID */
+  ConnectionObjectSetCipProducedConnectionID(connection_object,
+                                             GetDintFromMessage(message) );
+
+  ConnectionObjectSetConnectionSerialNumber(connection_object,
+                                            GetIntFromMessage(message) );
+  ConnectionObjectSetOriginatorVendorId(connection_object,
+                                        GetIntFromMessage(message) );
+  ConnectionObjectSetOriginatorSerialNumber(connection_object,
+                                            GetDintFromMessage(message) );
+
+  /* keep it to none existent till the setup is done this eases error handling and
+   * the state changes within the forward open request can not be detected from
+   * the application or from outside (reason we are single threaded)
+   * */
+  ConnectionObjectSetState(connection_object,
+                           kConnectionObjectStateNonExistent);
+  connection_object->sequence_count_producing = 0; /* set the sequence count to zero */
+
+  ConnectionObjectSetConnectionTimeoutMultiplier(connection_object,
+                                                 GetSintFromMessage(
+                                                   message) );
+
+  MoveMessageNOctets(3, message); /* 3 bytes reserved */
+
+  /* the requested packet interval parameter needs to be a multiple of TIMERTICK from the header file */
+  OPENER_TRACE_INFO(
+    "ForwardOpen: ConConnID %" PRIu32 ", ProdConnID %" PRIu32
+    ", ConnSerNo %u\n",
+    connection_object->cip_consumed_connection_id,
+    connection_object->cip_produced_connection_id,
+    connection_object->connection_serial_number);
+
+  ConnectionObjectSetOToTRequestedPacketInterval(connection_object,
+                                                 GetDintFromMessage(
+                                                   message) );
+
+  ConnectionObjectSetInitialInactivityWatchdogTimerValue(connection_object);
+
+  //TODO: introduce setter function
+  connection_object->o_to_t_network_connection_parameters = GetIntFromMessage(
+    message);
+
+  ConnectionObjectSetTToORequestedPacketInterval(connection_object,
+                                                 GetDintFromMessage(message) );
+
+  ConnectionObjectSetExpectedPacketRate(connection_object);
+
+  connection_object->t_to_o_network_connection_parameters = GetIntFromMessage(
+    message);
+
+  connection_object->transport_class_trigger = GetSintFromMessage(message);
+}
+
+ConnectionObjectState ConnectionObjectGetState(
+  const CipConnectionObject *const connection_object) {
+  switch (connection_object->state) {
+    case CIP_CONNECTION_OBJECT_STATE_NON_EXISTENT:
+      return kConnectionObjectStateNonExistent;
+      break;
+    case CIP_CONNECTION_OBJECT_STATE_CONFIGURING:
+      return kConnectionObjectStateConfiguring;
+      break;
+    case CIP_CONNECTION_OBJECT_STATE_WAITING_FOR_CONNECTION_ID:
+      return kConnectionObjectStateWaitingForConnectionID;
+      break;
+    case CIP_CONNECTION_OBJECT_STATE_ESTABLISHED:
+      return kConnectionObjectStateEstablished;
+      break;
+    case CIP_CONNECTION_OBJECT_STATE_TIMEOUT:
+      return kConnectionObjectStateTimedOut;
+      break;
+    case CIP_CONNECTION_OBJECT_STATE_DEFERRED_DELETE:
+      return kConnectionObjectStateDeferredDelete;
+      break;
+    case CIP_CONNECTION_OBJECT_STATE_CLOSING:
+      return kConnectionObjectStateClosing;
+      break;
+    default:
+      return kConnectionObjectStateInvalid;
+  }
+}
+
+void ConnectionObjectSetState(CipConnectionObject *const connection_object,
+                              const ConnectionObjectState state) {
+  switch (state) {
+    case kConnectionObjectStateNonExistent:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_NON_EXISTENT;
+      break;
+    case kConnectionObjectStateConfiguring:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_CONFIGURING;
+      break;
+    case kConnectionObjectStateWaitingForConnectionID:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_WAITING_FOR_CONNECTION_ID;
+      break;
+    case kConnectionObjectStateEstablished:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_ESTABLISHED;
+      break;
+    case kConnectionObjectStateTimedOut:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_TIMEOUT;
+      break;
+    case kConnectionObjectStateDeferredDelete:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_DEFERRED_DELETE;
+      break;
+    case kConnectionObjectStateClosing:
+      connection_object->state =
+        CIP_CONNECTION_OBJECT_STATE_CLOSING;
+      break;
+    default:
+      OPENER_ASSERT(false); /* Never get here */
+  }
+}
+
+ConnectionObjectInstanceType ConnectionObjectGetInstanceType(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->instance_type;
+//  switch (connection_object->instance_type) {
+//    case CIP_CONNECTION_OBJECT_INSTANCE_TYPE_EXPLICIT_MESSAGING:
+//      return kConnectionObjectInstanceTypeExplicitMessaging;
+//      break;
+//    case CIP_CONNECTION_OBJECT_INSTANCE_TYPE_IO:
+//      return kConnectionObjectInstanceTypeIO;
+//      break;
+//    case CIP_CONNECTION_OBJECT_INSTANCE_TYPE_CIP_BRIDGED:
+//      return kConnectionObjectInstanceTypeCipBridged;
+//      break;
+//    default:
+//      return kConnectionObjectInstanceTypeInvalid;
+//  }
+}
+
+void ConnectionObjectSetInstanceType(
+  CipConnectionObject *const connection_object,
+  const ConnectionObjectInstanceType instance_type) {
+  connection_object->instance_type = instance_type;
+}
+
+CipUsint ConnectionObjectGetInstanceTypeForAttribute(
+  const CipConnectionObject *const connection_object) {
+  switch (connection_object->instance_type) {
+    case kConnectionObjectInstanceTypeExplicitMessaging:
+      return CIP_CONNECTION_OBJECT_INSTANCE_TYPE_EXPLICIT_MESSAGING;
+      break;
+    case kConnectionObjectInstanceTypeIO:
+    case kConnectionObjectInstanceTypeIOExclusiveOwner:
+    case kConnectionObjectInstanceTypeIOInputOnly:
+    case kConnectionObjectInstanceTypeIOListenOnly:
+      return CIP_CONNECTION_OBJECT_INSTANCE_TYPE_IO;
+      break;
+    case kConnectionObjectInstanceTypeCipBridged:
+      return CIP_CONNECTION_OBJECT_INSTANCE_TYPE_CIP_BRIDGED;
+      break;
+    default:
+      assert(false);
+  }
+  assert(false);         //We should never come to this point
+  return 255;
+}
+
+bool ConnectionObjectIsTypeIOConnection(
+  const CipConnectionObject *const connection_object) {
+  switch(connection_object->instance_type) {
+    case kConnectionObjectInstanceTypeIO:
+    case kConnectionObjectInstanceTypeIOExclusiveOwner:
+    case kConnectionObjectInstanceTypeIOInputOnly:
+    case kConnectionObjectInstanceTypeIOListenOnly:
+      return true;
+    default: return false;
+  }
+  return false;
+}
+
+ConnectionObjectTransportClassTriggerDirection
+ConnectionObjectGetTransportClassTriggerDirection(
+  const CipConnectionObject *const connection_object) {
+  const CipByte TransportClassTriggerDirectionMask = 0x80;
+  return (connection_object->transport_class_trigger &
+          TransportClassTriggerDirectionMask) ==
+         TransportClassTriggerDirectionMask ?
+         kConnectionObjectTransportClassTriggerDirectionServer
+         : kConnectionObjectTransportClassTriggerDirectionClient;
+}
+
+ConnectionObjectTransportClassTriggerProductionTrigger
+ConnectionObjectGetTransportClassTriggerProductionTrigger(
+  const CipConnectionObject *const connection_object) {
+  const CipByte kTransportClassTriggerProductionTriggerMask = 0x70;
+  switch ( (connection_object->transport_class_trigger) &
+           kTransportClassTriggerProductionTriggerMask ) {
+    case
+      CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CYCLIC:
+      return kConnectionObjectTransportClassTriggerProductionTriggerCyclic;
+      break;
+    case
+      CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_CHANGE_OF_STATE
+      :
+      return
+        kConnectionObjectTransportClassTriggerProductionTriggerChangeOfState;
+      break;
+    case
+      CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_PRODUCTION_TRIGGER_APPLICATION_OBJECT
+      :
+      return
+        kConnectionObjectTransportClassTriggerProductionTriggerApplicationObject;
+      break;
+    default:
+      return kConnectionObjectTransportClassTriggerProductionTriggerInvalid;
+  }
+}
+
+ConnectionObjectTransportClassTriggerTransportClass
+ConnectionObjectGetTransportClassTriggerTransportClass(
+  const CipConnectionObject *const connection_object) {
+  const CipByte kTransportClassTriggerTransportClassMask = 0x0F;
+  switch ( (connection_object->transport_class_trigger) &
+           kTransportClassTriggerTransportClassMask ) {
+    case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_0:
+      return kConnectionObjectTransportClassTriggerTransportClass0;
+      break;
+    case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_1:
+      return kConnectionObjectTransportClassTriggerTransportClass1;
+      break;
+    case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_2:
+      return kConnectionObjectTransportClassTriggerTransportClass2;
+      break;
+    case CIP_CONNECTION_OBJECT_TRANSPORT_CLASS_TRIGGER_TRANSPORT_CLASS_3:
+      return kConnectionObjectTransportClassTriggerTransportClass3;
+      break;
+    default:
+      return kConnectionObjectTransportClassTriggerTransportClassInvalid;
+  }
+}
+
+CipUint ConnectionObjectGetProducedConnectionSize(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->produced_connection_size;
+}
+
+void ConnectionObjectSetProducedConnectionSize(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  produced_connection_size) {
+  connection_object->produced_connection_size = produced_connection_size;
+}
+
+CipUint ConnectionObjectGetConsumedConnectionSize(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->consumed_connection_size;
+}
+
+void ConnectionObjectSetConsumedConnectionSize(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  consumed_connection_size) {
+  connection_object->consumed_connection_size = consumed_connection_size;
+}
+
+CipUint ConnectionObjectGetExpectedPacketRate(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->expected_packet_rate;
+}
+
+CipUint ConnectionObjectGetRequestedPacketInterval(
+  const CipConnectionObject *const connection_object) {
+  CipUdint remainder_to_resolution =
+    (connection_object->t_to_o_requested_packet_interval) %
+    (kOpenerTimerTickInMilliSeconds * 1000);
+  if( 0 == remainder_to_resolution ) {         /* Value can be represented in multiples of the timer resolution */
+    return (CipUint)(connection_object->t_to_o_requested_packet_interval /
+                     1000);
+  }
+  else{
+    return (CipUint)(connection_object->t_to_o_requested_packet_interval /
+                     1000 - remainder_to_resolution / 1000);
+  }
+}
+
+void ConnectionObjectSetExpectedPacketRate(
+  CipConnectionObject *const connection_object) {
+  CipUdint remainder_to_resolution =
+    (connection_object->t_to_o_requested_packet_interval) %
+    (kOpenerTimerTickInMilliSeconds * 1000);
+  if( 0 == remainder_to_resolution ) { /* Value can be represented in multiples of the timer resolution */
+    connection_object->expected_packet_rate =
+      connection_object->t_to_o_requested_packet_interval / 1000;
+  }
+  else{
+    connection_object->expected_packet_rate =
+      connection_object->t_to_o_requested_packet_interval / 1000 +
+      ( (CipUdint)
+        kOpenerTimerTickInMilliSeconds - remainder_to_resolution / 1000 );
+  }
+}
+
+CipUdint ConnectionObjectGetCipProducedConnectionID(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->cip_produced_connection_id;
+}
+
+void ConnectionObjectSetCipProducedConnectionID(
+  CipConnectionObject *const connection_object,
+  const CipUdint
+  cip_produced_connection_id) {
+  connection_object->cip_produced_connection_id = cip_produced_connection_id;
+}
+
+CipUdint ConnectionObjectGetCipConsumedConnectionID(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->cip_consumed_connection_id;
+}
+
+void ConnectionObjectSetCipConsumedConnectionID(
+  CipConnectionObject *const connection_object,
+  const CipUdint
+  cip_consumed_connection_id) {
+  connection_object->cip_consumed_connection_id = cip_consumed_connection_id;
+}
+
+ConnectionObjectWatchdogTimeoutAction ConnectionObjectGetWatchdogTimeoutAction(
+  const CipConnectionObject *const connection_object) {
+  switch (connection_object->watchdog_timeout_action) {
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_TRANSITION_TO_TIMED_OUT:
+      return kConnectionObjectWatchdogTimeoutActionTransitionToTimedOut;
+      break;
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_DELETE:
+      return kConnectionObjectWatchdogTimeoutActionAutoDelete;
+      break;
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_RESET:
+      return kConnectionObjectWatchdogTimeoutActionAutoReset;
+      break;
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_DEFERRED_DELETE:
+      return kConnectionObjectWatchdogTimeoutActionDeferredDelete;
+      break;
+    default:
+      return kConnectionObjectWatchdogTimeoutActionInvalid;
+      break;
+  }
+}
+
+void ConnectionObjectSetWatchdogTimeoutAction(
+  CipConnectionObject *const connection_object,
+  const CipUsint
+  watchdog_timeout_action) {
+  switch (watchdog_timeout_action) {
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_TRANSITION_TO_TIMED_OUT:
+      connection_object->watchdog_timeout_action =
+        kConnectionObjectWatchdogTimeoutActionTransitionToTimedOut;
+      break;
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_DELETE:
+      connection_object->watchdog_timeout_action =
+        kConnectionObjectWatchdogTimeoutActionAutoDelete;
+      break;
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_AUTO_RESET:
+      connection_object->watchdog_timeout_action =
+        kConnectionObjectWatchdogTimeoutActionAutoReset;
+      break;
+    case CIP_CONNECTION_OBJECT_WATCHDOG_TIMEOUT_ACTION_DEFERRED_DELETE:
+      connection_object->watchdog_timeout_action =
+        kConnectionObjectWatchdogTimeoutActionDeferredDelete;
+      break;
+    default:
+      connection_object->watchdog_timeout_action =
+        kConnectionObjectWatchdogTimeoutActionInvalid;
+      break;
+  }
+}
+
+CipUint ConnectionObjectGetProducedConnectionPathLength(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->produced_connection_path_length;
+}
+
+void ConnectionObjectSetProducedConnectionPathLength(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  produced_connection_path_length) {
+  connection_object->produced_connection_path_length =
+    produced_connection_path_length;
+}
+
+CipUint ConnectionObjectGetConsumedConnectionPathLength(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->consumed_connection_path_length;
+}
+
+void ConnectionObjectSetConsumedConnectionPathLength(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  consumed_connection_path_length) {
+  connection_object->consumed_connection_path_length =
+    consumed_connection_path_length;
+}
+
+CipUint ConnectionObjectGetProductionInhibitTime(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->production_inhibit_time;
+}
+
+void ConnectionObjectSetProductionInhibitTime(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  production_inhibit_time) {
+  connection_object->production_inhibit_time = production_inhibit_time;
+}
+
+/*setup the preconsumption timer: max(ConnectionTimeoutMultiplier * ExpectedPacketRate, 10s) */
+void ConnectionObjectSetInitialInactivityWatchdogTimerValue(
+  CipConnectionObject *const connection_object) {
+  const uint64_t kMinimumInitialTimeoutValue = 10000;
+  const uint64_t calculated_timeout_value =
+    ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
+      connection_object);
+  connection_object->inactivity_watchdog_timer =
+    (calculated_timeout_value >
+     kMinimumInitialTimeoutValue) ? calculated_timeout_value :
+    kMinimumInitialTimeoutValue;
+}
+
+void ConnectionObjectResetInactivityWatchdogTimerValue(
+  CipConnectionObject *const connection_object) {
+  connection_object->inactivity_watchdog_timer =
+    ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
+      connection_object);
+}
+
+uint64_t ConnectionObjectCalculateRegularInactivityWatchdogTimerValue(
+  const CipConnectionObject *const connection_object) {
+  return ( ( (connection_object->o_to_t_requested_packet_interval) /
+             1000 ) << (2 + connection_object->connection_timeout_multiplier) );
+}
+
+
+
+CipUint ConnectionObjectGetConnectionSerialNumber(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->connection_serial_number;
+}
+
+void ConnectionObjectSetConnectionSerialNumber(
+  CipConnectionObject *connection_object,
+  const CipUint connection_serial_number) {
+  connection_object->connection_serial_number = connection_serial_number;
+}
+
+CipUint ConnectionObjectGetOriginatorVendorId(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->originator_vendor_id;
+}
+
+void ConnectionObjectSetOriginatorVendorId(
+  CipConnectionObject *connection_object,
+  const CipUint vendor_id) {
+  connection_object->originator_vendor_id = vendor_id;
+}
+
+CipUdint ConnectionObjectGetOriginatorSerialNumber(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->originator_serial_number;
+}
+
+void ConnectionObjectSetOriginatorSerialNumber(
+  CipConnectionObject *connection_object,
+  CipUdint originator_serial_number) {
+  connection_object->originator_serial_number = originator_serial_number;
+}
+
+CipUsint ConnectionObjectGetConnectionTimeoutMultiplier(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->connection_timeout_multiplier;
+}
+
+void ConnectionObjectSetConnectionTimeoutMultiplier(
+  CipConnectionObject *connection_object,
+  CipUsint connection_timeout_multiplier) {
+  connection_object->connection_timeout_multiplier =
+    connection_timeout_multiplier;
+}
+
+CipUdint ConnectionObjectGetOToTRequestedPacketInterval(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->o_to_t_requested_packet_interval;
+}
+
+void ConnectionObjectSetOToTRequestedPacketInterval(
+  CipConnectionObject *connection_object,
+  const CipUdint requested_packet_interval) {
+  connection_object->o_to_t_requested_packet_interval =
+    requested_packet_interval;
+}
+
+CipUdint ConnectionObjectGetTToORequestedPacketInterval(
+  const CipConnectionObject *const connection_object) {
+  return connection_object->t_to_o_requested_packet_interval;
+}
+
+void ConnectionObjectSetTToORequestedPacketInterval(
+  CipConnectionObject *connection_object,
+  const CipUdint requested_packet_interval) {
+  connection_object->t_to_o_requested_packet_interval =
+    requested_packet_interval;
+}
+
+bool ConnectionObjectIsOToTRedundantOwner(
+  const CipConnectionObject *const connection_object) {
+  const CipWord kOwnerMask = 0x80;
+  return kOwnerMask & connection_object->o_to_t_network_connection_parameters;
+}
+
+bool ConnectionObjectIsTToORedundantOwner(
+  const CipConnectionObject *const connection_object) {
+  const CipWord kOwnerMask = 0x80;
+  return kOwnerMask & connection_object->t_to_o_network_connection_parameters;
+}
+
+ConnectionObjectConnectionType ConnectionObjectGetConnectionType(
+  const CipWord connection_parameters) {
+  const CipWord kConnectionTypeMask = 3 << 13;
+  switch(connection_parameters & kConnectionTypeMask) {
+    case CIP_CONNECTION_OBJECT_CONNECTION_TYPE_NULL: return
+        kConnectionObjectConnectionTypeNull;
+    case CIP_CONNECTION_OBJECT_CONNECTION_TYPE_MULTICAST: return
+        kConnectionObjectConnectionTypeMulticast;
+    case CIP_CONNECTION_OBJECT_CONNECTION_TYPE_POINT_TO_POINT: return
+        kConnectionObjectConnectionTypePointToPoint;
+    default: return kConnectionObjectConnectionTypeInvalid;
+  }
+}
+
+ConnectionObjectConnectionType ConnectionObjectGetOToTConnectionType(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetConnectionType(
+    connection_object->o_to_t_network_connection_parameters);
+}
+
+ConnectionObjectConnectionType ConnectionObjectGetTToOConnectionType(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetConnectionType(
+    connection_object->t_to_o_network_connection_parameters);
+}
+
+ConnectionObjectPriority ConnectionObjectGetPriority(
+  const CipWord connection_parameters) {
+  const CipWord kPriorityMask = 3 << 10;
+  ConnectionObjectPriority result;
+  switch(connection_parameters & kPriorityMask) {
+    case CIP_CONNECTION_OBJECT_PRIORITY_LOW: result =
+      kConnectionObjectPriorityLow; break;
+    case CIP_CONNECTION_OBJECT_PRIORITY_HIGH: result =
+      kConnectionObjectPriorityHigh; break;
+    case CIP_CONNECTION_OBJECT_PRIORITY_SCHEDULED: result =
+      kConnectionObjectPriorityScheduled; break;
+    case CIP_CONNECTION_OBJECT_PRIORITY_URGENT: result =
+      kConnectionObjectPriorityUrgent; break;
+    default: OPENER_ASSERT(false); //Not possible to get here!
+  }
+  return result;
+}
+
+ConnectionObjectPriority ConnectionObjectGetOToTPriority(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetPriority(
+    connection_object->o_to_t_network_connection_parameters);
+}
+
+ConnectionObjectPriority ConnectionObjectGetTToOPriority(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetPriority(
+    connection_object->t_to_o_network_connection_parameters);
+}
+
+
+ConnectionObjectConnectionSizeType ConnectionObjectGetConnectionSizeType(
+  const CipWord connection_parameters) {
+  const CipWord kConnectionSizeTypeMask = 1 << 9;
+  if(connection_parameters & kConnectionSizeTypeMask) {
+    return kConnectionObjectConnectionSizeTypeVariable;
+  } else {
+    return kConnectionObjectConnectionSizeTypeFixed;
+  }
+}
+
+ConnectionObjectConnectionSizeType ConnectionObjectGetOToTConnectionSizeType(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetConnectionSizeType(
+    connection_object->o_to_t_network_connection_parameters);
+}
+
+ConnectionObjectConnectionSizeType ConnectionObjectGetTToOConnectionSizeType(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetConnectionSizeType(
+    connection_object->t_to_o_network_connection_parameters);
+}
+
+size_t ConnectionObjectGetConnectionSize(const CipWord connection_parameters) {
+  const CipWord kConnectionSizeMask = 0x01FF;
+  return connection_parameters & kConnectionSizeMask;
+}
+
+size_t ConnectionObjectGetOToTConnectionSize(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetConnectionSize(
+    connection_object->o_to_t_network_connection_parameters);
+}
+
+size_t ConnectionObjectGetTToOConnectionSize(
+  const CipConnectionObject *const connection_object) {
+  return ConnectionObjectGetConnectionSize(
+    connection_object->t_to_o_network_connection_parameters);
+}
+
+void ConnectionObjectDeepCopy(
+  CipConnectionObject *RESTRICT destination,
+  const CipConnectionObject *RESTRICT const source
+  ) {
+  memcpy( destination, source, sizeof(CipConnectionObject) );
+}
+
+void ConnectionObjectResetSequenceCounts(
+  CipConnectionObject *const connection_object) {
+  connection_object->eip_level_sequence_count_producing = 0;
+  connection_object->sequence_count_producing = 0;
+  connection_object->eip_level_sequence_count_consuming = 0;
+  connection_object->sequence_count_consuming = 0;
+}
+
+void ConnectionObjectResetProductionInhibitTimer(
+  CipConnectionObject *const connection_object) {
+  connection_object->production_inhibit_timer =
+    connection_object->production_inhibit_time;
+}
+
+void ConnectionObjectGeneralConfiguration(
+  CipConnectionObject *const connection_object) {
+
+  connection_object->socket[0] = kEipInvalidSocket;
+  connection_object->socket[1] = kEipInvalidSocket;
+
+  if ( kConnectionObjectConnectionTypePointToPoint
+       == ConnectionObjectGetOToTConnectionType(connection_object) ) {
+    /* if we have a point to point connection for the O to T direction
+     * the target shall choose the connection ID.
+     */
+    ConnectionObjectSetCipConsumedConnectionID(connection_object,
+                                               GetConnectionId() );
+  }
+
+  if ( kConnectionObjectConnectionTypeMulticast
+       == ConnectionObjectGetTToOConnectionType(connection_object) ) {
+    /* if we have a multi-cast connection for the T to O direction the
+     * target shall choose the connection ID.
+     */
+    ConnectionObjectSetCipProducedConnectionID(connection_object,
+                                               GetConnectionId() );
+  }
+
+  ConnectionObjectResetSequenceCounts(connection_object);
+
+  ConnectionObjectSetWatchdogTimeoutAction(connection_object,
+                                           kConnectionObjectWatchdogTimeoutActionInvalid);                    /* Correct value not know at this point */
+
+  ConnectionObjectResetProductionInhibitTimer(connection_object);
+
+  connection_object->transmission_trigger_timer = 0;
+}
+
+bool EqualConnectionTriad(const CipConnectionObject *const object1,
+                          const CipConnectionObject *const object2) {
+  if ( (object1->connection_serial_number
+        == object2->connection_serial_number)
+       && (object1->originator_vendor_id
+           == object2->originator_vendor_id)
+       && (object1->originator_serial_number
+           == object2->originator_serial_number) ) {
+    return true;
+  }
+  return false;
+}

+ 420 - 0
source/src/cip/cipconnectionobject.h

@@ -0,0 +1,420 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef SRC_CIP_CIPCONNECTIONOBJECT_H_
+#define SRC_CIP_CIPCONNECTIONOBJECT_H_
+
+#include "typedefs.h"
+#include "ciptypes.h"
+#include "opener_user_conf.h"
+#include "opener_api.h"
+#include "doublylinkedlist.h"
+#include "cipelectronickey.h"
+#include "cipepath.h"
+
+#define CIP_CONNECTION_OBJECT_CODE 0x05
+
+typedef enum {
+  kConnectionObjectStateNonExistent = 0, /**< Connection is non existent */
+  kConnectionObjectStateConfiguring, /**< Waiting for both to be configured and to apply the configuration */
+  kConnectionObjectStateWaitingForConnectionID, /**< Only used for device net */
+  kConnectionObjectStateEstablished, /**< Connection is established */
+  kConnectionObjectStateTimedOut, /**< Connection timed out - inactivity or watchdog timer expired */
+  kConnectionObjectStateDeferredDelete, /**< Only used for device net */
+  kConnectionObjectStateClosing, /**< For CIP bridged connections - have to wait for a successful forward close */
+  kConnectionObjectStateInvalid /**< An invalid state, shall never occur! */
+} ConnectionObjectState;
+
+typedef enum {
+  kConnectionObjectInstanceTypeInvalid = -1, /**< Invalid instance type - shall never occur! */
+  kConnectionObjectInstanceTypeExplicitMessaging = 0, /**< Connection is an explicit messaging connection */
+  kConnectionObjectInstanceTypeIO, /**< Connection is an I/O connection */
+  kConnectionObjectInstanceTypeIOExclusiveOwner, /**< Also I/O connection, only for easy differentiation */
+  kConnectionObjectInstanceTypeIOInputOnly, /**< Also I/O connection, only for easy differentiation */
+  kConnectionObjectInstanceTypeIOListenOnly, /**< Also I/O connection, only for easy differentiation */
+  kConnectionObjectInstanceTypeCipBridged  /**< Connection is a bridged connection */
+} ConnectionObjectInstanceType;
+
+typedef enum {
+  kConnectionObjectTransportClassTriggerDirectionClient = 0,  /**< Endpoint provides client behavior */
+  kConnectionObjectTransportClassTriggerDirectionServer /**< Endpoint provides server behavior - production trigger bits are to be ignored */
+} ConnectionObjectTransportClassTriggerDirection;
+
+typedef enum {
+  kConnectionObjectTransportClassTriggerProductionTriggerInvalid = -1,  /**< Invalid Production trigger - shall never occur! */
+  kConnectionObjectTransportClassTriggerProductionTriggerCyclic = 0, /**< Transmission Trigger Timer trigger data production */
+  kConnectionObjectTransportClassTriggerProductionTriggerChangeOfState, /**< Production is trigger when change-of-state is detected by the Application Object */
+  kConnectionObjectTransportClassTriggerProductionTriggerApplicationObject /**< The Application Object decided when production is triggered */
+} ConnectionObjectTransportClassTriggerProductionTrigger;
+
+typedef enum {
+  kConnectionObjectTransportClassTriggerTransportClassInvalid = -1, /**< Invalid Transport Class - shall never occur! */
+  kConnectionObjectTransportClassTriggerTransportClass0 = 0, /**< Class 0 producing or consuming connection, based on Direction */
+  kConnectionObjectTransportClassTriggerTransportClass1, /**< Class 1 producing or consuming connection, based on Direction */
+  kConnectionObjectTransportClassTriggerTransportClass2, /**< Class 2 producing and consuming connection, Client starts producing */
+  kConnectionObjectTransportClassTriggerTransportClass3 /**< Class 3 producing and consuming connection, Client starts producing */
+  /* Higher transport classes not supported */
+} ConnectionObjectTransportClassTriggerTransportClass;
+
+/** @brief Possible values for the watch dog time out action of a connection
+ *
+ * Only positive values allowed
+ */
+typedef enum {
+  kConnectionObjectWatchdogTimeoutActionTransitionToTimedOut = 0,       /**< Default for I/O connections, invalid for Explicit Messaging */
+  kConnectionObjectWatchdogTimeoutActionAutoDelete,       /**< Default for explicit connections */
+  kConnectionObjectWatchdogTimeoutActionAutoReset,       /**< Invalid for explicit connections */
+  kConnectionObjectWatchdogTimeoutActionDeferredDelete,       /**< Only for Device Net, invalid for I/O connections */
+  kConnectionObjectWatchdogTimeoutActionInvalid       /**< Invalid Watchdog Timeout Action - shall never occur! */
+} ConnectionObjectWatchdogTimeoutAction;
+
+typedef enum {
+  kConnectionObjectConnectionTypeNull = 0,
+  kConnectionObjectConnectionTypeMulticast,
+  kConnectionObjectConnectionTypePointToPoint,
+  kConnectionObjectConnectionTypeInvalid
+} ConnectionObjectConnectionType;
+
+typedef enum {
+  kConnectionObjectPriorityLow = 0,
+  kConnectionObjectPriorityHigh,
+  kConnectionObjectPriorityScheduled,
+  kConnectionObjectPriorityUrgent
+} ConnectionObjectPriority;
+
+typedef enum {
+  kConnectionObjectConnectionSizeTypeFixed,
+  kConnectionObjectConnectionSizeTypeVariable
+} ConnectionObjectConnectionSizeType;
+
+typedef enum {
+  kConnectionObjectSocketTypeProducing = 0,
+  kConnectionObjectSocketTypeConsuming = 1
+} ConnectionObjectSocketType;
+
+typedef struct cip_connection_object CipConnectionObject;
+
+typedef EipStatus (*CipConnectionStateHandler)(CipConnectionObject *RESTRICT
+                                               const connection_object,
+                                               ConnectionObjectState new_state);
+
+struct cip_connection_object {
+  CipUsint state; /*< Attribute 1 */
+  CipUsint instance_type; /*< Attribute 2 */
+  CipByte transport_class_trigger; /*< Attribute 3 */
+  /* Attribute 4-6 only for device net*/
+  CipUint produced_connection_size; /*< Attribute 7 - Limits produced connection size - for explicit messaging 0xFFFF means no predefined limit */
+  CipUint consumed_connection_size; /*< Attribute 8 - Limits produced connection size - for explicit messaging 0xFFFF means no predefined limit */
+  CipUint expected_packet_rate; /*< Attribute 9 - Resolution in Milliseconds */
+  CipUint cip_produced_connection_id; /*< Attribute 10 */
+  CipUint cip_consumed_connection_id; /*< Attribute 11 */
+  CipUsint watchdog_timeout_action; /*< Attribute 12 */
+  CipUint produced_connection_path_length; /*< Attribute 13 */
+  CipOctet *produced_connection_path; /*< Attribute 14 */
+  CipConnectionPathEpath produced_path;
+  CipUint consumed_connection_path_length; /*< Attribute 15 */
+  CipOctet *consumed_connection_path; /*< Attribute 16 */
+  CipConnectionPathEpath consumed_path;
+  CipUint production_inhibit_time; /*< Attribute 17 */
+  CipUsint connection_timeout_multiplier; /*< Attribute 18 */
+  /* Attribute 19 not supported as Connection Bind service not supported */
+
+  /* End of CIP attributes */
+  /* Start of needed non-object variables */
+  CipElectronicKey electronic_key; //TODO: Check if really needed
+
+  CipConnectionPathEpath configuration_path;
+
+  CipInstance *producing_instance;
+  CipInstance *consuming_instance;
+
+  CipUint requested_produced_connection_size;
+  CipUint requested_consumed_connection_size;
+
+  uint64_t transmission_trigger_timer;
+  uint64_t inactivity_watchdog_timer;
+  uint64_t production_inhibit_timer;
+
+  CipUint connection_serial_number;
+  CipUint originator_vendor_id;
+  CipUdint originator_serial_number;
+
+  CipUdint o_to_t_requested_packet_interval;
+  CipWord o_to_t_network_connection_parameters;
+
+  CipUdint t_to_o_requested_packet_interval;
+  CipWord t_to_o_network_connection_parameters;
+
+  CipUint sequence_count_producing; /**< sequence Count for Class 1 Producing
+                                         Connections */
+  CipUint sequence_count_consuming; /**< sequence Count for Class 1 Producing
+                                         Connections */
+
+  EipUint32 eip_level_sequence_count_producing; /**< the EIP level sequence Count
+                                                   for Class 0/1
+                                                   Producing Connections may have a
+                                                   different
+                                                   value than SequenceCountProducing */
+  EipUint32 eip_level_sequence_count_consuming; /**< the EIP level sequence Count
+                                                   for Class 0/1
+                                                   Producing Connections may have a
+                                                   different
+                                                   value than SequenceCountProducing */
+
+  CipInt correct_originator_to_target_size;
+  CipInt correct_target_to_originator_size;
+
+  /* Sockets for consuming and producing connection */
+  int socket[2];
+
+  struct sockaddr_in remote_address; /* socket address for produce */
+  struct sockaddr_in originator_address; /* the address of the originator that
+                                              established the connection. needed
+                                              for scanning if the right packet is
+                                              arriving */
+
+  /* pointers to connection handling functions */
+  CipConnectionStateHandler current_state_handler;
+
+  ConnectionCloseFunction connection_close_function;
+  ConnectionTimeoutFunction connection_timeout_function;
+  ConnectionSendDataFunction connection_send_data_function;
+  ConnectionReceiveDataFunction connection_receive_data_function;
+};
+
+DoublyLinkedListNode *CipConnectionObjectListArrayAllocator(
+  );
+void CipConnectionObjectListArrayFree(DoublyLinkedListNode **node);
+
+/** @brief Array allocator
+ *
+ */
+CipConnectionObject *CipConnectionObjectCreate(const CipOctet *message);
+
+/** @brief Array deallocator
+ *
+ */
+void CipConnectionObjectDelete(CipConnectionObject **connection_object);
+
+void ConnectionObjectInitializeEmpty(
+  CipConnectionObject *const connection_object);
+
+void ConnectionObjectInitializeFromMessage(
+  const CipOctet **message,
+  CipConnectionObject *const
+  connection_object);
+
+ConnectionObjectState ConnectionObjectGetState(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetState(CipConnectionObject *const connection_object,
+                              const ConnectionObjectState state);
+
+ConnectionObjectInstanceType ConnectionObjectGetInstanceType(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetInstanceType(
+  CipConnectionObject *const connection_object,
+  const ConnectionObjectInstanceType instance_type);
+
+CipUsint ConnectionObjectGetInstanceTypeForAttribute(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectTransportClassTriggerDirection
+ConnectionObjectGetTransportClassTriggerDirection(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectTransportClassTriggerProductionTrigger
+ConnectionObjectGetTransportClassTriggerProductionTrigger(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectTransportClassTriggerTransportClass
+ConnectionObjectGetTransportClassTriggerTransportClass(
+  const CipConnectionObject *const connection_object);
+
+CipUint ConnectionObjectGetProducedConnectionSize(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetProducedConnectionSize(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  produced_connection_size);
+
+CipUint ConnectionObjectGetConsumedConnectionSize(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetConsumedConnectionSize(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  consumed_connection_size);
+
+CipUint ConnectionObjectGetExpectedPacketRate(
+  const CipConnectionObject *const connection_object);
+
+CipUint ConnectionObjectGetRequestedPacketInterval(
+  const CipConnectionObject *const connection_object);
+
+/**
+ * @brief Sets the expected packet rate according to the rules of the CIP specification
+ *
+ * As this function sets the expected packet rate according to the rules of the CIP specification, it is not always
+ * the exact value entered, but rounded up to the next serviceable increment, relative to the timer resolution
+ */
+void ConnectionObjectSetExpectedPacketRate(
+  CipConnectionObject *const connection_object);
+
+CipUdint ConnectionObjectGetCipProducedConnectionID(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetCipProducedConnectionID(
+  CipConnectionObject *const connection_object,
+  const CipUdint
+  cip_produced_connection_id);
+
+CipUdint ConnectionObjectGetCipConsumedConnectionID(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetCipConsumedConnectionID(
+  CipConnectionObject *const connection_object,
+  const CipUdint
+  cip_consumed_connection_id);
+
+ConnectionObjectWatchdogTimeoutAction ConnectionObjectGetWatchdogTimeoutAction(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetWatchdogTimeoutAction(
+  CipConnectionObject *const connection_object,
+  const CipUsint
+  watchdog_timeout_action);
+
+CipUint ConnectionObjectGetProducedConnectionPathLength(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetProducedConnectionPathLength(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  produced_connection_path_length);
+
+CipUint ConnectionObjectGetConsumedConnectionPathLength(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetConsumedConnectionPathLength(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  consumed_connection_path_length);
+
+CipUint ConnectionObjectGetProductionInhibitTime(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetProductionInhibitTime(
+  CipConnectionObject *const connection_object,
+  const CipUint
+  production_inhibit_time);
+
+CipUsint ConnectionObjectGetConnectionTimeoutMultiplier(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetConnectionTimeoutMultiplier(
+  CipConnectionObject *const connection_object,
+  const CipUsint
+  connection_timeout_multiplier);
+
+void ConnectionObjectResetInactivityWatchdogTimerValue(
+  CipConnectionObject *connection_object);
+
+CipUint ConnectionObjectGetConnectionSerialNumber(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetConnectionSerialNumber(
+  CipConnectionObject *connection_object,
+  const CipUint connection_serial_number);
+
+CipUint ConnectionObjectGetOriginatorVendorId(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetOriginatorVendorId(
+  CipConnectionObject *connection_object,
+  const CipUint vendor_id);
+
+CipUdint ConnectionObjectGetOriginatorSerialNumber(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetOriginatorSerialNumber(
+  CipConnectionObject *connection_object,
+  CipUdint originator_serial_number);
+
+CipUdint ConnectionObjectGetOToTRequestedPacketInterval(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetOToTRequestedPacketInterval(
+  CipConnectionObject *connection_object,
+  const CipUdint requested_packet_interval);
+
+bool ConnectionObjectIsOToTRedundantOwner(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectConnectionType ConnectionObjectGetOToTConnectionType(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectPriority ConnectionObjectGetOToTPriority(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectConnectionSizeType ConnectionObjectGetOToTConnectionSizeType(
+  const CipConnectionObject *const connection_object);
+
+size_t ConnectionObjectGetOToTConnectionSize(
+  const CipConnectionObject *const connection_object);
+
+/* T to O */
+CipUdint ConnectionObjectGetTToORequestedPacketInterval(
+  const CipConnectionObject *const connection_object);
+
+void ConnectionObjectSetTToORequestedPacketInterval(
+  CipConnectionObject *connection_object,
+  const CipUdint requested_packet_interval);
+
+bool ConnectionObjectIsTToORedundantOwner(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectConnectionType ConnectionObjectGetTToOConnectionType(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectPriority ConnectionObjectGetTToOPriority(
+  const CipConnectionObject *const connection_object);
+
+ConnectionObjectConnectionSizeType ConnectionObjectGetTToOConnectionSizeType(
+  const CipConnectionObject *const connection_object);
+
+size_t ConnectionObjectGetTToOConnectionSize(
+  const CipConnectionObject *const connection_object);
+
+/** @brief Copy the given connection data from source to destination
+ *
+ * @param destination Destination of the copy operation
+ * @param source Source of the copy operation
+ */
+void ConnectionObjectDeepCopy(CipConnectionObject *RESTRICT destination,
+                              const CipConnectionObject *RESTRICT const source);
+
+void ConnectionObjectResetProductionInhibitTimer(
+  CipConnectionObject *const connection_object);
+
+/** @brief Generate the ConnectionIDs and set the general configuration
+ * parameter in the given connection object.
+ *
+ * @param connection_object pointer to the connection object that should be set
+ * up.
+ */
+void ConnectionObjectGeneralConfiguration(
+  CipConnectionObject *const connection_object);
+
+bool ConnectionObjectIsTypeIOConnection(
+  const CipConnectionObject *const connection_object);
+
+bool EqualConnectionTriad(const CipConnectionObject *const object1,
+                          const CipConnectionObject *const object2);
+
+#endif /* SRC_CIP_CIPCONNECTIONOBJECT_H_ */

+ 33 - 14
source/src/cip/cipelectronickey.c

@@ -8,6 +8,25 @@
 
 #include "cipelectronickey.h"
 
+void ElectronicKeySetKeyFormat(CipElectronicKey *const electronic_key,
+                               const CipUsint key_format) {
+  electronic_key->key_format = key_format;
+}
+
+CipUint ElectronicKeyGetKeyFormat(const CipElectronicKey *const electronic_key)
+{
+  return electronic_key->key_format;
+}
+
+void ElectronicKeySetKeyData(CipElectronicKey *const electronic_key,
+                             void *key_data) {
+  electronic_key->key_data = key_data;
+}
+
+void *ElectronicKeyGetKeyData(const CipElectronicKey *const electronic_key) {
+  return electronic_key->key_data;
+}
+
 typedef struct electronic_key_format_4 {
   CipUint vendor_id;
   CipUint device_type;
@@ -27,9 +46,8 @@ void ElectronicKeyFormat4Delete(ElectronicKeyFormat4 **electronic_key) {
   *electronic_key = NULL;
 }
 
-void ElectronicKeyFormat4SetVendorId(const CipUint vendor_id,
-                                     ElectronicKeyFormat4 *const electronic_key)
-{
+void ElectronicKeyFormat4SetVendorId(ElectronicKeyFormat4 *const electronic_key,
+                                     const CipUint vendor_id) {
   electronic_key->vendor_id = vendor_id;
 }
 
@@ -38,9 +56,9 @@ CipUint ElectronicKeyFormat4GetVendorId(
   return electronic_key->vendor_id;
 }
 
-void ElectronicKeyFormat4SetDeviceType(const CipUint device_type,
-                                       ElectronicKeyFormat4 *const electronic_key)
-{
+void ElectronicKeyFormat4SetDeviceType(
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipUint device_type) {
   electronic_key->device_type = device_type;
 }
 
@@ -49,9 +67,9 @@ CipUint ElectronicKeyFormat4GetDeviceType(
   return electronic_key->device_type;
 }
 
-void ElectronicKeyFormat4SetProductCode(const CipUint product_code,
-                                        ElectronicKeyFormat4 *const electronic_key)
-{
+void ElectronicKeyFormat4SetProductCode(
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipUint product_code) {
   electronic_key->product_code = product_code;
 }
 
@@ -61,8 +79,8 @@ CipUint ElectronicKeyFormat4GetProductCode(
 }
 
 void ElectronicKeyFormat4SetMajorRevisionCompatibility(
-  const CipByte major_revision_compatibility,
-  ElectronicKeyFormat4 *const electronic_key) {
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipByte major_revision_compatibility) {
   electronic_key->major_revision_compatibility = major_revision_compatibility;
 }
 
@@ -82,11 +100,12 @@ bool ElectronicKeyFormat4GetMajorRevisionCompatibility(
   return false;
 }
 
-void ElectronicKeyFormat4SetMinorRevision(const CipUsint minor_revision,
-                                          ElectronicKeyFormat4 *const electronic_key)
-{
+void ElectronicKeyFormat4SetMinorRevision(
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipUsint minor_revision) {
   electronic_key->minor_revision = minor_revision;
 }
+
 CipUsint ElectronicKeyFormat4GetMinorRevision(
   const ElectronicKeyFormat4 *const electronic_key) {
   return electronic_key->minor_revision;

+ 38 - 11
source/src/cip/cipelectronickey.h

@@ -11,6 +11,32 @@
 
 #include "typedefs.h"
 
+/** @brief CIP Electronic Key Segment struct
+ *
+ */
+typedef struct {
+  CipUsint key_format; /**< Key Format 0-3 reserved, 4 = see Key Format Table,
+                          5-255 = Reserved */
+  void *key_data; /**< Depends on key format used, usually Key Format 4 as
+                          specified in CIP Specification, Volume 1*/
+} CipElectronicKey;
+
+void ElectronicKeySetSegmentType(CipElectronicKey *const electronic_key,
+                                 const CipUsint segment_type);
+
+CipUsint ElectronicKeyGetSegmentType(
+  const CipElectronicKey *const electronic_key);
+
+void ElectronicKeySetKeyFormat(CipElectronicKey *const electronic_key,
+                               const CipUsint key_format);
+
+CipUint ElectronicKeyGetKeyFormat(const CipElectronicKey *const electronic_key);
+
+void ElectronicKeySetKeyData(CipElectronicKey *const electronic_key,
+                             void *key_data);
+
+void *ElectronicKeyGetKeyData(const CipElectronicKey *const electronic_key);
+
 /** @brief Declaration of the electronic key format 4 data struct for the class
  *
  */
@@ -22,7 +48,8 @@ extern const size_t kElectronicKeyFormat4Size;
  *
  *	@return A new unset electronic key
  */
-ElectronicKeyFormat4 *ElectronicKeyFormat4New();
+ElectronicKeyFormat4 *ElectronicKeyFormat4New(
+  );
 
 /** @brief Destructor for the electroic key format 4 class
  *
@@ -36,8 +63,8 @@ void ElectronicKeyFormat4Delete(ElectronicKeyFormat4 **electronic_key);
  *	@param vendor_id The vendor ID to be set into the electronic key
  *	@param electronic_key The electronic key to be set - will be modified
  */
-void ElectronicKeyFormat4SetVendorId(const CipUint vendor_id,
-                                     ElectronicKeyFormat4 *const electronic_key);
+void ElectronicKeyFormat4SetVendorId(ElectronicKeyFormat4 *const electronic_key,
+                                     const CipUint vendor_id);
 
 /** @brief Gets the vendor ID form the electronic key
  *
@@ -53,8 +80,8 @@ CipUint ElectronicKeyFormat4GetVendorId(
  *	@param electronic_key A format 4 electronic key
  */
 void ElectronicKeyFormat4SetDeviceType(
-  const CipUint device_type,ElectronicKeyFormat4 *const
-  electronic_key);
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipUint device_type);
 
 /** @brief Gets the device type from a format 4 electronic key
  *
@@ -70,8 +97,8 @@ CipUint ElectronicKeyFormat4GetDeviceType(
  *      @param electronic_key The electronic key to be modified
  */
 void ElectronicKeyFormat4SetProductCode(
-  const CipUint product_code,ElectronicKeyFormat4 *const
-  electronic_key);
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipUint product_code);
 
 /** @brief Gets the product code from an format 4 electronic key
  *
@@ -87,8 +114,8 @@ CipUint ElectronicKeyFormat4GetProductCode(
  *      @param electronic_key The electronic key to be modified
  */
 void ElectronicKeyFormat4SetMajorRevisionCompatibility(
-  const CipByte major_revision_compatibility,
-  ElectronicKeyFormat4 *const electronic_key);
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipByte major_revision_compatibility);
 
 /** @brief Gets the major revision from an format 4 electronic key
  *
@@ -112,8 +139,8 @@ bool ElectronicKeyFormat4GetMajorRevisionCompatibility(
  *      @param electronic_key The electronic key to be modified
  */
 void ElectronicKeyFormat4SetMinorRevision(
-  const CipUsint minor_revision,ElectronicKeyFormat4 *const
-  electronic_key);
+  ElectronicKeyFormat4 *const electronic_key,
+  const CipUsint minor_revision);
 
 /** @brief Gets the minor revision from an format 4 electronic key
  *

+ 200 - 18
source/src/cip/cipepath.c

@@ -72,7 +72,7 @@ const unsigned int kPortSegmentExtendedPort = 15; /**< Reserved port segment por
 
 
 /*** Path Segment ***/
-SegmentType GetPathSegmentType(const unsigned char *const cip_path) {
+SegmentType GetPathSegmentType(const CipOctet *const cip_path) {
   const unsigned int kSegmentTypeMask = 0xE0;
   const unsigned int segment_type = *cip_path & kSegmentTypeMask;
   SegmentType result = kSegmentTypeReserved;
@@ -194,7 +194,8 @@ unsigned int GetPathPortSegmentExtendedPortNumber(
 }
 
 void SetPathPortSegmentExtendedPortIdentifier(
-  const unsigned int extended_port_identifier, unsigned char *const cip_path) {
+  const unsigned int extended_port_identifier,
+  CipOctet *const cip_path) {
   SetPathPortSegmentPortIdentifier(kPortSegmentExtendedPort, cip_path);
   const unsigned int kExtendedPortSegmentPosition =
     GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 2 : 1;
@@ -246,6 +247,41 @@ LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
   return result;
 }
 
+void SetPathLogicalSegmentLogicalType(LogicalSegmentLogicalType logical_type,
+                                      CipOctet *const cip_path) {
+  OPENER_ASSERT( kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
+  switch (logical_type) {
+    case kLogicalSegmentLogicalTypeClassId:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_CLASS_ID;
+      break;
+    case kLogicalSegmentLogicalTypeInstanceId:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_INSTANCE_ID;
+      break;
+    case kLogicalSegmentLogicalTypeMemberId:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_MEMBER_ID;
+      break;
+    case kLogicalSegmentLogicalTypeConnectionPoint:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_CONNECTION_POINT;
+      break;
+    case kLogicalSegmentLogicalTypeAttributeId:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID;
+      break;
+    case kLogicalSegmentLogicalTypeSpecial:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_SPECIAL;
+      break;
+    case kLogicalSegmentLogicalTypeServiceId:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_SERVICE_ID;
+      break;
+    case kLogicalSegmentLogicalTypeExtendedLogical:
+      (*cip_path) |= LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL;
+      break;
+    default:
+      OPENER_ASSERT(
+        "Logical segment/logical type: It is not possible to reach this point!\n");
+      break;
+  }
+}
+
 LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
   const unsigned char *const cip_path) {
   OPENER_ASSERT( kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
@@ -270,6 +306,73 @@ LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
   return result;
 }
 
+void SetPathLogicalSegmentLogicalFormat(LogicalSegmentLogicalFormat format,
+                                        CipOctet *const cip_path) {
+  OPENER_ASSERT( kSegmentTypeLogicalSegment ==
+                 GetPathSegmentType( (const CipOctet *)cip_path ) );
+  switch (format) {
+    case kLogicalSegmentLogicalFormatEightBit:
+      (*cip_path) |= LOGICAL_SEGMENT_FORMAT_EIGHT_BIT;
+      break;
+    case kLogicalSegmentLogicalFormatSixteenBit:
+      (*cip_path) |= LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT;
+      break;
+    case kLogicalSegmentLogicalFormatThirtyTwoBit:
+      (*cip_path) |= LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT;
+      break;
+    default:
+      OPENER_ASSERT(
+        "Logical segment/logical type: Invalid logical type detected!\n");
+      break;
+  }
+}
+
+const CipDword CipEpathGetLogicalValue(const EipUint8 **message) {
+  LogicalSegmentLogicalFormat logical_format =
+    GetPathLogicalSegmentLogicalFormat(*message);
+  CipDword data = 0;
+  MoveMessageNOctets(1, message); /* Move to logical value */
+  switch (logical_format) {
+    case kLogicalSegmentLogicalFormatEightBit:
+      data = GetSintFromMessage(message);
+      break;
+    case kLogicalSegmentLogicalFormatSixteenBit:
+      MoveMessageNOctets(1, message); /* Pad byte needs to be skipped */
+      data = GetIntFromMessage(message);
+      break;
+    case kLogicalSegmentLogicalFormatThirtyTwoBit:
+      MoveMessageNOctets(1, message); /* Pad byte needs to be skipped */
+      data = GetDintFromMessage(message);
+      break;
+    default:
+      OPENER_ASSERT(false); //shall not happen!
+  }
+  return data;
+}
+
+size_t CipEpathSetLogicalValue(const CipDword logical_value,
+                               const LogicalSegmentLogicalFormat logical_format,
+                               CipOctet **message) {
+  switch(logical_value) {
+    case kLogicalSegmentLogicalFormatEightBit: AddSintToMessage(logical_value,
+                                                                message);
+      return 1; break;
+    case kLogicalSegmentLogicalFormatSixteenBit: MoveMessageNOctets(1,
+                                                                    (const
+                                                                     CipOctet **)message);
+      AddIntToMessage(logical_value, message);
+      return 3; break;
+    case kLogicalSegmentLogicalFormatThirtyTwoBit: MoveMessageNOctets(1,
+                                                                      (const
+                                                                       CipOctet
+                                                                       **)message);
+      AddDintToMessage(logical_value, message);
+      return 5; break;
+  }
+  OPENER_ASSERT(false); /* This should never happen! */
+  return 0;
+}
+
 LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(
   const unsigned char *const cip_path) {
 //  OPENER_ASSERT(LOGICAL_SEGMENT_TYPE_EXTENDED_kLogicalSegmentLogicalTypeExtendedLogicalMessageValue == GetPathLogicalSegmentLogicalType(cip_path),
@@ -333,22 +436,19 @@ ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(
   return result;
 }
 
-void GetPathLogicalSegmentElectronicKeyFormat4(
-  const unsigned char *const cip_path, ElectronicKeyFormat4 *key) {
-//  OPENER_ASSERT(kElectronicKeySegmentFormatKeyFormat4 ==
-//      GetPathLogicalSegmentElectronicKeyFormat(cip_path), "Not electronic key format 4!\n");
+void GetElectronicKeyFormat4FromMessage(
+  const CipOctet **const message,
+  ElectronicKeyFormat4 *key) {
   OPENER_ASSERT( kElectronicKeySegmentFormatKeyFormat4 ==
-                 GetPathLogicalSegmentElectronicKeyFormat(cip_path) );
-
-  const EipUint8 *message_runner = (const EipUint8 *)(cip_path + 2);
-  ElectronicKeyFormat4SetVendorId(GetIntFromMessage(&message_runner), key);
-  ElectronicKeyFormat4SetDeviceType(GetIntFromMessage(&message_runner), key);
-  ElectronicKeyFormat4SetProductCode(GetIntFromMessage(&message_runner), key);
-  ElectronicKeyFormat4SetMajorRevisionCompatibility(GetSintFromMessage(&
-                                                                       message_runner),
-                                                    key);
-  ElectronicKeyFormat4SetMinorRevision(GetSintFromMessage(&message_runner),
-                                       key);
+                 GetPathLogicalSegmentElectronicKeyFormat(*message) );
+
+  MoveMessageNOctets(2, message);
+  ElectronicKeyFormat4SetVendorId(key, GetIntFromMessage(message) );
+  ElectronicKeyFormat4SetDeviceType(key, GetIntFromMessage(message) );
+  ElectronicKeyFormat4SetProductCode(key, GetIntFromMessage(message) );
+  ElectronicKeyFormat4SetMajorRevisionCompatibility(key,
+                                                    GetSintFromMessage(message) );
+  ElectronicKeyFormat4SetMinorRevision(key, GetSintFromMessage(message) );
 }
 
 /*** Logical Segment ***/
@@ -523,5 +623,87 @@ CipUsint GetPathDataSegmentSimpleDataWordLength(
   return GetSintFromMessage(&message_runner);
 }
 
-/*** Data Segment ***/
+/*** End Data Segment ***/
+
+/* Special purpose functions */
+
+LogicalSegmentLogicalFormat CipEpathGetNeededLogicalFormatForValue(
+  CipDword value) {
+  LogicalSegmentLogicalFormat logical_format =
+    kLogicalSegmentLogicalFormatEightBit;
+  if(0xFF < value) {
+    logical_format = kLogicalSegmentLogicalFormatSixteenBit;
+  }
+  if(0xFFFF < value) {
+    logical_format = kLogicalSegmentLogicalFormatThirtyTwoBit;
+  }
+  return logical_format;
+}
+
+size_t CipEpathEncodeConnectionEpath(
+  const CipConnectionPathEpath *const connection_epath,
+  CipOctet **encoded_path) {
+
+  size_t encoded_path_length = 0;
+  {
+    SetPathSegmentType(kSegmentTypeLogicalSegment, *encoded_path);
+    SetPathLogicalSegmentLogicalType(kLogicalSegmentLogicalTypeClassId,
+                                     *encoded_path);
+    LogicalSegmentLogicalFormat logical_value =
+      CipEpathGetNeededLogicalFormatForValue(connection_epath->class_id);
+    SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
+    encoded_path_length += 1;
+    MoveMessageNOctets(1, (const CipOctet **)encoded_path);
+    encoded_path_length += CipEpathSetLogicalValue(connection_epath->class_id,
+                                                   logical_value,
+                                                   encoded_path);
+  }
+
+  {
+    SetPathSegmentType(kSegmentTypeLogicalSegment, *encoded_path);
+    SetPathLogicalSegmentLogicalType(kLogicalSegmentLogicalTypeClassId,
+                                     *encoded_path);
+    LogicalSegmentLogicalFormat logical_value =
+      CipEpathGetNeededLogicalFormatForValue(connection_epath->instance_id);
+    SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
+    encoded_path_length += 1;
+    MoveMessageNOctets(1, (const CipOctet **)encoded_path);
+    encoded_path_length += CipEpathSetLogicalValue(
+      connection_epath->instance_id,
+      logical_value,
+      encoded_path);
+  }
+
+  if(0 != connection_epath->attribute_id_or_connection_point) {
+    SetPathSegmentType(kSegmentTypeLogicalSegment, *encoded_path);
+    SetPathLogicalSegmentLogicalType(kLogicalSegmentLogicalTypeClassId,
+                                     *encoded_path);
+    LogicalSegmentLogicalFormat logical_value =
+      CipEpathGetNeededLogicalFormatForValue(
+        connection_epath->attribute_id_or_connection_point);
+    SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
+    encoded_path_length += 1;
+    MoveMessageNOctets(1, (const CipOctet **)encoded_path);
+    encoded_path_length += CipEpathSetLogicalValue(
+      connection_epath->attribute_id_or_connection_point,
+      logical_value,
+      encoded_path);
+  }
+  return encoded_path_length += 1;
+}
+
+bool CipEpathEqual(const CipOctet *const path1,
+                   const CipUint path1_length,
+                   const CipOctet *const path2,
+                   const CipUint path2_length) {
+  if(path1_length != path2_length) {
+    return false;
+  }
+  for(size_t i = 0; i < path1_length; ++i) {
+    if(path1[i] != path2[i]) {
+      return false;
+    }
+  }
+  return true;
+}
 

+ 41 - 6
source/src/cip/cipepath.h

@@ -159,19 +159,28 @@ typedef enum symbolic_segment_extended_format {
   kSymbolicSegmentExtendedFormatReserved /**< Reserved */
 } SymbolicSegmentExtendedFormat;
 
+/* Start - Often used types of EPaths */
+typedef struct connection_path_epath {
+  CipDword class_id;
+  CipDword instance_id;
+  CipDword attribute_id_or_connection_point;
+} CipConnectionPathEpath;
+/* End - Often used types of EPaths */
+
 /** @brief Gets the basic segment type of a CIP EPath
  *
  * @param cip_path The start of the EPath message
  * @return The basic segment type
  */
-SegmentType GetPathSegmentType(const unsigned char *const cip_path);
+SegmentType GetPathSegmentType(const CipOctet *const cip_path);
 
 /** @brief Sets the basic segment type of an CIP EPath to be sent
  *
  * @param segment_type The segment type
  * @param cip_path A message buffer - Will be written on!
  */
-void SetPathSegmentType(SegmentType segment_type,unsigned char *const cip_path);
+void SetPathSegmentType(SegmentType segment_type,
+                        unsigned char *const cip_path);
 
 /*********************************************************
 * Port Segment functions
@@ -223,7 +232,8 @@ unsigned int GetPathPortSegmentExtendedPortNumber(
  * @param cip_path The start for the EPatch message
  */
 void SetPathPortSegmentExtendedPortIdentifier(
-  const unsigned int extended_port_identifier, unsigned char *const cip_path);
+  const unsigned int extended_port_identifier,
+  CipOctet *const cip_path);
 
 /** @brief Gets the Logical Type of an EPath Logical Segment message
  *
@@ -233,6 +243,9 @@ void SetPathPortSegmentExtendedPortIdentifier(
 LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
   const unsigned char *const cip_path);
 
+void SetPathLogicalSegmentLogicalType(LogicalSegmentLogicalType logical_type,
+                                      CipOctet *const cip_path);
+
 /** @brief Gets the Logical Format of a Logical Segment EPath message
  *
  * @param cip_path The start of the EPath message
@@ -241,6 +254,15 @@ LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
 LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
   const unsigned char *const cip_path);
 
+void SetPathLogicalSegmentLogicalFormat(LogicalSegmentLogicalFormat format,
+                                        CipOctet *const cip_path);
+
+const CipDword CipEpathGetLogicalValue(const EipUint8 **message);
+
+size_t CipEpathSetLogicalValue(const CipDword logical_value,
+                               const LogicalSegmentLogicalFormat logical_format,
+                               CipOctet **message);
+
 /** @brief  Gets the Extended Logical Type of a Logical Segment EPath message
  *
  * @param cip_path The start of the EPath message
@@ -255,7 +277,8 @@ LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(
  * @return The Special Type Logical Format subtype of a Logical Segment EPath message
  */
 LogicalSegmentSpecialTypeLogicalFormat
-GetPathLogicalSegmentSpecialTypeLogicalType(const unsigned char *const cip_path);
+GetPathLogicalSegmentSpecialTypeLogicalType(
+  const unsigned char *const cip_path);
 
 /** @brief Gets the Electronic Key format of a Logical Segment Special Type EPath message
  *
@@ -270,8 +293,9 @@ ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(
  * @param cip_path The start of the EPath message
  * @param Writes the data on the user provided data electronic key struct
  */
-void GetPathLogicalSegmentElectronicKeyFormat4(
-  const unsigned char *const cip_path, ElectronicKeyFormat4 *key);
+void GetElectronicKeyFormat4FromMessage(
+  const CipOctet **const cip_path,
+  ElectronicKeyFormat4 *key);
 
 /** @brief Gets the Network Segment Subtype of a EPatch Network Segement EPath message
  *
@@ -337,4 +361,15 @@ SymbolicSegmentExtendedFormat GetPathSymbolicSegmentNumericType(
 SymbolicSegmentExtendedFormat GetPathSymbolicSegmentExtendedFormat(
   const unsigned char *const cip_path);
 
+/* Special purpose encoding and decoding functions */
+
+size_t CipEpathEncodeConnectionEpath(
+  const CipConnectionPathEpath *const connection_epath,
+  CipOctet **encoded_path);
+
+bool CipEpathEqual(const CipOctet *const path1,
+                   const CipUint path1_length,
+                   const CipOctet *const path2,
+                   const CipUint path2_length);
+
 #endif /* SRC_CIP_CIPEPATH_H_ */

+ 4 - 20
source/src/cip/cipethernetlink.c

@@ -14,13 +14,6 @@
 #include "opener_api.h"
 #include "trace.h"
 
-/** @brief Data of an CIP Ethernet Link object */
-typedef struct {
-  EipUint32 interface_speed; /**< 10/100/1000 Mbit/sec */
-  EipUint32 interface_flags; /**< Inferface flags as defined in the CIP specification */
-  EipUint8 physical_address[6]; /**< MAC address of the Ethernet link */
-} CipEthernetLinkObject;
-
 typedef struct {
   CipWord control_bits;
   CipUint forced_interface_speed;
@@ -41,9 +34,6 @@ typedef struct {
   struct speed_duplex_options speed_duplex_options;
 } CipEthernetLinkInterfaceCapability;
 
-/* global private variables */
-CipEthernetLinkObject g_ethernet_link;
-
 EipStatus GetAttributeSingleEthernetLink(
   CipInstance *RESTRICT const instance,
   CipMessageRouterRequest *const message_router_request,
@@ -54,11 +44,6 @@ EipStatus GetAttributeSingleEthernetLink(
  *
  *  @param mac_address The MAC address of the Ethernet Link
  */
-void ConfigureMacAddress(const EipUint8 *const mac_address) {
-  memcpy( &g_ethernet_link.physical_address, mac_address,
-          sizeof(g_ethernet_link.physical_address) );
-
-}
 
 CipUsint dummy_attribute_usint = 0;
 CipUdint dummy_attribute_udint = 0;
@@ -69,13 +54,13 @@ CipEthernetLinkInterfaceControl interface_control = { .control_bits = 0,
                                                         0 };
 
 CipEthernetLinkSpeedDuplexArrayEntry speed_duplex_object = { .interface_speed =
-                                                               100,
-                                                             .
+                                                               100, .
                                                              interface_duplex_mode
                                                                = 1 };
 CipEthernetLinkInterfaceCapability interface_capability = {
   .capability_bits = 1, .speed_duplex_options = { .speed_duplex_array_count =
-                                                    1, .speed_duplex_array =
+                                                    1,
+                                                  .speed_duplex_array =
                                                     &speed_duplex_object }
 };
 
@@ -210,8 +195,7 @@ EipStatus GetAttributeSingleEthernetLink(
     uint8_t get_bit_mask = 0;
     if (kGetAttributeAll == message_router_request->service) {
       get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                              attribute_number)
-                      ]);
+                                                              attribute_number)]);
       message_router_response->general_status = kCipErrorSuccess;
     } else {
       get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(

+ 11 - 0
source/src/cip/cipethernetlink.h

@@ -32,4 +32,15 @@ EipStatus GetAttributeSingleEthernetLink(
   CipMessageRouterResponse *const message_router_response,
   struct sockaddr *originator_address);
 
+/** @brief Data of an CIP Ethernet Link object */
+typedef struct {
+  EipUint32 interface_speed; /**< 10/100/1000 Mbit/sec */
+  EipUint32 interface_flags; /**< Inferface flags as defined in the CIP specification */
+  EipUint8 physical_address[6]; /**< MAC address of the Ethernet link */
+} CipEthernetLinkObject;
+
+/* global private variables */
+
+CipEthernetLinkObject g_ethernet_link;
+
 #endif /* OPENER_CIPETHERNETLINK_H_*/

+ 5 - 5
source/src/cip/cipidentity.c

@@ -125,21 +125,21 @@ void InitializeCipIdentiy(CipClass *class) {
 
   InsertAttribute( (CipInstance *) class, 1, kCipUint,
                    (void *) &class->revision,
-				   kGetableSingleAndAll ); /* revision */
+                   kGetableSingleAndAll );                 /* revision */
   InsertAttribute( (CipInstance *) class, 2, kCipUint,
                    (void *) &class->number_of_instances, kGetableSingleAndAll ); /*  largest instance number */
   InsertAttribute( (CipInstance *) class, 3, kCipUint,
                    (void *) &class->number_of_instances, kGetAttributeSingle ); /* number of instances currently existing*/
   InsertAttribute( (CipInstance *) class, 4, kCipUint, (void *) &kCipUintZero,
-		  kNotSetOrGetable ); /* optional attribute list - default = 0 */
+                   kNotSetOrGetable ); /* optional attribute list - default = 0 */
   InsertAttribute( (CipInstance *) class, 5, kCipUint, (void *) &kCipUintZero,
-		  kNotSetOrGetable ); /* optional service list - default = 0 */
+                   kNotSetOrGetable ); /* optional service list - default = 0 */
   InsertAttribute( (CipInstance *) class, 6, kCipUint,
                    (void *) &meta_class->highest_attribute_number,
-				   kGetableSingleAndAll ); /* max class attribute number*/
+                   kGetableSingleAndAll );                 /* max class attribute number*/
   InsertAttribute( (CipInstance *) class, 7, kCipUint,
                    (void *) &class->highest_attribute_number,
-				   kGetableSingleAndAll ); /* max instance attribute number*/
+                   kGetableSingleAndAll );                 /* max instance attribute number*/
 
 }
 

+ 170 - 206
source/src/cip/cipioconnection.c

@@ -19,30 +19,6 @@
 #include "trace.h"
 #include "endianconv.h"
 
-typedef enum {
-  kCipConnectionObjectTransportClassTriggerClassInvalid = -1,
-  kCipConnectionObjectTransportClassTriggerClass0 = 0,
-  kCipConnectionObjectTransportClassTriggerClass1 = 1,
-  kCipConnectionObjectTransportClassTriggerClass2 = 2,
-  kCipConnectionObjectTransportClassTriggerClass3 = 3,
-  kCipConnectionObjectTransportClassTriggerClass4 = 4,
-  kCipConnectionObjectTransportClassTriggerClass5 = 5,
-  kCipConnectionObjectTransportClassTriggerClass6 = 6
-} CipConnectionObjectTransportClassTriggerClass;
-
-
-const unsigned int kConnectionPointConsumer = 0; /**< Consumer connection point */
-const unsigned int kConnectionPointProducer = 1; /**< Producer connection point */
-const unsigned int kConnectionPointConfig = 2; /**< Config connection point */
-
-/** @brief The cardinality of a connection endpoint,
- *  either point to point or point to multipoint
- *
- */
-typedef enum {
-  PointToMultipoint = 1, /**< Connection is a point to multi-point connection */
-  PointToPoint = 2 /**< Connection is a point to point connection */
-} CommunicationEndpointCardinality;
 
 /*The port to be used per default for I/O messages on UDP.*/
 const int kOpenerEipIoUdpPort = 0x08AE;
@@ -51,30 +27,30 @@ const int kOpenerEipIoUdpPort = 0x08AE;
  * application connection types.
  */
 EipStatus OpenProducingMulticastConnection(
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   CipCommonPacketFormatData *common_packet_format_data);
 
 EipStatus OpenMulticastConnection(
   UdpCommuncationDirection direction,
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   CipCommonPacketFormatData *common_packet_format_data);
 
 EipStatus OpenConsumingPointToPointConnection(
-  ConnectionObject *const connection_object,
+  CipConnectionObject *const connection_object,
   CipCommonPacketFormatData *const common_packet_format_data);
 
 EipStatus OpenProducingPointToPointConnection(
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   CipCommonPacketFormatData *common_packet_format_data);
 
-EipUint16 HandleConfigData(ConnectionObject *connection_object);
+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(ConnectionObject *connection_object);
+void CloseIoConnection(CipConnectionObject *connection_object);
 
-void HandleIoConnectionTimeOut(ConnectionObject *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.
@@ -82,10 +58,10 @@ void HandleIoConnectionTimeOut(ConnectionObject *connection_object);
  *      @return status  EIP_OK .. success
  *                     EIP_ERROR .. error
  */
-EipStatus SendConnectedData(ConnectionObject *connection_object);
+EipStatus SendConnectedData(CipConnectionObject *connection_object);
 
 EipStatus HandleReceivedIoConnectionData(
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   const EipUint8 *data,
   EipUint16 data_length);
 
@@ -95,21 +71,24 @@ unsigned int g_config_data_length = 0; /**< length of g_config_data_buffer. Init
 
 EipUint32 g_run_idle_state; /**< buffer for holding the run idle information. */
 
-EipUint16 ProcessProductionInhibitTime(ConnectionObject *io_connection_object)
+EipUint16 ProcessProductionInhibitTime(CipConnectionObject *io_connection_object)
 {
-  if ( kProductionTriggerCyclic
-       == GetProductionTrigger(io_connection_object) ) {
-    if ( 256 == GetProductionInhibitTime(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 */
-      SetProductionInhibitTime(
-        GetTargetToOriginatorRequestedPackedInterval(io_connection_object)
-        / 4000,
-        io_connection_object);
+      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 ( GetProductionInhibitTime(io_connection_object)
-           > (GetTargetToOriginatorRequestedPackedInterval(io_connection_object)
+      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 */
@@ -119,24 +98,7 @@ EipUint16 ProcessProductionInhibitTime(ConnectionObject *io_connection_object)
   return kConnectionManagerExtendedStatusCodeSuccess;
 }
 
-CipConnectionObjectTransportClassTriggerClass GetConnectionObjectTransportClass(
-  const ConnectionObject *const connection_object) {
-  const unsigned int kTransportClassMask = 0x0F;
-
-  switch(connection_object->transport_type_class_trigger &
-         kTransportClassMask) {
-    case 0: return kCipConnectionObjectTransportClassTriggerClass0;
-    case 1: return kCipConnectionObjectTransportClassTriggerClass1;
-    case 2: return kCipConnectionObjectTransportClassTriggerClass2;
-    case 3: return kCipConnectionObjectTransportClassTriggerClass3;
-    case 4: return kCipConnectionObjectTransportClassTriggerClass4;
-    case 5: return kCipConnectionObjectTransportClassTriggerClass5;
-    case 6: return kCipConnectionObjectTransportClassTriggerClass6;
-  }
-  return kCipConnectionObjectTransportClassTriggerClassInvalid;
-}
-
-void SetIoConnectionCallbacks(ConnectionObject *const io_connection_object) {
+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;
@@ -145,8 +107,8 @@ void SetIoConnectionCallbacks(ConnectionObject *const io_connection_object) {
 }
 
 EipUint16 SetupIoConnectionOriginatorToTargetConnectionPoint(
-  ConnectionObject *const io_connection_object,
-  ConnectionObject *const RESTRICT connection_object
+  CipConnectionObject *const io_connection_object,
+  CipConnectionObject *const RESTRICT connection_object
   ) {
   CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
   CipInstance *instance = NULL;
@@ -154,28 +116,27 @@ EipUint16 SetupIoConnectionOriginatorToTargetConnectionPoint(
        != ( instance =
               GetCipInstance(
                 assembly_class,
-                io_connection_object->connection_path.connection_point[
-                  kConnectionPointConsumer]) ) ) {
+                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_connection_path.path_size = 6;
-    io_connection_object->consumed_connection_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_connection_path.attribute_number = 3;
-    int data_size = io_connection_object->consumed_connection_size;
+    /*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, 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 ( kCipConnectionObjectTransportClassTriggerClass1
-         == GetConnectionObjectTransportClass(io_connection_object) ) {
-      //if ((io_connection_object->transport_type_class_trigger & 0x0F) == 1) {
+    if ( kConnectionObjectTransportClassTriggerTransportClass1
+         == ConnectionObjectGetTransportClassTriggerTransportClass(
+           io_connection_object) ) {
       /* class 1 connection */
       data_size -= 2; /* remove 16-bit sequence count length */
       diff_size += 2;
@@ -199,53 +160,59 @@ EipUint16 SetupIoConnectionOriginatorToTargetConnectionPoint(
 }
 
 EipUint16 SetupIoConnectionTargetToOriginatorConnectionPoint(
-  ConnectionObject *const io_connection_object,
-  ConnectionObject *const RESTRICT connection_object
+  CipConnectionObject *const io_connection_object,
+  CipConnectionObject *const RESTRICT connection_object
   ) {
-  ConnectionObject *iterator = g_active_connection_list;
-  while (NULL != iterator) {
-    if(io_connection_object->connection_path.connection_point[
-         kConnectionPointProducer] ==
-       iterator->connection_path.connection_point[kConnectionPointProducer]) {
+  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( GetTargetToOriginatorRequestedPackedInterval(io_connection_object) !=
-          GetTargetToOriginatorRequestedPackedInterval(iterator) ) {
+      if( ConnectionObjectGetTToORequestedPacketInterval(io_connection_object)
+          !=
+          ConnectionObjectGetTToORequestedPacketInterval(iterator) ) {
         return kConnectionManagerExtendedStatusCodeErrorRpiValuesNotAcceptable;
       }
-      if( GetConnectionObjectTargetToOriginatorFixedOrVariableConnectionSize(
+      if( ConnectionObjectGetTToOConnectionSizeType(
             io_connection_object) !=
-          GetConnectionObjectTargetToOriginatorFixedOrVariableConnectionSize(
+          ConnectionObjectGetTToOConnectionSizeType(
             iterator) ) {
         return
           kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionFixVar;
       }
-      if ( GetConnectionObjectTToOPriority(io_connection_object) !=
-           GetConnectionObjectTToOPriority(iterator) ) {
+      if ( ConnectionObjectGetTToOPriority(io_connection_object) !=
+           ConnectionObjectGetTToOPriority(iterator) ) {
         return
           kConnectionManagerExtendedStatusCodeMismatchedTToONetworkConnectionPriority;
       }
 
-      if( GetConnectionObjectTransportClass(io_connection_object) !=
-          GetConnectionObjectTransportClass(iterator) ) {
+      if( ConnectionObjectGetTransportClassTriggerTransportClass(
+            io_connection_object) !=
+          ConnectionObjectGetTransportClassTriggerTransportClass(iterator) ) {
         return kConnectionManagerExtendedStatusCodeMismatchedTransportClass;
       }
 
 
-      if( GetProductionTrigger(io_connection_object) !=
-          GetProductionTrigger(iterator) ) {
+      if( ConnectionObjectGetTransportClassTriggerProductionTrigger(
+            io_connection_object) !=
+          ConnectionObjectGetTransportClassTriggerProductionTrigger(iterator) )
+      {
         return
           kConnectionManagerExtendedStatusCodeMismatchedTToOProductionTrigger;
       }
 
-      if( GetProductionInhibitTime(io_connection_object) !=
-          GetProductionInhibitTime(iterator) ) {
+      if( ConnectionObjectGetProductionInhibitTime(io_connection_object) !=
+          ConnectionObjectGetProductionInhibitTime(iterator) ) {
         return
           kConnectionManagerExtendedStatusCodeMismatchedTToOProductionInhibitTimeSegment;
       }
 
     }
 
-    iterator = iterator->next_connection_object;
+    node = node->next;
   }
 
   /*setup producer side*/
@@ -255,25 +222,20 @@ EipUint16 SetupIoConnectionTargetToOriginatorConnectionPoint(
        != ( instance =
               GetCipInstance(
                 assembly_class,
-                io_connection_object->connection_path.connection_point[
-                  kConnectionPointProducer]) ) ) {
+                io_connection_object->produced_path.instance_id) ) ) {
+
     io_connection_object->producing_instance = instance;
-    io_connection_object->produced_connection_path_length = 6;
-    io_connection_object->produced_connection_path.path_size = 6;
-    io_connection_object->produced_connection_path.class_id =
-      io_connection_object->connection_path.class_id;
-    io_connection_object->produced_connection_path.instance_number =
-      io_connection_object->connection_path.connection_point[
-        kConnectionPointProducer];
-    io_connection_object->produced_connection_path.attribute_number = 3;
-    int data_size = io_connection_object->produced_connection_size;
+    int data_size = ConnectionObjectGetTToOConnectionSize(io_connection_object);
     int diff_size = 0;
     /* an assembly object should always have an attribute 3 */
-    CipAttributeStruct *attribute = GetCipAttribute(instance, 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 ( kCipConnectionObjectTransportClassTriggerClass1 ==
-         GetConnectionObjectTransportClass(io_connection_object) ) {
+    if ( kConnectionObjectTransportClassTriggerTransportClass1 ==
+         ConnectionObjectGetTransportClassTriggerTransportClass(
+           io_connection_object) ) {
       /* class 1 connection */
       data_size -= 2; /* remove 16-bit sequence count length */
       diff_size += 2;
@@ -308,12 +270,12 @@ EipUint16 SetupIoConnectionTargetToOriginatorConnectionPoint(
  *    - On an error the general status code to be put into the response
  */
 EipStatus EstablishIoConnection(
-  ConnectionObject *RESTRICT const connection_object,
+  CipConnectionObject *RESTRICT const connection_object,
   EipUint16 *const extended_error
   ) {
   EipStatus eip_status = kEipStatusOk;
 
-  ConnectionObject *io_connection_object = GetIoConnectionForConnectionData(
+  CipConnectionObject *io_connection_object = GetIoConnectionForConnectionData(
     connection_object,
     extended_error);
   if(NULL == io_connection_object) {
@@ -328,22 +290,18 @@ EipStatus EstablishIoConnection(
 
   SetIoConnectionCallbacks(io_connection_object);
 
-  GeneralConnectionConfiguration(io_connection_object);
+  ConnectionObjectGeneralConfiguration(io_connection_object);
 
-  ForwardOpenConnectionType originator_to_target_connection_type =
-    GetConnectionType(io_connection_object
-                      ->
-                      o_to_t_network_connection_parameter);
-  ForwardOpenConnectionType target_to_originator_connection_type =
-    GetConnectionType(io_connection_object
-                      ->
-                      t_to_o_network_connection_parameter);
+  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 ==
-                   kForwardOpenConnectionTypeNull &&
+                   kConnectionObjectConnectionTypeNull &&
                    target_to_originator_connection_type ==
-                   kForwardOpenConnectionTypeNull) );
+                   kConnectionObjectConnectionTypeNull) );
 
   io_connection_object->consuming_instance = NULL;
   io_connection_object->consumed_connection_path_length = 0;
@@ -353,7 +311,8 @@ EipStatus EstablishIoConnection(
 
   /* we don't need to check for zero as this is handled in the connection path parsing */
 
-  if (originator_to_target_connection_type != kForwardOpenConnectionTypeNull) { /*setup consumer side*/
+  if (originator_to_target_connection_type !=
+      kConnectionObjectConnectionTypeNull) {                                         /*setup consumer side*/
     *extended_error = SetupIoConnectionOriginatorToTargetConnectionPoint(
       io_connection_object,
       connection_object);
@@ -363,7 +322,8 @@ EipStatus EstablishIoConnection(
   }
 
 
-  if (target_to_originator_connection_type != kForwardOpenConnectionTypeNull) { /*setup producer side*/
+  if (target_to_originator_connection_type !=
+      kConnectionObjectConnectionTypeNull) {                                         /*setup producer side*/
     *extended_error = SetupIoConnectionTargetToOriginatorConnectionPoint(
       io_connection_object,
       connection_object);
@@ -388,8 +348,8 @@ EipStatus EstablishIoConnection(
 
   AddNewActiveConnection(io_connection_object);
   CheckIoConnectionEvent(
-    io_connection_object->connection_path.connection_point[0],
-    io_connection_object->connection_path.connection_point[1],
+    io_connection_object->consumed_path.instance_id,
+    io_connection_object->produced_path.instance_id,
     kIoConnectionEventOpened);
   return eip_status;
 }
@@ -401,10 +361,10 @@ EipStatus EstablishIoConnection(
  * @return kEipStatusOk on success, otherwise kEipStatusError
  */
 EipStatus OpenConsumingPointToPointConnection(
-  ConnectionObject *const connection_object,
+  CipConnectionObject *const connection_object,
   CipCommonPacketFormatData *const common_packet_format_data
   ) {
-  /*static EIP_UINT16 nUDPPort = 2222; TODO think on improving the udp port assigment for point to point connections */
+
   int j = 0;
 
   if (common_packet_format_data->address_info_item[0].type_id == 0) { /* it is not used yet */
@@ -414,10 +374,10 @@ EipStatus OpenConsumingPointToPointConnection(
   }
 
   struct sockaddr_in addr =
-  { .sin_family = PF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(
+  { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(
       kOpenerEipIoUdpPort) };
 
-  CipUsint qos_for_socket = GetConnectionObjectTToOPriority (connection_object);
+  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 */
@@ -446,7 +406,7 @@ EipStatus OpenConsumingPointToPointConnection(
 }
 
 EipStatus OpenProducingPointToPointConnection(
-  ConnectionObject *connection_object,
+  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 */
@@ -465,7 +425,7 @@ EipStatus OpenProducingPointToPointConnection(
   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 = GetConnectionObjectTToOPriority(connection_object);
+  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 */
@@ -481,12 +441,12 @@ EipStatus OpenProducingPointToPointConnection(
 }
 
 EipStatus OpenProducingMulticastConnection(
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   CipCommonPacketFormatData *common_packet_format_data
   ) {
-  ConnectionObject *existing_connection_object =
+  CipConnectionObject *existing_connection_object =
     GetExistingProducerMulticastConnection(
-      connection_object->connection_path.connection_point[1]);
+      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 */
@@ -512,7 +472,8 @@ EipStatus OpenProducingMulticastConnection(
 
   /* we have a connection reuse the data and the socket */
 
-  if (kConnectionTypeIoExclusiveOwner == connection_object->instance_type) {
+  if (kConnectionObjectInstanceTypeIOExclusiveOwner ==
+      connection_object->instance_type) {
     /* exclusive owners take the socket and further manage the connection
      * especially in the case of time outs.
      */
@@ -552,7 +513,7 @@ EipStatus OpenProducingMulticastConnection(
  */
 EipStatus OpenMulticastConnection(
   UdpCommuncationDirection direction,
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   CipCommonPacketFormatData *common_packet_format_data
   ) {
   int j = -1;
@@ -630,7 +591,7 @@ EipStatus OpenMulticastConnection(
   socket_address.sin_port = common_packet_format_data->address_info_item[j]
                             .sin_port;
 
-  CipUsint qos_for_socket = GetConnectionObjectTToOPriority(connection_object);
+  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");
@@ -651,22 +612,20 @@ EipStatus OpenMulticastConnection(
   return kEipStatusOk;
 }
 
-EipUint16 HandleConfigData(ConnectionObject *connection_object) {
+EipUint16 HandleConfigData(CipConnectionObject *connection_object) {
 
   CipClass *const assembly_class = GetCipClass(kCipAssemblyClassCode);
   EipUint16 connection_manager_status = 0;
   CipInstance *config_instance = GetCipInstance(
-    assembly_class, connection_object->connection_path.connection_point[2]);
+    assembly_class, connection_object->configuration_path.instance_id);
 
   if (0 != g_config_data_length) {
     if ( ConnectionWithSameConfigPointExists(
-           connection_object->connection_path.connection_point[
-             kConnectionPointConfig]) ) {                                               /* there is a connected connection with the same config point
-                                                                                         * we have to have the same data as already present in the config point*/
+           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*/
       CipByteArray *attribute_three = (CipByteArray *) GetCipAttribute(
         config_instance,
-        3)
-                                      ->data;
+        3)->data;
       if (attribute_three->length != g_config_data_length) {
         connection_manager_status =
           kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
@@ -698,30 +657,35 @@ EipUint16 HandleConfigData(ConnectionObject *connection_object) {
   return connection_manager_status;
 }
 
-void CloseIoConnection(ConnectionObject *connection_object) {
+void CloseIoConnection(CipConnectionObject *connection_object) {
 
-  CheckIoConnectionEvent(connection_object->connection_path.connection_point[
-                           kConnectionPointConsumer],
-                         connection_object->connection_path.connection_point[
-                           kConnectionPointProducer],
+  CheckIoConnectionEvent(connection_object->consumed_path.instance_id,
+                         connection_object->produced_path.instance_id,
                          kIoConnectionEventClosed);
 
-  if ( (kConnectionTypeIoExclusiveOwner == connection_object->instance_type)
-       || (kConnectionTypeIoInputOnly == connection_object->instance_type) ) {
-    if ( ( kForwardOpenConnectionTypeMulticastConnection
-           == (connection_object->t_to_o_network_connection_parameter
-               & kForwardOpenConnectionTypeMulticastConnection) )
+  if ( kConnectionObjectInstanceTypeIOExclusiveOwner ==
+       ConnectionObjectGetInstanceType(connection_object)
+       || kConnectionObjectInstanceTypeIOInputOnly ==
+       ConnectionObjectGetInstanceType(connection_object) ) {
+    if ( ( kConnectionObjectConnectionTypeMulticast
+           == ConnectionObjectGetTToOConnectionType(connection_object) )
          && (kEipInvalidSocket
              != connection_object->socket[kUdpCommuncationDirectionProducing]) )
     {
-      ConnectionObject *next_non_control_master_connection =
+      CipConnectionObject *next_non_control_master_connection =
         GetNextNonControlMasterConnection(
-          connection_object->connection_path.connection_point[
-            kConnectionPointProducer]);
+          connection_object->produced_path.instance_id);
       if (NULL != next_non_control_master_connection) {
+
+        /* Transfer socket ownership */
         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) );
@@ -730,15 +694,12 @@ void CloseIoConnection(ConnectionObject *connection_object) {
             connection_object->eip_level_sequence_count_producing;
         next_non_control_master_connection->sequence_count_producing =
           connection_object->sequence_count_producing;
-        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->connection_path.connection_point[
-            kConnectionPointProducer],
-          kConnectionTypeIoListenOnly);
+          connection_object->produced_path.instance_id,
+          kConnectionObjectInstanceTypeIOListenOnly);
       }
     }
   }
@@ -747,29 +708,28 @@ void CloseIoConnection(ConnectionObject *connection_object) {
     connection_object);
 }
 
-void HandleIoConnectionTimeOut(ConnectionObject *connection_object) {
-  CheckIoConnectionEvent(connection_object->connection_path.connection_point[0],
-                         connection_object->connection_path.connection_point[1],
+void HandleIoConnectionTimeOut(CipConnectionObject *connection_object) {
+  CheckIoConnectionEvent(connection_object->produced_path.instance_id,
+                         connection_object->consumed_path.instance_id,
                          kIoConnectionEventTimedOut);
 
-  if ( kForwardOpenConnectionTypeMulticastConnection
-       == (connection_object->t_to_o_network_connection_parameter
-           & kForwardOpenConnectionTypeMulticastConnection) ) {
-    switch (connection_object->instance_type) {
-      case kConnectionTypeIoExclusiveOwner:
+  if ( kConnectionObjectConnectionTypeMulticast
+       == ConnectionObjectGetTToOConnectionType(connection_object) ) {
+    switch (ConnectionObjectGetInstanceType(connection_object) ) {
+      case kConnectionObjectInstanceTypeIOExclusiveOwner:
         CloseAllConnectionsForInputWithSameType(
-          connection_object->connection_path.connection_point[1],
-          kConnectionTypeIoInputOnly);
+          connection_object->produced_path.instance_id,
+          kConnectionObjectInstanceTypeIOInputOnly);
         CloseAllConnectionsForInputWithSameType(
-          connection_object->connection_path.connection_point[1],
-          kConnectionTypeIoListenOnly);
+          connection_object->produced_path.instance_id,
+          kConnectionObjectInstanceTypeIOListenOnly);
         break;
-      case kConnectionTypeIoInputOnly:
+      case kConnectionObjectInstanceTypeIOInputOnly:
         if (kEipInvalidSocket
             != connection_object->socket[kUdpCommuncationDirectionProducing]) { /* we are the controlling input only connection find a new controller*/
-          ConnectionObject *next_non_control_master_connection =
+          CipConnectionObject *next_non_control_master_connection =
             GetNextNonControlMasterConnection(
-              connection_object->connection_path.connection_point[1]);
+              connection_object->produced_path.instance_id);
           if (NULL != next_non_control_master_connection) {
             next_non_control_master_connection->socket[
               kUdpCommuncationDirectionProducing] =
@@ -780,8 +740,8 @@ void HandleIoConnectionTimeOut(ConnectionObject *connection_object) {
               connection_object->transmission_trigger_timer;
           } else { /* this was the last master connection close all listen only connections listening on the port */
             CloseAllConnectionsForInputWithSameType(
-              connection_object->connection_path.connection_point[1],
-              kConnectionTypeIoListenOnly);
+              connection_object->produced_path.instance_id,
+              kConnectionObjectInstanceTypeIOListenOnly);
           }
         }
         break;
@@ -790,11 +750,12 @@ void HandleIoConnectionTimeOut(ConnectionObject *connection_object) {
     }
   }
 
-  OPENER_ASSERT(NULL != connection_object->connection_close_function);
-  connection_object->connection_close_function(connection_object);
+  ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
+//  OPENER_ASSERT(NULL != connection_object->connection_close_function);
+//  connection_object->connection_close_function(connection_object);
 }
 
-EipStatus SendConnectedData(ConnectionObject *connection_object) {
+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 */
 
@@ -805,7 +766,9 @@ EipStatus SendConnectedData(ConnectionObject *connection_object) {
 
   /* assembleCPFData */
   common_packet_format_data->item_count = 2;
-  if ( (connection_object->transport_type_class_trigger & 0x0F) != 0 ) { /* use Sequenced Address Items if not Connection Class 0 */
+  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;
@@ -847,7 +810,9 @@ EipStatus SendConnectedData(ConnectionObject *connection_object) {
     common_packet_format_data->data_item.length += 4;
   }
 
-  if ( (connection_object->transport_type_class_trigger & 0x0F) == 1 ) {
+  if (kConnectionObjectTransportClassTriggerTransportClass1 ==
+      ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
+  {
     common_packet_format_data->data_item.length += 2;
     AddIntToMessage(common_packet_format_data->data_item.length,
                     &message_data_reply_buffer);
@@ -868,19 +833,21 @@ EipStatus SendConnectedData(ConnectionObject *connection_object) {
   reply_length += common_packet_format_data->data_item.length;
 
   return SendUdpData(
-           &connection_object->remote_address,
-           connection_object->socket[kUdpCommuncationDirectionProducing],
-           &g_message_data_reply_buffer[0], reply_length);
+    &connection_object->remote_address,
+    connection_object->socket[kUdpCommuncationDirectionProducing],
+    &g_message_data_reply_buffer[0], reply_length);
 }
 
 EipStatus HandleReceivedIoConnectionData(
-  ConnectionObject *connection_object,
+  CipConnectionObject *connection_object,
   const EipUint8 *data,
   EipUint16 data_length
   ) {
 
   /* check class 1 sequence number*/
-  if ( (connection_object->transport_type_class_trigger & 0x0F) == 1 ) {
+  if (kConnectionObjectTransportClassTriggerTransportClass1 ==
+      ConnectionObjectGetTransportClassTriggerTransportClass(connection_object) )
+  {
     EipUint16 sequence_buffer = GetIntFromMessage( &(data) );
     if ( SEQ_LEQ16(sequence_buffer,
                    connection_object->sequence_count_consuming) ) {
@@ -910,26 +877,22 @@ EipStatus HandleReceivedIoConnectionData(
   return kEipStatusOk;
 }
 
-EipStatus OpenCommunicationChannels(ConnectionObject *connection_object) {
+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;
 
-  ForwardOpenConnectionType originator_to_target_connection_type =
-    GetConnectionType(connection_object
-                      ->
-                      o_to_t_network_connection_parameter);
+  ConnectionObjectConnectionType originator_to_target_connection_type =
+    ConnectionObjectGetOToTConnectionType(connection_object);
 
-  ForwardOpenConnectionType target_to_originator_connection_type =
-    GetConnectionType(connection_object
-                      ->
-                      t_to_o_network_connection_parameter);
+  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 ==
-      kForwardOpenConnectionTypeMulticastConnection)                                         /* Multicast consuming */
+      kConnectionObjectConnectionTypeMulticast)                                         /* Multicast consuming */
   {
     if (OpenMulticastConnection(kUdpCommuncationDirectionConsuming,
                                 connection_object, common_packet_format_data)
@@ -938,7 +901,7 @@ EipStatus OpenCommunicationChannels(ConnectionObject *connection_object) {
       return kCipErrorConnectionFailure;
     }
   } else if (originator_to_target_connection_type ==
-             kForwardOpenConnectionTypePointToPointConnection)                                         /* Point to Point consuming */
+             kConnectionObjectConnectionTypePointToPoint)                                  /* Point to Point consuming */
   {
     if (OpenConsumingPointToPointConnection(connection_object,
                                             common_packet_format_data)
@@ -949,7 +912,7 @@ EipStatus OpenCommunicationChannels(ConnectionObject *connection_object) {
   }
 
   if (target_to_originator_connection_type ==
-      kForwardOpenConnectionTypeMulticastConnection)                                         /* Multicast producing */
+      kConnectionObjectConnectionTypeMulticast)                                         /* Multicast producing */
   {
     if (OpenProducingMulticastConnection(connection_object,
                                          common_packet_format_data)
@@ -958,7 +921,7 @@ EipStatus OpenCommunicationChannels(ConnectionObject *connection_object) {
       return kCipErrorConnectionFailure;
     }
   } else if (target_to_originator_connection_type ==
-             kForwardOpenConnectionTypePointToPointConnection)                                         /* Point to Point producing */
+             kConnectionObjectConnectionTypePointToPoint)                                  /* Point to Point producing */
   {
 
     if (OpenProducingPointToPointConnection(connection_object,
@@ -972,7 +935,7 @@ EipStatus OpenCommunicationChannels(ConnectionObject *connection_object) {
 }
 
 void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
-  ConnectionObject *connection_object) {
+  CipConnectionObject *connection_object) {
   CloseUdpSocket(
     connection_object->socket[kUdpCommuncationDirectionConsuming]);
 
@@ -986,4 +949,5 @@ void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
     kEipInvalidSocket;
 
   RemoveFromActiveConnections(connection_object);
+  ConnectionObjectInitializeEmpty(connection_object);
 }

+ 4 - 3
source/src/cip/cipioconnection.h

@@ -42,6 +42,7 @@
 
 #include "opener_api.h"
 #include "cipconnectionmanager.h"
+#include "cipconnectionobject.h"
 
 /** @brief Setup all data in order to establish an IO connection
  *
@@ -53,7 +54,7 @@
  *    - On an error the general status code to be put into the response
  */
 EipStatus EstablishIoConnection(
-  ConnectionObject *RESTRICT const connection_object,
+  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
@@ -64,7 +65,7 @@ EipStatus EstablishIoConnection(
  *    - EIP_OK ... on success
  *    - On an error the general status code to be put into the response
  */
-EipStatus OpenCommunicationChannels(ConnectionObject *connection_object);
+EipStatus OpenCommunicationChannels(CipConnectionObject *connection_object);
 
 /** @brief close the communication channels of the given connection and remove it
  * from the active connections list.
@@ -72,7 +73,7 @@ EipStatus OpenCommunicationChannels(ConnectionObject *connection_object);
  * @param connection_object pointer to the connection object data
  */
 void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
-  ConnectionObject *connection_object);
+  CipConnectionObject *connection_object);
 
 extern EipUint8 *g_config_data_buffer;
 extern unsigned int g_config_data_length;

+ 23 - 21
source/src/cip/cipmessagerouter.c

@@ -51,26 +51,28 @@ CipError CreateMessageRouterRequestStructure(
 
 void InitializeCipMessageRouterClass(CipClass *cip_class) {
 
-	CipClass *meta_class = cip_class->class_instance.cip_class;
-
-    InsertAttribute( (CipInstance *) cip_class, 1, kCipUint,
-                     (void *) &cip_class->revision, kGetableSingleAndAll ); /* revision */
-    InsertAttribute( (CipInstance *) cip_class, 2, kCipUint,
-                     (void *) &cip_class->number_of_instances,
-                     kGetableSingle );                                     /*  largest instance number */
-    InsertAttribute( (CipInstance *) cip_class, 3, kCipUint,
-                     (void *) &cip_class->number_of_instances,
-					 kGetableSingle );                                     /* number of instances currently existing*/
-    InsertAttribute( (CipInstance *) cip_class, 4, kCipUint, (void *) &kCipUintZero,
-                     kGetableAll ); /* optional attribute list - default = 0 */
-    InsertAttribute( (CipInstance *) cip_class, 5, kCipUint, (void *) &kCipUintZero,
-    		kGetableAll ); /* optional service list - default = 0 */
-    InsertAttribute( (CipInstance *) cip_class, 6, kCipUint,
-                     (void *) &meta_class->highest_attribute_number,
-					 kGetableSingleAndAll ); /* max class attribute number*/
-    InsertAttribute( (CipInstance *) cip_class, 7, kCipUint,
-                     (void *) &cip_class->highest_attribute_number,
-					 kGetableSingleAndAll ); /* max instance attribute number*/
+  CipClass *meta_class = cip_class->class_instance.cip_class;
+
+  InsertAttribute( (CipInstance *) cip_class, 1, kCipUint,
+                   (void *) &cip_class->revision, kGetableSingleAndAll );   /* revision */
+  InsertAttribute( (CipInstance *) cip_class, 2, kCipUint,
+                   (void *) &cip_class->number_of_instances,
+                   kGetableSingle );                                       /*  largest instance number */
+  InsertAttribute( (CipInstance *) cip_class, 3, kCipUint,
+                   (void *) &cip_class->number_of_instances,
+                   kGetableSingle );                                                           /* number of instances currently existing*/
+  InsertAttribute( (CipInstance *) cip_class, 4, kCipUint,
+                   (void *) &kCipUintZero,
+                   kGetableAll );   /* optional attribute list - default = 0 */
+  InsertAttribute( (CipInstance *) cip_class, 5, kCipUint,
+                   (void *) &kCipUintZero,
+                   kGetableAll ); /* optional service list - default = 0 */
+  InsertAttribute( (CipInstance *) cip_class, 6, kCipUint,
+                   (void *) &meta_class->highest_attribute_number,
+                   kGetableSingleAndAll );                       /* max class attribute number*/
+  InsertAttribute( (CipInstance *) cip_class, 7, kCipUint,
+                   (void *) &cip_class->highest_attribute_number,
+                   kGetableSingleAndAll );                       /* max instance attribute number*/
 }
 
 EipStatus CipMessageRouterInit() {
@@ -85,7 +87,7 @@ EipStatus CipMessageRouterInit() {
                                             1, /* # of instances*/
                                             "message router", /* class name*/
                                             1, /* # class revision*/
-											InitializeCipMessageRouterClass); /* # function pointer for initialization*/
+                                            InitializeCipMessageRouterClass);                                             /* # function pointer for initialization*/
   if (NULL == message_router) {
     return kEipStatusError;
   }

+ 8 - 9
source/src/cip/cipqos.c

@@ -30,8 +30,7 @@ EipStatus GetAttributeSingleQoS(
   CipInstance *const RESTRICT instance,
   CipMessageRouterRequest *RESTRICT const message_router_request,
   CipMessageRouterResponse *RESTRICT const message_router_response,
-  struct sockaddr *originator_address)
-{
+  struct sockaddr *originator_address) {
 
   return GetAttributeSingle(instance, message_router_request,
                             message_router_response, originator_address);
@@ -41,8 +40,7 @@ EipStatus SetAttributeSingleQoS(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address)
-{
+  struct sockaddr *originator_address) {
 
   CipAttributeStruct *attribute = GetCipAttribute(
     instance, message_router_request->request_path.attribute_number);
@@ -69,6 +67,7 @@ EipStatus SetAttributeSingleQoS(
         message_router_response->general_status = kCipErrorSuccess;
       } else {
         message_router_response->general_status = kCipErrorNotEnoughData;
+        OPENER_TRACE_INFO("CIP QoS not enough data\n");
       }
     } else {
       message_router_response->general_status = kCipErrorInvalidAttributeValue;
@@ -86,21 +85,21 @@ EipStatus SetAttributeSingleQoS(
   return kEipStatusOkSend;
 }
 
-CipUsint GetPriorityForSocket(ForwardOpenPriority priority) {
+CipUsint GetPriorityForSocket(ConnectionObjectPriority priority) {
   switch (priority) {
-    case kForwardOpenPriorityLow: {
+    case kConnectionObjectPriorityLow: {
       return dscp_low;
       break;
     }
-    case kForwardOpenPriorityHigh: {
+    case kConnectionObjectPriorityHigh: {
       return dscp_high;
       break;
     }
-    case kForwardOpenPriorityScheduled: {
+    case kConnectionObjectPriorityScheduled: {
       return dscp_scheduled;
       break;
     }
-    case kForwardOpenPriorityUrgent: {
+    case kConnectionObjectPriorityUrgent: {
       return dscp_urgent;
       break;
     }

+ 1 - 1
source/src/cip/cipqos.h

@@ -21,7 +21,7 @@ static const EipUint16 kCipQoSClassCode = 0x48; /**< QoS Object class code */
 /* public functions */
 /** @brief Initializing the data structures of the TCP/IP interface object
  */
-CipUsint GetPriorityForSocket(ForwardOpenPriority priority);
+CipUsint GetPriorityForSocket(ConnectionObjectPriority priority);
 EipStatus CipQoSInit(void);
 
 #endif  /* OPENER_CIPQOS_H_*/

+ 8 - 67
source/src/cip/ciptcpipinterface.c

@@ -62,7 +62,6 @@ MulticastAddressConfiguration g_multicast_configuration = { 0, /* us the default
  */
 CipUint g_encapsulation_inactivity_timeout = 120;
 
-
 /************** Functions ****************************************/
 EipStatus GetAttributeSingleTcpIpInterface(
   CipInstance *instance,
@@ -76,60 +75,6 @@ EipStatus GetAttributeAllTcpIpInterface(
   CipMessageRouterResponse *message_router_response,
   struct sockaddr *originator_address);
 
-EipStatus ConfigureNetworkInterface(const char *ip_address,
-                                    const char *subnet_mask,
-                                    const char *gateway) {
-
-  interface_configuration_.ip_address = inet_addr(ip_address);
-  interface_configuration_.network_mask = inet_addr(subnet_mask);
-  interface_configuration_.gateway = inet_addr(gateway);
-
-  /* calculate the CIP multicast address. The multicast address is calculated, not input*/
-  EipUint32 host_id = ntohl(interface_configuration_.ip_address)
-                      & ~ntohl(interface_configuration_.network_mask); /* see CIP spec 3-5.3 for multicast address algorithm*/
-  host_id -= 1;
-  host_id &= 0x3ff;
-
-  g_multicast_configuration.starting_multicast_address = htonl(
-    ntohl( inet_addr("239.192.1.0") ) + (host_id << 5) );
-
-  return kEipStatusOk;
-}
-
-void ConfigureDomainName(const char *domain_name) {
-  if (NULL != interface_configuration_.domain_name.string) {
-    /* if the string is already set to a value we have to free the resources
-     * before we can set the new value in order to avoid memory leaks.
-     */
-    CipFree(interface_configuration_.domain_name.string);
-  }
-  interface_configuration_.domain_name.length = strlen(domain_name);
-  if (interface_configuration_.domain_name.length) {
-    interface_configuration_.domain_name.string = (EipByte *) CipCalloc(
-      interface_configuration_.domain_name.length + 1, sizeof(EipInt8) );
-    strcpy(interface_configuration_.domain_name.string, domain_name);
-  } else {
-    interface_configuration_.domain_name.string = NULL;
-  }
-}
-
-void ConfigureHostName(const char *const RESTRICT hostname) {
-  if (NULL != hostname_.string) {
-    /* if the string is already set to a value we have to free the resources
-     * before we can set the new value in order to avoid memory leaks.
-     */
-    CipFree(hostname_.string);
-  }
-  hostname_.length = strlen(hostname);
-  if (hostname_.length) {
-    hostname_.string = (EipByte *) CipCalloc( hostname_.length + 1,
-                                              sizeof(EipByte) );
-    strcpy(hostname_.string, hostname);
-  } else {
-    hostname_.string = NULL;
-  }
-}
-
 EipStatus SetAttributeSingleTcp(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
@@ -224,8 +169,7 @@ EipStatus CipTcpIpInterfaceInit() {
                                        13, /* # highest instance attribute number*/
                                        3, /* # instance services*/
                                        1, /* # instances*/
-                                       "TCP/IP interface",
-                                       4, /* # class revision*/
+                                       "TCP/IP interface", 4, /* # class revision*/
                                        NULL /* # function pointer for initialization*/
                                        ) ) == 0 ) {
     return kEipStatusError;
@@ -298,11 +242,10 @@ EipStatus GetAttributeSingleTcpIpInterface(
 
   message_router_response->general_status = kCipErrorAttributeNotSupported;
 
-  if (9 == message_router_request->request_path.attribute_number ) {   /* attribute 9 can not be easily handled with the default mechanism therefore we will do it by hand */
+  if (9 == message_router_request->request_path.attribute_number) { /* attribute 9 can not be easily handled with the default mechanism therefore we will do it by hand */
     if (kGetAttributeAll == message_router_request->service) {
       get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                              attribute_number)
-                      ]);
+                                                              attribute_number)]);
       message_router_response->general_status = kCipErrorSuccess;
     } else {
       get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
@@ -310,7 +253,7 @@ EipStatus GetAttributeSingleTcpIpInterface(
                       ]);
     }
 
-    if ( 0 == ( get_bit_mask & ( 1 << ( attribute_number  % 8 ) ) ) ) {
+    if ( 0 == ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
       return kEipStatusOkSend;
     }
     message_router_response->general_status = kCipErrorSuccess;
@@ -332,14 +275,12 @@ EipStatus GetAttributeSingleTcpIpInterface(
                                                        &multicast_address,
                                                        &message);
   } else {
-    CipAttributeStruct *attribute = GetCipAttribute(instance,
-                                                    attribute_number);
+    CipAttributeStruct *attribute = GetCipAttribute(instance, attribute_number);
 
     if ( (NULL != attribute) && ( NULL != attribute->data) ) {
 
-      OPENER_TRACE_INFO(
-        "getAttribute %d\n",
-        message_router_request->request_path.attribute_number);     /* create a reply message containing the data*/
+      OPENER_TRACE_INFO("getAttribute %d\n",
+                        message_router_request->request_path.attribute_number); /* create a reply message containing the data*/
 
       if (kGetAttributeAll == message_router_request->service) {
         get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
@@ -352,7 +293,7 @@ EipStatus GetAttributeSingleTcpIpInterface(
                         ]);
       }
 
-      if( 0 == ( get_bit_mask &  ( 1 << ( (attribute_number ) % 8 ) ) ) ) {
+      if ( 0 == ( get_bit_mask & ( 1 << ( (attribute_number) % 8 ) ) ) ) {
         return kEipStatusOkSend;
       }
 

+ 2 - 0
source/src/cip/ciptcpipinterface.h

@@ -14,6 +14,8 @@
 #include "typedefs.h"
 #include "ciptypes.h"
 
+extern CipString hostname_;
+
 extern CipTcpIpNetworkInterfaceConfiguration interface_configuration_;
 
 static const EipUint16 kCipTcpIpInterfaceClassCode = 0xF5; /**< TCP/IP Interface Object class code */

+ 2 - 30
source/src/cip/ciptypes.h

@@ -56,7 +56,6 @@ typedef enum cip_data_types {
                            figure out the right way to handle it */
 } CipDataType;
 
-
 /** @brief Definition of CIP service codes
  *
  * An Enum with all CIP service codes. Common services codes range from 0x01 to
@@ -172,17 +171,6 @@ typedef struct {
   EipUint8 *segment_data;
 } CipConnectionPath;
 
-/** @brief Struct representing the key data format of the electronic key segment
- *
- */
-typedef struct {
-  CipUint vendor_id; /**< Vendor ID */
-  CipUint device_type; /**< Device Type */
-  CipUint product_code; /**< Product Code */
-  CipByte major_revision; /**< Major Revision and Compatibility (Bit 0-6 = Major
-                             Revision) Bit 7 = Compatibility */
-  CipUsint minor_revision; /**< Minor Revision */
-} CipKeyData;
 
 /** @brief Struct storing the CIP revision */
 typedef struct {
@@ -190,17 +178,6 @@ typedef struct {
   EipUint8 minor_revision;
 } CipRevision;
 
-/** @brief CIP Electronic Key Segment struct
- *
- */
-typedef struct {
-  CipUsint segment_type; /**< Specifies the Segment Type */
-  CipUsint key_format; /**< Key Format 0-3 reserved, 4 = see Key Format Table,
-                          5-255 = Reserved */
-  CipKeyData key_data; /**< Depends on key format used, usually Key Format 4 as
-                          specified in CIP Specification, Volume 1*/
-} CipElectronicKey;
-
 /** @brief CIP Message Router Request
  *
  */
@@ -266,8 +243,8 @@ typedef struct cip_class {
                                          (attribute numbers are not necessarily
                                          consecutive)*/
   uint8_t *get_single_bit_mask; /**< Bitmask for GetAttributeSingle*/
-  uint8_t *set_bit_mask;        /**< Bitmask for SetAttributeSingle*/
-  uint8_t *get_all_bit_mask;    /**< Bitmask for GetAttributeAll*/
+  uint8_t *set_bit_mask; /**< Bitmask for SetAttributeSingle*/
+  uint8_t *get_all_bit_mask; /**< Bitmask for GetAttributeAll*/
 
   EipUint32 get_attribute_all_mask; /**< mask indicating which attributes are
                                        returned by getAttributeAll*/
@@ -340,16 +317,11 @@ typedef struct {
 //  EipUint32 interface_flags; /**< Inferface flags as defined in the CIP specification */
 //  EipUint8 physical_address[6]; /**< MAC address of the Ethernet link */
 //} CipEthernetLinkObject;
-
-
-
-
 typedef struct {
   CipUint num_conn_entries;
   CipBool *conn_open_bits;
 } CipConnectionManagerConnectionEntryList;
 
-
 /* these are used for creating the getAttributeAll masks
    TODO there might be a way simplifying this using __VARARGS__ in #define */
 #define MASK1(a) ( 1 << (a) )

+ 2 - 3
source/src/enet_encap/cpf.c

@@ -78,13 +78,12 @@ int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
     if (g_common_packet_format_data_item.address_item.type_id
         == kCipItemIdConnectionAddress) /* check if ConnectedAddressItem received, otherwise it is no connected message and should not be here*/
     {     /* ConnectedAddressItem item */
-      ConnectionObject *connection_object = GetConnectedObject(
+      CipConnectionObject *connection_object = GetConnectedObject(
         g_common_packet_format_data_item.address_item.data
         .connection_identifier);
       if (NULL != connection_object) {
         /* reset the watchdog timer */
-        connection_object->inactivity_watchdog_timer =
-          GetConnectionObjectInactivityWatchdogTimerValue(connection_object);
+        ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
 
         /*TODO check connection id  and sequence count    */
         if (g_common_packet_format_data_item.data_item.type_id

+ 11 - 8
source/src/enet_encap/encap.c

@@ -311,10 +311,10 @@ int HandleReceivedExplictUdpData(int socket,
 }
 
 int EncapsulateData(const EncapsulationData *const send_data) {
-  EipUint8 *communcation_buffer = send_data->communication_buffer_start + 2;
+  CipOctet *communcation_buffer = send_data->communication_buffer_start + 2;
   AddIntToMessage(send_data->data_length, &communcation_buffer);
   /*the CommBuf should already contain the correct session handle*/
-  MoveMessageNOctets(4, &communcation_buffer);
+  MoveMessageNOctets(4, (const CipOctet **)&communcation_buffer);
   AddDintToMessage(send_data->status, &communcation_buffer);
   /*the CommBuf should already contain the correct sender context*/
   /*the CommBuf should already contain the correct  options value*/
@@ -393,13 +393,13 @@ void HandleReceivedListIdentityCommandUdp(int socket,
 
 ptrdiff_t EncapsulateListIdentyResponseMessage(
   EipByte *const communication_buffer) {
-  EipUint8 *communication_buffer_runner = communication_buffer;
+  CipOctet *communication_buffer_runner = communication_buffer;
 
   AddIntToMessage( 1, &(communication_buffer_runner) ); /* Item count: one item */
   AddIntToMessage(kCipItemIdListIdentityResponse, &communication_buffer_runner);
 
   EipByte *id_length_buffer = communication_buffer_runner;
-  MoveMessageNOctets(2, &communication_buffer_runner); /*at this place the real length will be inserted below*/
+  MoveMessageNOctets(2, (const CipOctet **)&communication_buffer_runner); /*at this place the real length will be inserted below*/
 
   AddIntToMessage(kSupportedProtocolVersion, &communication_buffer_runner);
 
@@ -408,7 +408,7 @@ ptrdiff_t EncapsulateListIdentyResponseMessage(
                        &communication_buffer_runner);
 
   memset(communication_buffer_runner, 0, 8);
-  MoveMessageNOctets(8, &communication_buffer_runner);
+  MoveMessageNOctets(8, (const CipOctet **)&communication_buffer_runner);
 
   AddIntToMessage(vendor_id_, &communication_buffer_runner);
   AddIntToMessage(device_type_, &communication_buffer_runner);
@@ -432,7 +432,7 @@ ptrdiff_t EncapsulateListIdentyResponseMessage(
 void DetermineDelayTime(EipByte *buffer_start,
                         DelayedEncapsulationMessage *delayed_message_buffer) {
 
-  MoveMessageNOctets(12, &buffer_start); /* start of the sender context */
+  MoveMessageNOctets(12, (const CipOctet **)&buffer_start); /* start of the sender context */
   EipUint16 maximum_delay_time = GetIntFromMessage(
     (const EipUint8 **const)&buffer_start );
 
@@ -466,6 +466,9 @@ void HandleReceivedRegisterSessionCommand(int socket,
     for (int 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);
         receive_data->session_handle = i + 1; /*return the already assigned session back, the cip spec is not clear about this needs to be tested*/
         receive_data->status = kEncapsulationProtocolInvalidCommand;
         session_index = kSessionStatusInvalid;
@@ -510,8 +513,8 @@ void HandleReceivedRegisterSessionCommand(int socket,
  *   close all corresponding TCP connections and delete session handle.
  *      pa_S_ReceiveData pointer to unregister session request with corresponding socket handle.
  */
-EipStatus HandleReceivedUnregisterSessionCommand(
-  EncapsulationData *receive_data) {
+EipStatus HandleReceivedUnregisterSessionCommand(EncapsulationData *receive_data)
+{
 
   OPENER_TRACE_INFO("encap.c: Unregister Session Command\n");
 

+ 3 - 3
source/src/enet_encap/endianconv.c

@@ -28,7 +28,7 @@ OpenerEndianess g_opener_platform_endianess = kOpenerEndianessUnknown;
  */
 EipUint8 GetSintFromMessage(const EipUint8 **const buffer) {
   const unsigned char *const buffer_address = (unsigned char *) *buffer;
-  EipUint16 data = buffer_address[0];
+  EipUint8 data = buffer_address[0];
   *buffer += 1;
   return data;
 }
@@ -256,7 +256,7 @@ int GetEndianess() {
 }
 
 void MoveMessageNOctets(int amount_of_bytes_moved,
-                        CipOctet **message_runner) {
+                        const CipOctet **message_runner) {
   (*message_runner) += amount_of_bytes_moved;
 }
 
@@ -271,7 +271,7 @@ int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
                                                          unsigned int amount_of_filled_bytes,
                                                          CipOctet **message) {
   FillNextNMessageOctetsWith(value, amount_of_filled_bytes, message);
-  MoveMessageNOctets(amount_of_filled_bytes, message);
+  MoveMessageNOctets(amount_of_filled_bytes, (const CipOctet **)message);
   return amount_of_filled_bytes;
 }
 

+ 1 - 1
source/src/enet_encap/endianconv.h

@@ -125,7 +125,7 @@ void DetermineEndianess(void);
 int GetEndianess(void);
 
 void MoveMessageNOctets(int n,
-                        CipOctet **message_runner);
+                        const CipOctet **message_runner);
 
 int FillNextNMessageOctetsWith(CipOctet value,
                                unsigned int n,

+ 14 - 16
source/src/opener_api.h

@@ -31,28 +31,27 @@
  *  @return kEipStatusOk if the configuring worked otherwise kEipStatusError
  */
 EipStatus
-ConfigureNetworkInterface(const char *const ip_address,
-                          const char *const subnet_mask,
-                          const char *const gateway_address);
+ConfigureNetworkInterface(const char *const network_interface);
 
 /** @ingroup CIP_API
  * @brief Configure the MAC address of the device
  *
  *  @param mac_address  the hardware MAC address of the network interface
  */
-void ConfigureMacAddress(const EipUint8 *const mac_address);
+void ConfigureMacAddress(const char *network_interface);
 
 /** @ingroup CIP_API
  * @brief Configure the domain name of the device
  * @param domain_name the domain name to be used
  */
-void ConfigureDomainName(const char *const RESTRICT domain_name);
-
+void ConfigureDomainName(
+  );
 /** @ingroup CIP_API
  * @brief Configure the host name of the device
  * @param host_name the host name to be used
  */
-void ConfigureHostName(const char *const RESTRICT host_name);
+void ConfigureHostName(
+  );
 
 /** @ingroup CIP_API
  * @brief Set the serial number of the device's identity object.
@@ -303,7 +302,7 @@ CipInstance *CreateAssemblyObject(const EipUint32 instance_number,
                                   EipByte *const data,
                                   const EipUint16 data_length);
 
-typedef struct connection_object ConnectionObject;
+typedef struct cip_connection_object CipConnectionObject;
 
 /** @ingroup CIP_API
  * @brief Function prototype for handling the opening of connections
@@ -315,7 +314,7 @@ typedef struct connection_object ConnectionObject;
  * @return CIP error code
  */
 typedef EipStatus (*OpenConnectionFunction)(
-  ConnectionObject *RESTRICT const connection_object,
+  CipConnectionObject *RESTRICT const connection_object,
   EipUint16 *const extended_error_code);
 
 /** @ingroup CIP_API
@@ -324,16 +323,15 @@ typedef EipStatus (*OpenConnectionFunction)(
  * @param connection_object The connection object which is closing the
  * connection
  */
-typedef void (*ConnectionCloseFunction)(struct connection_object *
-                                        connection_object);
+typedef void (*ConnectionCloseFunction)(CipConnectionObject *connection_object);
 
 /** @ingroup CIP_API
  * @brief Function prototype for handling the timeout of connections
  *
  * @param connection_object The connection object which connection timed out
  */
-typedef void (*ConnectionTimeoutFunction)(struct connection_object *
-                                          connection_object);
+typedef void (*ConnectionTimeoutFunction)(
+  CipConnectionObject *connection_object);
 
 /** @ingroup CIP_API
  * @brief Function prototype for sending data via a connection
@@ -342,7 +340,7 @@ typedef void (*ConnectionTimeoutFunction)(struct connection_object *
  *
  * @return EIP stack status
  */
-typedef EipStatus (*ConnectionSendDataFunction)(struct connection_object *
+typedef EipStatus (*ConnectionSendDataFunction)(CipConnectionObject *
                                                 connection_object);
 
 /** @ingroup CIP_API
@@ -355,7 +353,7 @@ typedef EipStatus (*ConnectionSendDataFunction)(struct connection_object *
  * @return Stack status
  */
 typedef EipStatus (*ConnectionReceiveDataFunction)(
-  struct connection_object *connection_object,
+  CipConnectionObject *connection_object,
   const EipUint8 *data,
   const EipUint16 data_length);
 
@@ -370,7 +368,7 @@ typedef EipStatus (*ConnectionReceiveDataFunction)(
  * @return EIP_OK on success
  */
 EipStatus
-AddConnectableObject(EipUint32 class_id,
+AddConnectableObject(const EipUint32 class_id,
                      OpenConnectionFunction open_connection_function);
 
 /** @ingroup CIP_API

+ 2 - 2
source/src/ports/POSIX/CMakeLists.txt

@@ -1,6 +1,6 @@
 add_subdirectory(sample_application)
 
-set( PLATFORM_SPEC_SRC networkhandler.c opener_error.c)
+set( PLATFORM_SPEC_SRC networkhandler.c opener_error.c networkconfig.c)
 
 #######################################
 # Add common includes                 #
@@ -16,4 +16,4 @@ add_library( ${OpENer_PLATFORM}PLATFORM ${PLATFORM_SPEC_SRC})
 
 add_executable(OpENer main.c)
 
-target_link_libraries( OpENer CIP SAMPLE_APP ENET_ENCAP PLATFORM_GENERIC ${OpENer_PLATFORM}PLATFORM ${PLATFORM_SPEC_LIBS} ${OpENer_ADD_CIP_OBJECTS} rt)
+target_link_libraries( OpENer CIP Utils SAMPLE_APP ENET_ENCAP PLATFORM_GENERIC ${OpENer_PLATFORM}PLATFORM ${PLATFORM_SPEC_LIBS} ${OpENer_ADD_CIP_OBJECTS} rt)

+ 13 - 16
source/src/ports/POSIX/main.c

@@ -11,6 +11,9 @@
 #include "opener_api.h"
 #include "cipcommon.h"
 #include "trace.h"
+#include "networkconfig.h"
+#include "doublylinkedlist.h"
+#include "cipconnectionobject.h"
 
 /******************************************************************************/
 /** @brief Signal handler function for ending stack execution
@@ -27,30 +30,24 @@ int g_end_stack = 0;
 /******************************************************************************/
 int main(int argc,
          char *arg[]) {
-  EipUint8 my_mac_address[6];
   EipUint16 unique_connection_id;
 
-  if (argc != 12) {
+  if (argc != 2) {
     printf("Wrong number of command line parameters!\n");
     printf("The correct command line parameters are:\n");
-    printf(
-      "./OpENer ipaddress subnetmask gateway domainname hostaddress macaddress\n");
-    printf(
-      "    e.g. ./OpENer 192.168.0.2 255.255.255.0 192.168.0.1 test.com testdevice 00 15 C5 BF D0 87\n");
+    printf("./OpENer interfacename\n");
+    printf("    e.g. ./OpENer eth1\n");
     exit(0);
   } else {
+    DoublyLinkedListInitialize(&connection_list,
+                               CipConnectionObjectListArrayAllocator,
+                               CipConnectionObjectListArrayFree);
     /* fetch Internet address info from the platform */
-    ConfigureNetworkInterface(arg[1], arg[2], arg[3]);
-    ConfigureDomainName(arg[4]);
-    ConfigureHostName(arg[5]);
+    ConfigureNetworkInterface(arg[1]);
+    ConfigureDomainName();
+    ConfigureHostName();
 
-    my_mac_address[0] = (EipUint8) strtoul(arg[6], NULL, 16);
-    my_mac_address[1] = (EipUint8) strtoul(arg[7], NULL, 16);
-    my_mac_address[2] = (EipUint8) strtoul(arg[8], NULL, 16);
-    my_mac_address[3] = (EipUint8) strtoul(arg[9], NULL, 16);
-    my_mac_address[4] = (EipUint8) strtoul(arg[10], NULL, 16);
-    my_mac_address[5] = (EipUint8) strtoul(arg[11], NULL, 16);
-    ConfigureMacAddress(my_mac_address);
+    ConfigureMacAddress(arg[1]);
   }
 
   /*for a real device the serial number should be unique per device */

+ 184 - 0
source/src/ports/POSIX/networkconfig.c

@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "ciptcpipinterface.h"
+#include "networkconfig.h"
+#include "cipcommon.h"
+#include "ciperror.h"
+#include "trace.h"
+#include "opener_api.h"
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#define LOOPBACK_BINARY 0x7f000001
+
+void ConfigureMacAddress(const char *interface) {
+  struct ifreq ifr;
+  size_t if_name_len = strlen(interface);
+  if ( if_name_len < sizeof(ifr.ifr_name) ) {
+    memcpy(ifr.ifr_name, interface, if_name_len);
+    ifr.ifr_name[if_name_len] = 0;
+  } else {
+    OPENER_TRACE_INFO("interface name is too long");
+  }
+
+  int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+  if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
+    memcpy( &(g_ethernet_link.physical_address), &ifr.ifr_hwaddr.sa_data,
+            sizeof(g_ethernet_link.physical_address) );
+  }
+}
+
+EipStatus ConfigureNetworkInterface(const char *const network_interface) {
+
+  struct ifreq ifr;
+  size_t if_name_len = strlen(network_interface);
+  if ( if_name_len < sizeof(ifr.ifr_name) ) {
+    memcpy(ifr.ifr_name, network_interface, if_name_len);
+    ifr.ifr_name[if_name_len] = 0;
+  } else {
+    OPENER_TRACE_INFO("interface name is too long\n");
+  }
+
+  int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+  int ipaddr = 0;
+  int netaddr = 0;
+  if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+    ipaddr = ( (struct sockaddr_in *) &ifr.ifr_addr )->sin_addr.s_addr;
+  }
+
+  if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0) {
+    netaddr = ( (struct sockaddr_in *) &ifr.ifr_netmask )->sin_addr.s_addr;
+  }
+
+  interface_configuration_.ip_address = ipaddr;
+  interface_configuration_.network_mask = netaddr;
+
+  FILE *file_handle = fopen("/proc/net/route", "r");
+  char line[100] = { 0 };
+  char *string_part1 = NULL;
+  char *string_part2 = NULL;
+  char *gateway_string = NULL;
+  CipUdint gateway = 0;
+
+  while ( fgets(line, 100, file_handle) ) {
+    if ( strstr(line, network_interface) ) {
+      string_part1 = strtok(line, " \t");
+      string_part2 = strtok(NULL, " \t");
+      gateway_string = strtok(NULL, "\t");
+    }
+  }
+  fclose(file_handle);
+
+  if (inet_pton(AF_INET, gateway_string, gateway) == 1) {
+    if (gateway != LOOPBACK_BINARY) {
+      interface_configuration_.gateway = gateway;
+    } else {
+      interface_configuration_.gateway = 0;
+    }
+  } else {
+    interface_configuration_.gateway = 0;
+  }
+
+  /* calculate the CIP multicast address. The multicast address is calculated, not input*/
+  EipUint32 host_id = ntohl(interface_configuration_.ip_address)
+                      & ~ntohl(interface_configuration_.network_mask); /* see CIP spec 3-5.3 for multicast address algorithm*/
+  host_id -= 1;
+  host_id &= 0x3ff;
+
+  g_multicast_configuration.starting_multicast_address = htonl(
+    ntohl( inet_addr("239.192.1.0") ) + (host_id << 5) );
+
+  return kEipStatusOk;
+}
+
+void ConfigureDomainName() {
+  FILE *file_handle = fopen("/etc/resolv.conf", "r");
+
+  char line[100] = { 0 };
+  char *string_part1 = NULL;
+  char *domain_name_string = NULL;
+  char *dns1_string = NULL;
+  char *dns2_string = NULL;
+  CipBool done_domain = false;
+  CipBool done_n1 = false;
+
+  while ( fgets(line, 100, file_handle) ) {
+    if (strstr(line, "domain") && !done_domain) {
+      string_part1 = strtok(line, " ");
+      domain_name_string = strtok(NULL, "\n");
+
+      if (NULL != interface_configuration_.domain_name.string) {
+        /* if the string is already set to a value we have to free the resources
+         * before we can set the new value in order to avoid memory leaks.
+         */
+        CipFree(interface_configuration_.domain_name.string);
+      }
+      interface_configuration_.domain_name.length = strlen(domain_name_string);
+
+      if (interface_configuration_.domain_name.length) {
+        interface_configuration_.domain_name.string = (EipByte *) CipCalloc(
+          interface_configuration_.domain_name.length + 1, sizeof(EipInt8) );
+        strcpy(interface_configuration_.domain_name.string, domain_name_string);
+      } else {
+        interface_configuration_.domain_name.string = NULL;
+      }
+      done_domain = true;
+      continue;
+    }
+
+    if (strstr(line, "nameserver") && !done_n1) {
+      string_part1 = strtok(line, " ");
+      dns1_string = strtok(NULL, "\n");
+
+      inet_pton(AF_INET, dns1_string, &interface_configuration_.name_server);
+
+      done_n1 = true;
+      continue;
+    }
+    if (strstr(line, "nameserver ") && done_n1) {
+      string_part1 = strtok(line, " ");
+      dns2_string = strtok(NULL, "\n");
+
+      inet_pton(AF_INET, dns2_string, &interface_configuration_.name_server_2);
+      break;
+    }
+  }
+  close(file_handle);
+
+}
+
+void ConfigureHostName() {
+  char name[1024] = { 0 };
+  gethostname( name, sizeof(name) );
+
+  if (NULL != hostname_.string) {
+    /* if the string is already set to a value we have to free the resources
+     * before we can set the new value in order to avoid memory leaks.
+     */
+    CipFree(hostname_.string);
+  }
+  hostname_.length = strlen(name);
+  if (hostname_.length) {
+    hostname_.string = (EipByte *) CipCalloc( hostname_.length + 1,
+                                              sizeof(EipByte) );
+    strcpy(hostname_.string, name);
+  } else {
+    hostname_.string = NULL;
+  }
+}

+ 14 - 0
source/src/ports/POSIX/networkconfig.h

@@ -0,0 +1,14 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#include "cipethernetlink.h"
+
+EipStatus ConfigureNetworkInterface(const char *network_interface);
+
+void ConfigureDomainName(
+  );
+
+void ConfigureHostName(
+  );

+ 12 - 2
source/src/ports/POSIX/networkhandler.c

@@ -10,6 +10,8 @@
 
 #include "networkhandler.h"
 
+#include "opener_error.h"
+#include "trace.h"
 #include "encap.h"
 #include "opener_user_conf.h"
 
@@ -33,7 +35,15 @@ EipStatus NetworkHandlerInitializePlatform(void) {
 }
 
 void CloseSocketPlatform(int socket_handle) {
-  shutdown(socket_handle, SHUT_RDWR);
+  if(0 != shutdown(socket_handle, SHUT_RDWR) ) {
+    int error_code = GetSocketErrorNumber();
+    char *error_message = GetErrorMessage(error_code);
+    OPENER_TRACE_ERR("Could not close socket %d - Error Code: %d - %s\n",
+                     socket_handle,
+                     error_code,
+                     error_message);
+    FreeErrorMessage(error_message);
+  }
   close(socket_handle);
 }
 
@@ -47,5 +57,5 @@ void SetQosOnSocket(int socket,
                     CipUsint qos_value) {
 
   int set_tos = qos_value;
-  setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos));
+  setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos) );
 }

+ 2 - 1
source/src/ports/POSIX/networkhandler.h

@@ -41,6 +41,7 @@ MicroSeconds GetMicroSeconds(void);
  */
 MilliSeconds GetMilliSeconds(void);
 
-void SetQosOnSocket(int socket, CipUsint qos_value);
+void SetQosOnSocket(int socket,
+                    CipUsint qos_value);
 
 #endif /* OPENER_NETWORKHANDLER_H_ */

+ 2 - 3
source/src/ports/POSIX/sample_application/opener_user_conf.h

@@ -36,7 +36,7 @@
 #define OPENER_DEVICE_PRODUCT_CODE      65001
 #define OPENER_DEVICE_MAJOR_REVISION      1
 #define OPENER_DEVICE_MINOR_REVISION      2
-#define OPENER_DEVICE_NAME      "OpENer PC"
+#define OPENER_DEVICE_NAME      ("OpENer PC")
 
 /** @brief Define the number of objects that may be used in connections
  *
@@ -47,7 +47,7 @@
 #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.
+ *  According to ODVA's PUB 70 this number should be equal or greater than 6.
  */
 #define OPENER_CIP_NUM_EXPLICIT_CONNS 6
 
@@ -95,7 +95,6 @@
  */
 static const MilliSeconds kOpenerTimerTickInMilliSeconds = 10;
 
-
 /** @brief Define if RUN IDLE data is sent with consumed data
  */
 static const int kOpenerConsumedDataHasRunIdleHeader = 1;

+ 5 - 2
source/src/ports/POSIX/sample_application/sampleapplication.c

@@ -20,6 +20,8 @@
 
 /* global variables for demo application (4 assembly data fields)  ************/
 
+extern CipUint g_encapsulation_inactivity_timeout;
+
 EipUint8 g_assembly_data064[32]; /* Input */
 EipUint8 g_assembly_data096[32]; /* Output */
 EipUint8 g_assembly_data097[10]; /* Config */
@@ -127,14 +129,15 @@ EipStatus ResetDevice(void) {
 
 EipStatus ResetDeviceToInitialConfiguration(void) {
   /*rest the parameters */
-
+  g_encapsulation_inactivity_timeout = 120;
   /*than perform device reset*/
   ResetDevice();
   return kEipStatusOk;
 }
 
 void *
-CipCalloc(size_t number_of_elements, size_t size_of_element) {
+CipCalloc(size_t number_of_elements,
+          size_t size_of_element) {
   return calloc(number_of_elements, size_of_element);
 }
 

+ 1 - 1
source/src/ports/WIN32/CMakeLists.txt

@@ -1,6 +1,6 @@
 add_subdirectory(sample_application)
 
-set( PLATFORM_SPEC_SRC networkhandler.c opener_error.c)
+set( PLATFORM_SPEC_SRC networkhandler.c opener_error.c networkconfig.c)
 
 #######################################
 # Add common includes                 #

+ 1 - 0
source/src/ports/WIN32/main.c

@@ -11,6 +11,7 @@
 #include "opener_api.h"
 #include "cipcommon.h"
 #include "trace.h"
+#include "networkconfig.h"
 
 extern int newfd;
 

+ 73 - 0
source/src/ports/WIN32/networkconfig.c

@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "ciptcpipinterface.h"
+#include "networkconfig.h"
+#include "cipcommon.h"
+#include "ciperror.h"
+#include "opener_api.h"
+#include "trace.h"
+#include <string.h>
+
+EipStatus ConfigureNetworkInterface(const char *ip_address,
+                                    const char *subnet_mask,
+                                    const char *gateway) {
+
+  interface_configuration_.ip_address = inet_addr(ip_address);
+  interface_configuration_.network_mask = inet_addr(subnet_mask);
+  interface_configuration_.gateway = inet_addr(gateway);
+
+  /* calculate the CIP multicast address. The multicast address is calculated, not input*/
+  EipUint32 host_id = ntohl(interface_configuration_.ip_address)
+                      & ~ntohl(interface_configuration_.network_mask); /* see CIP spec 3-5.3 for multicast address algorithm*/
+  host_id -= 1;
+  host_id &= 0x3ff;
+
+  g_multicast_configuration.starting_multicast_address = htonl(
+    ntohl( inet_addr("239.192.1.0") ) + (host_id << 5) );
+
+  return kEipStatusOk;
+}
+
+void ConfigureMacAddress(const EipUint8 *const mac_address) {
+  memcpy( &g_ethernet_link.physical_address, mac_address,
+          sizeof(g_ethernet_link.physical_address) );
+
+}
+
+void ConfigureDomainName(const char *domain_name) {
+  if (NULL != interface_configuration_.domain_name.string) {
+    /* if the string is already set to a value we have to free the resources
+     * before we can set the new value in order to avoid memory leaks.
+     */
+    CipFree(interface_configuration_.domain_name.string);
+  }
+  interface_configuration_.domain_name.length = strlen(domain_name);
+  if (interface_configuration_.domain_name.length) {
+    interface_configuration_.domain_name.string = (EipByte *) CipCalloc(
+      interface_configuration_.domain_name.length + 1, sizeof(EipInt8) );
+    strcpy(interface_configuration_.domain_name.string, domain_name);
+  } else {
+    interface_configuration_.domain_name.string = NULL;
+  }
+}
+
+void ConfigureHostName(const char *const RESTRICT hostname) {
+  if (NULL != hostname_.string) {
+    /* if the string is already set to a value we have to free the resources
+     * before we can set the new value in order to avoid memory leaks.
+     */
+    CipFree(hostname_.string);
+  }
+  hostname_.length = strlen(hostname);
+  if (hostname_.length) {
+    hostname_.string = (EipByte *) CipCalloc( hostname_.length + 1,
+                                              sizeof(EipByte) );
+    strcpy(hostname_.string, hostname);
+  } else {
+    hostname_.string = NULL;
+  }
+}

+ 15 - 0
source/src/ports/WIN32/networkconfig.h

@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "cipethernetlink.h"
+
+EipStatus ConfigureNetworkInterface(const char *ip_address,
+                                    const char *subnet_mask,
+                                    const char *gateway);
+
+void ConfigureDomainName(const char *domain_name);
+
+void ConfigureHostName(const char *const RESTRICT hostname);

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

@@ -48,5 +48,5 @@ int SetSocketToNonBlocking(int socket_handle) {
 void SetQosOnSocket(int socket,
                     CipUsint qos_value) {
   CipUsint set_tos = qos_value;
-  setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos));
+  setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos) );
 }

+ 2 - 1
source/src/ports/WIN32/networkhandler.h

@@ -34,6 +34,7 @@ MicroSeconds GetMicroSeconds(void);
  */
 MilliSeconds GetMilliSeconds(void);
 
-void SetQosOnSocket(int socket, CipUsint qos_value);
+void SetQosOnSocket(int socket,
+                    CipUsint qos_value);
 
 #endif /*NETWORKHANDLER_H_*/

+ 5 - 2
source/src/ports/WIN32/sample_application/sampleapplication.c

@@ -17,6 +17,8 @@
 
 /* global variables for demo application (4 assembly data fields)  ************/
 
+extern CipUint g_encapsulation_inactivity_timeout;
+
 EipUint8 g_assembly_data064[32]; /* Input */
 EipUint8 g_assembly_data096[32]; /* Output */
 EipUint8 g_assembly_data097[10]; /* Config */
@@ -124,14 +126,15 @@ EipStatus ResetDevice(void) {
 
 EipStatus ResetDeviceToInitialConfiguration(void) {
   /*rest the parameters */
-
+  g_encapsulation_inactivity_timeout = 120;
   /*than perform device reset*/
   ResetDevice();
   return kEipStatusOk;
 }
 
 void *
-CipCalloc(unsigned pa_nNumberOfElements, unsigned pa_nSizeOfElement) {
+CipCalloc(unsigned pa_nNumberOfElements,
+          unsigned pa_nSizeOfElement) {
   return calloc(pa_nNumberOfElements, pa_nSizeOfElement);
 }
 

+ 29 - 16
source/src/ports/generic_networkhandler.c

@@ -280,7 +280,7 @@ void CheckAndHandleTcpListenerSocket(void) {
     OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
 
     new_socket = accept(g_network_status.tcp_listener, NULL, NULL);
-    if (new_socket == -1) {
+    if (new_socket == kEipInvalidSocket) {
       int error_code = GetSocketErrorNumber();
       char *error_message = GetErrorMessage(error_code);
       OPENER_TRACE_ERR("networkhandler: error on accept: %d - %s\n",
@@ -561,9 +561,11 @@ EipStatus HandleDataOnTcpSocket(int socket) {
   if (number_of_read_bytes == 0) {
     int error_code = GetSocketErrorNumber();
     char *error_message = GetErrorMessage(error_code);
-    OPENER_TRACE_ERR("networkhandler: connection closed by client: %d - %s\n",
-                     error_code,
-                     error_message);
+    OPENER_TRACE_ERR(
+      "networkhandler: socket: %d - connection closed by client: %d - %s\n",
+      socket,
+      error_code,
+      error_message);
     FreeErrorMessage(error_message);
     RemoveSocketTimerFromList(socket);
     RemoveSession(socket);
@@ -603,7 +605,8 @@ EipStatus HandleDataOnTcpSocket(int socket) {
         int error_code = GetSocketErrorNumber();
         char *error_message = GetErrorMessage(error_code);
         OPENER_TRACE_ERR(
-          "networkhandler: connection closed by client: %d - %s\n",
+          "networkhandler: socket: %d - connection closed by client: %d - %s\n",
+          socket,
           error_code,
           error_message);
         FreeErrorMessage(error_message);
@@ -639,9 +642,11 @@ EipStatus HandleDataOnTcpSocket(int socket) {
   {
     int error_code = GetSocketErrorNumber();
     char *error_message = GetErrorMessage(error_code);
-    OPENER_TRACE_ERR("networkhandler: connection closed by client: %d - %s\n",
-                     error_code,
-                     error_message);
+    OPENER_TRACE_ERR(
+      "networkhandler: socket: %d - connection closed by client: %d - %s\n",
+      socket,
+      error_code,
+      error_message);
     FreeErrorMessage(error_message);
     RemoveSocketTimerFromList(socket);
     RemoveSession(socket);
@@ -744,7 +749,7 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
   }
 
   SetSocketToNonBlocking(new_socket);
-  SetQosOnSocket(new_socket, qos_for_socket);
+  SetQosOnSocket(new_socket, GetPriorityForSocket(qos_for_socket) );
 
   OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", new_socket);
 
@@ -819,15 +824,14 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
 }
 
 void CheckAndHandleConsumingUdpSockets(void) {
+  DoublyLinkedListNode *iterator = connection_list.first;
 
-  ConnectionObject *connection_object_iterator = g_active_connection_list;
-  ConnectionObject *current_connection_object = NULL;
+  CipConnectionObject *current_connection_object = NULL;
 
   /* see a message on one of the registered UDP sockets has been received     */
-  while (NULL != connection_object_iterator) {
-    current_connection_object = connection_object_iterator;
-    connection_object_iterator = connection_object_iterator
-                                 ->next_connection_object; /* do this at the beginning as the close function may can make the entry invalid */
+  while (NULL != iterator) {
+    current_connection_object = (CipConnectionObject *)iterator->data;
+    iterator = iterator->next; /* do this at the beginning as the close function may can make the entry invalid */
 
     if ( (-1
           != current_connection_object->socket[
@@ -843,12 +847,21 @@ void CheckAndHandleConsumingUdpSockets(void) {
         g_ethernet_communication_buffer, PC_OPENER_ETHERNET_BUFFER_SIZE, 0,
         (struct sockaddr *) &from_address, &from_address_length);
       if (0 == received_size) {
-        OPENER_TRACE_STATE("connection closed by client\n");
+        int error_code = GetSocketErrorNumber();
+        char *error_message = GetErrorMessage(error_code);
+        OPENER_TRACE_ERR(
+          "networkhandler: socket: %d - connection closed by client: %d - %s\n",
+          current_connection_object->socket[
+            kUdpCommuncationDirectionConsuming],
+          error_code,
+          error_message);
+        FreeErrorMessage(error_message);
         current_connection_object->connection_close_function(
           current_connection_object);
         continue;
       }
 
+
       if (0 > received_size) {
         int error_code = GetSocketErrorNumber();
         char *error_message = GetErrorMessage(error_code);

+ 0 - 3
source/src/ports/generic_networkhandler.h

@@ -29,9 +29,6 @@
 
 SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
 
-/* values needed from the connection manager */
-extern ConnectionObject *g_active_connection_list;
-
 EipUint8 g_ethernet_communication_buffer[PC_OPENER_ETHERNET_BUFFER_SIZE]; /**< communication buffer */
 
 fd_set master_socket;

+ 2 - 1
source/src/ports/opener_error.h

@@ -17,7 +17,8 @@
  *
  * @return Error number
  */
-int GetSocketErrorNumber();
+int GetSocketErrorNumber(
+  );
 
 
 /**

+ 4 - 2
source/src/ports/socket_timer.c

@@ -8,7 +8,8 @@
 
 #include "trace.h"
 
-void SocketTimerSetSocket(SocketTimer *const socket_timer, const int socket) {
+void SocketTimerSetSocket(SocketTimer *const socket_timer,
+                          const int socket) {
   socket_timer->socket = socket;
   OPENER_TRACE_INFO("Adds socket %d to socket timers\n", socket);
 }
@@ -50,7 +51,8 @@ SocketTimer *SocketTimerArrayGetSocketTimer(
 }
 
 SocketTimer *SocketTimerArrayGetEmptySocketTimer(
-  SocketTimer *const array_of_socket_timers,const size_t array_length) {
+  SocketTimer *const array_of_socket_timers,
+  const size_t array_length) {
   return SocketTimerArrayGetSocketTimer(array_of_socket_timers, array_length,
                                         kEipInvalidSocket);
 }

+ 4 - 2
source/src/ports/socket_timer.h

@@ -24,7 +24,8 @@ typedef struct socket_timer {
  * @param socket_timer Socket Timer to be set
  * @param Socket value
  */
-void SocketTimerSetSocket(SocketTimer *const socket_timer, const int socket);
+void SocketTimerSetSocket(SocketTimer *const socket_timer,
+                          const int socket);
 
 /** @brief
  * Sets time stamp entry of the Socket Timer
@@ -82,6 +83,7 @@ SocketTimer *SocketTimerArrayGetSocketTimer(
  * @return An empty Socket Timer entry, or NULL if non is available
  */
 SocketTimer *SocketTimerArrayGetEmptySocketTimer(
-  SocketTimer *const array_of_socket_timers,const size_t array_length);
+  SocketTimer *const array_of_socket_timers,
+  const size_t array_length);
 
 #endif /* SRC_PORTS_SOCKET_TIMER_H_ */

+ 1 - 1
source/src/utils/CMakeLists.txt

@@ -2,6 +2,6 @@
 opener_common_includes()
 opener_platform_spec()
 
-set( UTILS_SRC random.c xorshiftrandom.c)
+set( UTILS_SRC random.c xorshiftrandom.c doublylinkedlist.c)
 
 add_library( Utils ${UTILS_SRC} )

+ 139 - 0
source/src/utils/doublylinkedlist.c

@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "doublylinkedlist.h"
+
+#include "opener_user_conf.h"
+
+void DoublyLinkedListInitialize(DoublyLinkedList *list,
+                                NodeMemoryAllocator allocator,
+                                NodeMemoryDeallocator deallocator) {
+  list->first = NULL;
+  list->last = NULL;
+  list->allocator = allocator;
+  list->deallocator = deallocator;
+}
+
+void DoublyLinkedListDestroy(DoublyLinkedList *list) {
+  DoublyLinkedListNode *iterator = list->first;
+  while(NULL != iterator) {
+    DoublyLinkedListNode *to_delete = iterator;
+    iterator = iterator->next;
+    DoublyLinkedListNodeDestroy(list, &to_delete);
+  }
+
+  list->first = NULL;
+  list->last = NULL;
+  list->allocator = NULL;
+  list->deallocator = NULL;
+}
+
+DoublyLinkedListNode *DoublyLinkedListNodeCreate(
+  const void *const data,
+  NodeMemoryAllocator const
+  allocator) {
+  DoublyLinkedListNode *new_node = (DoublyLinkedListNode *)allocator();
+  new_node->data = (void *)data;
+  return new_node;
+}
+
+void DoublyLinkedListNodeDestroy(const DoublyLinkedList *const list,
+                                 DoublyLinkedListNode **node) {
+  OPENER_ASSERT(list->deallocator != NULL);
+  list->deallocator(node);
+}
+
+void DoublyLinkedListInsertAtHead(DoublyLinkedList *const list,
+                                  void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                              list->allocator);
+  if(NULL == list->first) {
+    list->first = new_node;
+    list->last = new_node;
+  } else {
+    new_node->next = list->first;
+    list->first->previous = new_node;
+    list->first = new_node;
+  }
+}
+
+void DoublyLinkedListInsertAtTail(DoublyLinkedList *const list,
+                                  const void *const data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                              list->allocator);
+  if(NULL == list->last) {
+    list->first = new_node;
+    list->last = new_node;
+  } else {
+    new_node->previous = list->last;
+    list->last->next = new_node;
+    list->last = new_node;
+  }
+}
+
+void DoublyLinkedListInsertBeforeNode(DoublyLinkedList *const list,
+                                      DoublyLinkedListNode *node,
+                                      void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  if(list->first == node) {
+    DoublyLinkedListInsertAtHead(list, data);
+  } else {
+    DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                                list->allocator);
+    new_node->previous = node->previous;
+    new_node->next = node;
+    node->previous = new_node;
+    new_node->previous->next = new_node;
+  }
+}
+
+void DoublyLinkedListInsertAfterNode(DoublyLinkedList *const list,
+                                     DoublyLinkedListNode *node,
+                                     void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  if(list->last == node) {
+    DoublyLinkedListInsertAtTail(list, data);
+  } else {
+    DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                                list->allocator);
+    new_node->previous = node;
+    new_node->next = node->next;
+    node->next->previous = new_node;
+    node->next = new_node;
+  }
+}
+
+void DoublyLinkedListRemoveNode(DoublyLinkedList *const list,
+                                DoublyLinkedListNode **pointer_to_node_pointer)
+{
+  DoublyLinkedListNode *node = *pointer_to_node_pointer;
+  DoublyLinkedListNode *previous = node->previous;
+  DoublyLinkedListNode *next = node->next;
+
+  if (node == list->first && node == list->last) {
+    list->first = NULL;
+    list->last = NULL;
+  } else {
+    if(node == list->first) {
+      list->first = next;
+    }
+    if(node == list->last) {
+      list->last = previous;
+    }
+    if(NULL != previous) {
+      previous->next = next;
+    }
+    if(NULL != next) {
+      next->previous = previous;
+    }
+
+  }
+
+
+  DoublyLinkedListNodeDestroy(list, pointer_to_node_pointer);
+}

+ 67 - 0
source/src/utils/doublylinkedlist.h

@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef SRC_UTILS_DOUBLYLINKEDLIST_H_
+#define SRC_UTILS_DOUBLYLINKEDLIST_H_
+
+/**
+ * @file doublelinkedlist.h
+ *
+ * The public interface for a reference type doubly linked list
+ */
+
+typedef struct doubly_linked_list_node DoublyLinkedListNode;
+
+typedef DoublyLinkedListNode * (*NodeMemoryAllocator)(
+  );
+
+typedef void (*NodeMemoryDeallocator)(DoublyLinkedListNode **node);
+
+typedef struct doubly_linked_list_node {
+  DoublyLinkedListNode *previous;
+  DoublyLinkedListNode *next;
+  void *data;
+} DoublyLinkedListNode;
+
+typedef struct {
+  DoublyLinkedListNode *first;
+  DoublyLinkedListNode *last;
+
+  NodeMemoryAllocator allocator;
+  NodeMemoryDeallocator deallocator;
+
+} DoublyLinkedList;
+
+void DoublyLinkedListInitialize(DoublyLinkedList *list,
+                                NodeMemoryAllocator allocator,
+                                NodeMemoryDeallocator deallocator);
+
+void DoublyLinkedListDestroy(DoublyLinkedList *list);
+
+DoublyLinkedListNode *DoublyLinkedListNodeCreate(const void *const data,
+                                                 NodeMemoryAllocator allocator);
+
+void DoublyLinkedListNodeDestroy(const DoublyLinkedList *const list,
+                                 DoublyLinkedListNode **node);
+
+void DoublyLinkedListInsertAtHead(DoublyLinkedList *const list,
+                                  void *data);
+
+void DoublyLinkedListInsertAtTail(DoublyLinkedList *const list,
+                                  const void *const data);
+
+void DoublyLinkedListInsertBeforeNode(DoublyLinkedList *const list,
+                                      DoublyLinkedListNode *node,
+                                      void *data);
+
+void DoublyLinkedListInsertAfterNode(DoublyLinkedList *const list,
+                                     DoublyLinkedListNode *node,
+                                     void *data);
+
+void DoublyLinkedListRemoveNode(DoublyLinkedList *const list,
+                                DoublyLinkedListNode **pointer_to_node_pointer);
+
+#endif /* SRC_UTILS_DOUBLYLINKEDLIST_H_ */

+ 4 - 5
source/src/utils/random.c

@@ -1,9 +1,8 @@
-/*
- * random.cpp
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
  *
- *  Created on: Dec 16, 2013
- *      Author: mmm
- */
+ ******************************************************************************/
 
 #include "random.h"
 

+ 4 - 5
source/src/utils/random.h

@@ -1,9 +1,8 @@
-/*
- * random.h
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
  *
- *  Created on: Dec 1, 2013
- *      Author: mmm
- */
+ ******************************************************************************/
 
 #ifndef OPENER_RANDOM_H_
 #define OPENER_RANDOM_H_

+ 4 - 5
source/src/utils/xorshiftrandom.c

@@ -1,9 +1,8 @@
-/*
- * xorshiftrandom.c
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
  *
- *  Created on: Nov 28, 2013
- *      Author: mmm
- */
+ ******************************************************************************/
 
 #include "xorshiftrandom.h"
 

+ 4 - 5
source/src/utils/xorshiftrandom.h

@@ -1,9 +1,8 @@
-/*
- * xorshiftrandom.h
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
  *
- *  Created on: Dec 1, 2013
- *      Author: mmm
- */
+ ******************************************************************************/
 
 /**
  * @file xorshiftrandom.h

+ 2 - 1
source/tests/OpENerTests.cpp

@@ -1,6 +1,7 @@
 #include "OpENerTests.h"
 
-int main(int argc, char **argv) {
+int main(int argc,
+         char **argv) {
   /* These checks are here to make sure assertions outside test runs don't crash */
   CHECK(true);
   LONGS_EQUAL(1, 1);

+ 2 - 0
source/tests/OpENerTests.h

@@ -6,4 +6,6 @@ IMPORT_TEST_GROUP(EndianConversion);
 IMPORT_TEST_GROUP(CipEpath);
 IMPORT_TEST_GROUP(CipElectronicKey);
 IMPORT_TEST_GROUP(CipConnectionManager);
+IMPORT_TEST_GROUP(CipConnectionObject);
 IMPORT_TEST_GROUP(SocketTimer);
+IMPORT_TEST_GROUP(DoublyLinkedList);

+ 1 - 1
source/tests/cip/CMakeLists.txt

@@ -8,7 +8,7 @@ opener_common_includes()
 #######################################
 opener_platform_support("INCLUDES")
 
-set( CipTestSrc cipepathtest.cpp cipelectronickeytest.cpp cipconnectionmanagertest.cpp )
+set( CipTestSrc cipepathtest.cpp cipelectronickeytest.cpp cipconnectionmanagertest.cpp cipconnectionobjecttest.cpp )
 
 include_directories( ${SRC_DIR}/cip )
 

+ 0 - 8
source/tests/cip/cipconnectionmanagertest.cpp

@@ -18,11 +18,3 @@ TEST_GROUP(CipConnectionManager) {
 
 };
 
-TEST(CipConnectionManager, GetForwardOpenFixedVarFlag) {
-  ConnectionObject connection_object;
-  connection_object.t_to_o_network_connection_parameter = 0x2222;
-  ConnectionObjectFixedVariable fixed_variable =
-    GetConnectionObjectTargetToOriginatorFixedOrVariableConnectionSize(
-      &connection_object);
-  CHECK_EQUAL(kConnectionObjectVariableConnectionSize, fixed_variable);
-}

+ 359 - 0
source/tests/cip/cipconnectionobjecttest.cpp

@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+
+#include "cipconnectionobject.h"
+
+}
+
+TEST_GROUP(CipConnectionObject) {
+
+};
+
+TEST(CipConnectionObject, StateNonExistent) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 0;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateNonExistent, state);
+}
+
+TEST(CipConnectionObject, StateConfiguring) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 1;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateConfiguring, state);
+}
+
+TEST(CipConnectionObject, StateWaitingForConnectionID) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 2;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateWaitingForConnectionID, state);
+}
+
+TEST(CipConnectionObject, StateEstablished) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 3;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateEstablished, state);
+}
+
+TEST(CipConnectionObject, StateTimedOut) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 4;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateTimedOut, state);
+}
+
+TEST(CipConnectionObject, StateDeferredDelete) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 5;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateDeferredDelete, state);
+}
+
+TEST(CipConnectionObject, StateClosing) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 6;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateClosing, state);
+}
+
+TEST(CipConnectionObject, StateInvalid) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.state = 7;
+  ConnectionObjectState state = ConnectionObjectGetState(&connection_object);
+  CHECK_EQUAL(kConnectionObjectStateInvalid, state);
+}
+
+TEST(CipConnectionObject, InstanceTypeIExplicitMessaging) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.instance_type =
+    kConnectionObjectInstanceTypeExplicitMessaging;
+  CipUsint value = ConnectionObjectGetInstanceTypeForAttribute(
+    &connection_object);
+  CHECK_EQUAL(0, value);
+}
+
+TEST(CipConnectionObject, InstanceTypeIO) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.instance_type = kConnectionObjectInstanceTypeIO;
+  CipUsint value = ConnectionObjectGetInstanceTypeForAttribute(
+    &connection_object);
+  CHECK_EQUAL(1, value);
+}
+
+TEST(CipConnectionObject, InstanceTypeIOExclusiveOwner) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.instance_type =
+    kConnectionObjectInstanceTypeIOExclusiveOwner;
+  CipUsint value = ConnectionObjectGetInstanceTypeForAttribute(
+    &connection_object);
+  CHECK_EQUAL(1, value);
+}
+
+TEST(CipConnectionObject, InstanceTypeIOInputOnly) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.instance_type = kConnectionObjectInstanceTypeIOInputOnly;
+  CipUsint value = ConnectionObjectGetInstanceTypeForAttribute(
+    &connection_object);
+  CHECK_EQUAL(1, value);
+}
+
+TEST(CipConnectionObject, InstanceTypeIOListenOnly) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.instance_type = kConnectionObjectInstanceTypeIOListenOnly;
+  CipUsint value = ConnectionObjectGetInstanceTypeForAttribute(
+    &connection_object);
+  CHECK_EQUAL(1, value);
+}
+
+TEST(CipConnectionObject, InstanceTypeCipBridged) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.instance_type = kConnectionObjectInstanceTypeCipBridged;
+  CipUsint value = ConnectionObjectGetInstanceTypeForAttribute(
+    &connection_object);
+  CHECK_EQUAL(2, value);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerDirectionServer) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 0x80;
+  ConnectionObjectTransportClassTriggerDirection direction =
+    ConnectionObjectGetTransportClassTriggerDirection(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerDirectionServer, direction);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerDirectionClient) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 0x00;
+  ConnectionObjectTransportClassTriggerDirection direction =
+    ConnectionObjectGetTransportClassTriggerDirection(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerDirectionClient, direction);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerProductionTriggerInvalid) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 3 << 4;
+  ConnectionObjectTransportClassTriggerProductionTrigger production_trigger =
+    ConnectionObjectGetTransportClassTriggerProductionTrigger(
+      &connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerProductionTriggerInvalid,
+              production_trigger);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerProductionTriggerCyclic) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 0x00;
+  ConnectionObjectTransportClassTriggerProductionTrigger production_trigger =
+    ConnectionObjectGetTransportClassTriggerProductionTrigger(
+      &connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerProductionTriggerCyclic,
+              production_trigger);
+}
+
+TEST(CipConnectionObject,
+     TransportClassTriggerProductionTriggerChangeOfState) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 1 << 4;
+  ConnectionObjectTransportClassTriggerProductionTrigger production_trigger =
+    ConnectionObjectGetTransportClassTriggerProductionTrigger(
+      &connection_object);
+  CHECK_EQUAL(
+    kConnectionObjectTransportClassTriggerProductionTriggerChangeOfState,
+    production_trigger);
+}
+
+TEST(CipConnectionObject,
+     TransportClassTriggerProductionTriggerApplicationObject) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 2 << 4;
+  ConnectionObjectTransportClassTriggerProductionTrigger production_trigger =
+    ConnectionObjectGetTransportClassTriggerProductionTrigger(
+      &connection_object);
+  CHECK_EQUAL(
+    kConnectionObjectTransportClassTriggerProductionTriggerApplicationObject,
+    production_trigger);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerClassInvalid) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 5;
+  ConnectionObjectTransportClassTriggerTransportClass transport_class =
+    ConnectionObjectGetTransportClassTriggerTransportClass(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerTransportClassInvalid,
+              transport_class);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerClass0) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 0;
+  ConnectionObjectTransportClassTriggerTransportClass transport_class =
+    ConnectionObjectGetTransportClassTriggerTransportClass(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerTransportClass0,
+              transport_class);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerClass1) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 1;
+  ConnectionObjectTransportClassTriggerTransportClass transport_class =
+    ConnectionObjectGetTransportClassTriggerTransportClass(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerTransportClass1,
+              transport_class);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerClass2) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 2;
+  ConnectionObjectTransportClassTriggerTransportClass transport_class =
+    ConnectionObjectGetTransportClassTriggerTransportClass(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerTransportClass2,
+              transport_class);
+}
+
+TEST(CipConnectionObject, TransportClassTriggerClass3) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.transport_class_trigger = 3;
+  ConnectionObjectTransportClassTriggerTransportClass transport_class =
+    ConnectionObjectGetTransportClassTriggerTransportClass(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerTransportClass3,
+              transport_class);
+}
+
+TEST(CipConnectionObject, ExpectedPacketRate) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.t_to_o_requested_packet_interval = 11 * 1000; // 11 ms in µs
+  ConnectionObjectSetExpectedPacketRate(&connection_object);
+  CipUint expected_packet_rate = ConnectionObjectGetExpectedPacketRate(
+    &connection_object);
+  CHECK_EQUAL(20, expected_packet_rate);
+}
+
+TEST(CipConnectionObject, ExpectedPacketRateBelowTimerResolution) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.t_to_o_requested_packet_interval = 9 * 1000; // 9 ms in µs
+  ConnectionObjectSetExpectedPacketRate(&connection_object);
+  CipUint expected_packet_rate = ConnectionObjectGetExpectedPacketRate(
+    &connection_object);
+  CHECK_EQUAL(10, expected_packet_rate);
+}
+
+TEST(CipConnectionObject, ExpectedPacketRateZero) {
+  CipConnectionObject connection_object = { 0 };
+  connection_object.t_to_o_requested_packet_interval = 0; // A value of zero needs to be maintained, as this deactivates timeout
+  ConnectionObjectSetExpectedPacketRate(&connection_object);
+  CipUint expected_packet_rate = ConnectionObjectGetExpectedPacketRate(
+    &connection_object);
+  CHECK_EQUAL(0, expected_packet_rate);
+}
+
+TEST(CipConnectionObject, ParseConnectionData) {
+  CipConnectionObject connection_object = { 0 };
+  const CipOctet message[] =
+    "\x06\x28\x00\x00\x00\x00\x00\x00\x00\x00\x98\xff\x18\x00\x78\x56" \
+    "\x34\x12\x00\x00\x00\x00\xe0\x93\x04\x00\x02\x40\xa0\x86\x01\x00" \
+    "\x22\x20\x01\x04\x20\x04\x24\x97\x2c\x98\x2c\x64";
+
+  const CipOctet *message_runner = (const CipOctet *)message;
+
+  ConnectionObjectInitializeFromMessage(&message_runner, &connection_object);
+  CipUdint o_to_t_network_connection_id =
+    ConnectionObjectGetCipConsumedConnectionID(&connection_object);
+  CHECK_EQUAL(0, o_to_t_network_connection_id);
+
+  CipUdint t_to_o_network_connection_id =
+    ConnectionObjectGetCipProducedConnectionID(&connection_object);
+  CHECK_EQUAL(0, t_to_o_network_connection_id);
+
+  CipUint connection_serial_number = ConnectionObjectGetConnectionSerialNumber(
+    &connection_object);
+  CHECK_EQUAL(0xff98, connection_serial_number);
+
+  CipUint vendor_id = ConnectionObjectGetOriginatorVendorId(&connection_object);
+  CHECK_EQUAL(0x0018, vendor_id);
+
+  CipUdint originator_serial_number = ConnectionObjectGetOriginatorSerialNumber(
+    &connection_object);
+  CHECK_EQUAL(0x12345678, originator_serial_number);
+
+  CipUsint connection_timeout_multiplier =
+    ConnectionObjectGetConnectionTimeoutMultiplier(&connection_object);
+  CHECK_EQUAL(0, connection_timeout_multiplier);
+
+  CipUdint o_to_t_rpi_in_microseconds =
+    ConnectionObjectGetOToTRequestedPacketInterval(&connection_object);
+  CHECK_EQUAL(300000, o_to_t_rpi_in_microseconds);
+
+  bool o_to_t_redundant_owner = ConnectionObjectIsOToTRedundantOwner(
+    &connection_object);
+  CHECK_EQUAL(false, o_to_t_redundant_owner);
+
+  ConnectionObjectConnectionType o_to_t_connection_type =
+    ConnectionObjectGetOToTConnectionType(&connection_object);
+  CHECK_EQUAL(kConnectionObjectConnectionTypePointToPoint,
+              o_to_t_connection_type);
+
+  ConnectionObjectPriority o_to_t_priority = ConnectionObjectGetOToTPriority(
+    &connection_object);
+  CHECK_EQUAL(kConnectionObjectPriorityLow, o_to_t_priority);
+
+  ConnectionObjectConnectionSizeType o_to_t_connection_size_type =
+    ConnectionObjectGetOToTConnectionSizeType(&connection_object);
+  CHECK_EQUAL(kConnectionObjectConnectionSizeTypeFixed,
+              o_to_t_connection_size_type);
+
+  size_t o_to_t_connection_size = ConnectionObjectGetOToTConnectionSize(
+    &connection_object);
+  CHECK_EQUAL(2ULL, o_to_t_connection_size);
+
+  //T to O Tests
+
+  CipUdint t_to_o_rpi_in_microseconds =
+    ConnectionObjectGetTToORequestedPacketInterval(&connection_object);
+  CHECK_EQUAL(100000, t_to_o_rpi_in_microseconds);
+
+  bool t_to_o_redundant_owner = ConnectionObjectIsTToORedundantOwner(
+    &connection_object);
+  CHECK_EQUAL(false, t_to_o_redundant_owner);
+
+  ConnectionObjectConnectionType t_to_o_connection_type =
+    ConnectionObjectGetTToOConnectionType(&connection_object);
+  CHECK_EQUAL(kConnectionObjectConnectionTypeMulticast, t_to_o_connection_type);
+
+  ConnectionObjectPriority t_to_o_priority = ConnectionObjectGetTToOPriority(
+    &connection_object);
+  CHECK_EQUAL(kConnectionObjectPriorityLow, t_to_o_priority);
+
+  ConnectionObjectConnectionSizeType t_to_o_connection_size_type =
+    ConnectionObjectGetTToOConnectionSizeType(&connection_object);
+  CHECK_EQUAL(kConnectionObjectConnectionSizeTypeFixed,
+              t_to_o_connection_size_type);
+
+  size_t t_to_o_connection_size = ConnectionObjectGetTToOConnectionSize(
+    &connection_object);
+  CHECK_EQUAL(34ULL, t_to_o_connection_size);
+
+  ConnectionObjectTransportClassTriggerDirection direction =
+    ConnectionObjectGetTransportClassTriggerDirection(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerDirectionClient, direction);
+
+  ConnectionObjectTransportClassTriggerProductionTrigger trigger =
+    ConnectionObjectGetTransportClassTriggerProductionTrigger(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerProductionTriggerCyclic,
+              trigger);
+
+  ConnectionObjectTransportClassTriggerTransportClass transport_class =
+    ConnectionObjectGetTransportClassTriggerTransportClass(&connection_object);
+  CHECK_EQUAL(kConnectionObjectTransportClassTriggerTransportClass1,
+              transport_class);
+
+}

+ 27 - 14
source/tests/cip/cipelectronickeytest.cpp

@@ -30,7 +30,7 @@ TEST_GROUP(CipElectronicKey) {
 
 TEST(CipElectronicKey, CreateElectronicKey) {
   char dummyArea[kElectronicKeyFormat4Size];
-  memset(dummyArea, 0, sizeof(dummyArea));
+  memset(dummyArea, 0, sizeof(dummyArea) );
   MEMCMP_EQUAL(dummyArea, key, kElectronicKeyFormat4Size);
 };
 
@@ -41,10 +41,10 @@ TEST(CipElectronicKey, DeleteElectronicKey) {
 
 TEST(CipElectronicKey, SetVendorID) {
   char demoArea[kElectronicKeyFormat4Size];
-  memset(demoArea, 0, sizeof(demoArea));
+  memset(demoArea, 0, sizeof(demoArea) );
   CipUint *vendor_id = (CipUint *)demoArea;
   *vendor_id = 1;
-  ElectronicKeyFormat4SetVendorId(1, key);
+  ElectronicKeyFormat4SetVendorId(key, 1);
 
   MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
 }
@@ -61,11 +61,11 @@ TEST(CipElectronicKey, GetVendorID) {
 
 TEST(CipElectronicKey, SetDeviceType) {
   char demoArea[kElectronicKeyFormat4Size];
-  memset(demoArea, 0, sizeof(demoArea));
+  memset(demoArea, 0, sizeof(demoArea) );
   CipUint *device_type = (CipUint *)demoArea + 1;
   *device_type = 1;
 
-  ElectronicKeyFormat4SetDeviceType(1, key);
+  ElectronicKeyFormat4SetDeviceType(key, 1);
   MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
 }
 
@@ -81,11 +81,11 @@ TEST(CipElectronicKey, GetDeviceType) {
 
 TEST(CipElectronicKey, SetProductCode) {
   char demoArea[kElectronicKeyFormat4Size];
-  memset(demoArea, 0, sizeof(demoArea));
+  memset(demoArea, 0, sizeof(demoArea) );
   CipUint *product_code = (CipUint *)demoArea + 2;
   *product_code = 1;
 
-  ElectronicKeyFormat4SetProductCode(1, key);
+  ElectronicKeyFormat4SetProductCode(key, 1);
   MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
 }
 
@@ -101,11 +101,11 @@ TEST(CipElectronicKey, GetProductCode) {
 
 TEST(CipElectronicKey, SetMajorRevisionCompatibility) {
   char demoArea[kElectronicKeyFormat4Size];
-  memset(demoArea, 0, sizeof(demoArea));
+  memset(demoArea, 0, sizeof(demoArea) );
   CipByte *major_revision_compatiblitiy = (CipByte *)demoArea + 6;
   *major_revision_compatiblitiy = 0x81;
 
-  ElectronicKeyFormat4SetMajorRevisionCompatibility(0x81, key);
+  ElectronicKeyFormat4SetMajorRevisionCompatibility(key, 0x81);
   MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
 }
 
@@ -132,11 +132,11 @@ TEST(CipElectronicKey, GetMajorRevisionCompatibility) {
 
 TEST(CipElectronicKey, SetMinorRevision) {
   char demoArea[kElectronicKeyFormat4Size];
-  memset(demoArea, 0, sizeof(demoArea));
+  memset(demoArea, 0, sizeof(demoArea) );
   CipByte *minor_revision_compatiblitiy = (CipByte *)demoArea + 7;
   *minor_revision_compatiblitiy = 0x81;
 
-  ElectronicKeyFormat4SetMinorRevision(0x81, key);
+  ElectronicKeyFormat4SetMinorRevision(key, 0x81);
   MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
 }
 
@@ -152,10 +152,12 @@ TEST(CipElectronicKey, GetMinorRevision) {
 
 TEST(CipElectronicKey, ParseElectronicKeyTest) {
   /* Size of an electronic key is 1 + 1 + 8 (Segment, Key format, Key) */
-  const unsigned char message[] =
+  const CipOctet message[] =
   {0x34, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x84, 0x05};
-  GetPathLogicalSegmentElectronicKeyFormat4(message, key);
+  const CipOctet *message_buffer = message;
+  GetElectronicKeyFormat4FromMessage( (const CipOctet **)&message_buffer, key );
 
+  message_buffer = message;
   CHECK_EQUAL( 256, ElectronicKeyFormat4GetVendorId(key) );
   CHECK_EQUAL( 512, ElectronicKeyFormat4GetDeviceType(key) );
   CHECK_EQUAL( 768, ElectronicKeyFormat4GetProductCode(key) );
@@ -163,6 +165,17 @@ TEST(CipElectronicKey, ParseElectronicKeyTest) {
   CHECK_EQUAL( 0x04, ElectronicKeyFormat4GetMajorRevision(key) );
   CHECK_EQUAL( 0x05, ElectronicKeyFormat4GetMinorRevision(key) );
 
-  MEMCMP_EQUAL(message + 2, key, 8);
+  MEMCMP_EQUAL(message_buffer + 2, key, 8);
 
 }
+
+//TEST(CipElectronicKey, CheckElectronicKeyWrongVendorId) {
+//	const CipOctet message [] = "\x34\x04\x02\x00\x0c\x00\xe9\xfd\x01\x02";
+//	const CipOctet *message_buffer = message;
+//	EipUint16 *extended_status = 0;
+//
+//	GetElectronicKeyFormat4FromMessage((const CipOctet**)&message_buffer, key);
+//
+//	CheckElectronicKeyData(4, key_data, extended_status);
+//
+//}

+ 6 - 4
source/tests/cip/cipepathtest.cpp

@@ -277,7 +277,7 @@ TEST(CipEpath, GetPathLogicalSegmentElectronicKeyFormatReserved) {
   CHECK_EQUAL(kElectronicKeySegmentFormatReserved, key_format);
 }
 
-TEST(CipEpath, GetPathLogicalSegmentElectronicKeyFormat4) {
+TEST(CipEpath, GetElectronicKeyFormat4FromMessage) {
   const unsigned char message[] = {0x34, 0x04};
   ElectronicKeySegmentFormat key_format =
     GetPathLogicalSegmentElectronicKeyFormat(message);
@@ -286,12 +286,14 @@ TEST(CipEpath, GetPathLogicalSegmentElectronicKeyFormat4) {
 
 TEST(CipEpath, GetLogicalSegmentElectronicKeyFormat4) {
   /* Size of an electronic key is 1 + 1 + 8 (Segment, Key format, Key) */
-  const unsigned char message[] =
+  const CipOctet message[] =
   {0x34, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x04, 0x05};
+  const CipOctet *message_pp = (const CipOctet *)message;
+  const CipOctet *message_buffer = message;
   ElectronicKeyFormat4 *electronic_key = ElectronicKeyFormat4New();
-  GetPathLogicalSegmentElectronicKeyFormat4(message, electronic_key);
+  GetElectronicKeyFormat4FromMessage(&message_pp, electronic_key);
 
-  MEMCMP_EQUAL(message + 2, electronic_key, 8);
+  MEMCMP_EQUAL(message_buffer + 2, electronic_key, 8);
 
   ElectronicKeyFormat4Delete(&electronic_key);
 }

+ 2 - 2
source/tests/enet_encap/endianconvtest.cpp

@@ -130,8 +130,8 @@ TEST(EndianConversion, EncapsulateIpAddress) {
 }
 
 TEST(EndianConversion, MoveMessageNOctets) {
-  CipOctet message[8];
-  CipOctet *message_runner = message;
+  const CipOctet message[] = "This is a test message";
+  const CipOctet *message_runner = message;
 
   MoveMessageNOctets(4, &message_runner);
 

+ 1 - 1
source/tests/utils/CMakeLists.txt

@@ -1,7 +1,7 @@
 
 opener_common_includes()
 
-set( UtilsTestSrc randomTests.cpp xorshiftrandomtests.cpp)
+set( UtilsTestSrc randomTests.cpp xorshiftrandomtests.cpp doublylinkedlistTests.cpp)
 
 include_directories( ${SRC_DIR}/utils )
 

+ 278 - 0
source/tests/utils/doublylinkedlistTests.cpp

@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+#include <doublylinkedlist.h>
+}
+
+TEST_GROUP(DoublyLinkedList) {
+
+};
+
+const size_t kNodesAmount = 5;
+
+static DoublyLinkedListNode nodes[kNodesAmount] = { 0 };
+
+DoublyLinkedListNode *CallocAllocator() {
+  return (DoublyLinkedListNode *) calloc( 1, sizeof( DoublyLinkedListNode) );
+}
+
+void CallocDeallocator(DoublyLinkedListNode **node) {
+  free(*node);
+  *node = NULL;
+}
+
+DoublyLinkedListNode *ArrayAllocator() {
+  for(size_t i = 0; i < kNodesAmount; ++i) {
+    if(nodes[i].previous == NULL && nodes[i].next == NULL && nodes[i].data ==
+       NULL) {
+      return &nodes[i];
+    }
+  }
+  return NULL;
+}
+
+void ArrayFree(DoublyLinkedListNode **node) {
+  if(*node != NULL) {
+    memset( *node, 0, sizeof(DoublyLinkedListNode) );
+    *node = NULL;
+  }
+}
+
+TEST(DoublyLinkedList, CallocAllocatorCreateTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          CallocAllocator);
+  CHECK_EQUAL( test_data, *( (int *)node->data ) );
+  CallocDeallocator(&node);
+}
+
+TEST(DoublyLinkedList, CallocFreeTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          CallocAllocator);
+  CallocDeallocator(&node);
+  POINTERS_EQUAL(NULL, node);
+}
+
+TEST(DoublyLinkedList, ArrayAllocatorCreateTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          ArrayAllocator);
+  CHECK_EQUAL( test_data, *( (int *)node->data ) );
+  ArrayFree(&node);
+}
+
+TEST(DoublyLinkedList, ArrayAllocatorDeleteTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          ArrayAllocator);
+  DoublyLinkedListNode *assigned_array_slot = node;
+  ArrayFree(&node);
+  CHECK_EQUAL(8, test_data);
+  POINTERS_EQUAL(NULL, assigned_array_slot->data);
+  POINTERS_EQUAL(NULL, assigned_array_slot->previous);
+  POINTERS_EQUAL(NULL, assigned_array_slot->next);
+  POINTERS_EQUAL(NULL, node);
+}
+
+TEST(DoublyLinkedList, InitializeList) {
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  POINTERS_EQUAL(CallocAllocator, list.allocator);
+  POINTERS_EQUAL(CallocDeallocator, list.deallocator);
+}
+
+TEST(DoublyLinkedList, CheckDestroyListCleansInteralVaribles) {
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  POINTERS_EQUAL(NULL, list.allocator);
+  POINTERS_EQUAL(NULL, list.deallocator);
+}
+
+TEST(DoublyLinkedList, InsertFirstAtHead) {
+  int test_data = 42;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  CHECK_EQUAL( 42, *(int *)(list.first->data) );
+  CHECK_EQUAL( 42, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertSecondAtHead) {
+  int test_data = 42;
+  int test_data_2 = 42 * 2;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  CHECK_EQUAL( 84, *(int *)(list.first->data) );
+  CHECK_EQUAL( 42, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, CheckDestroyListRemovesAllNodes) {
+  int test_data = 42;
+  int test_data_2 = 84;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertFirstAtTail) {
+  int test_data = 42;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data);
+  CHECK_EQUAL( 42, *(int *)(list.first->data) );
+  CHECK_EQUAL( 42, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertSecondAtTail) {
+  int test_data = 42;
+  int test_data_2 = 84;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data);
+  DoublyLinkedListInsertAtTail(&list, &test_data_2);
+  CHECK_EQUAL( 42, *(int *)(list.first->data) );
+  CHECK_EQUAL( 84, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertAfterNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertAfterNode(&list, list.first, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.first->next->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, InsertAfterLastNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertAfterNode(&list, list.last, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.last->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, InsertBeforeNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertBeforeNode(&list, list.last, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.last->previous->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, InsertBeforeFirstNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertBeforeNode(&list, list.first, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.first->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, RemoveFirstElementInList) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data_1);
+  DoublyLinkedListInsertAtTail(&list, &test_data_2);
+  DoublyLinkedListInsertAtTail(&list, &test_data_3);
+  DoublyLinkedListNode *node_to_be_deleted = list.first;
+  DoublyLinkedListRemoveNode(&list, &node_to_be_deleted);
+  CHECK_EQUAL(2, test_data_1);
+  CHECK_EQUAL(4, *( (int *)list.first->data ) );
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, RemoveFirstElementInOtherwiseEmptyList) {
+  int test_data_1 = 2;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data_1);
+  DoublyLinkedListNode *node_to_be_deleted = list.first;
+  DoublyLinkedListRemoveNode(&list, &node_to_be_deleted);
+  CHECK_EQUAL(2, test_data_1);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, RemoveLastElementInOtherwiseEmptyList) {
+  int test_data_1 = 2;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data_1);
+  DoublyLinkedListNode *node_to_be_deleted = list.last;
+  DoublyLinkedListRemoveNode(&list, &node_to_be_deleted);
+  CHECK_EQUAL(2, test_data_1);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, CheckDeleteAllNodesResultsInEmptyList) {
+  int test_data = 42;
+  int test_data_2 = 84;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListNode *node_to_delete = list.first;
+  DoublyLinkedListRemoveNode(&list, &node_to_delete);
+  POINTERS_EQUAL(NULL, node_to_delete);
+  node_to_delete = list.first;
+  DoublyLinkedListRemoveNode(&list, &node_to_delete);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  DoublyLinkedListDestroy(&list);
+}

+ 1 - 1
uncrustify.cfg

@@ -35,7 +35,7 @@ sp_balance_nested_parens=true
 align_keep_tabs=false
 align_with_tabs=false
 align_on_tabstop=false
-align_number_left=false
+align_number_right=true
 align_func_params=false
 align_same_func_call_params=false
 align_var_def_colon=false

Некоторые файлы не были показаны из-за большого количества измененных файлов