Просмотр исходного кода

Merge pull request #132 from EIPStackGroup/Issue_131

Closes #131 Issue 131
Martin Melik-Merkumians 8 лет назад
Родитель
Сommit
d7a04bbefb

+ 1 - 0
source/src/cip/appcontype.c

@@ -428,6 +428,7 @@ bool ConnectionWithSameConfigPointExists(const EipUint32 config_point) {
 
   while (NULL != node) {
     CipConnectionObject *connection = node->data;
+    OPENER_ASSERT(NULL != connection);
     if (config_point == connection->configuration_path.instance_id) {
       return (NULL != connection);
     }

+ 4 - 2
source/src/cip/cipassembly.c

@@ -22,7 +22,8 @@ EipStatus SetAssemblyAttributeSingle(
   CipInstance *const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 /** @brief Constructor for the assembly object class
  *
@@ -124,7 +125,8 @@ EipStatus SetAssemblyAttributeSingle(
   CipInstance *const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
   OPENER_TRACE_INFO(" setAttribute %d\n",
                     message_router_request->request_path.attribute_number);
 

+ 9 - 1
source/src/cip/cipclass3connection.c

@@ -8,12 +8,20 @@
 
 #include "cipclass3connection.h"
 
+#include "encap.h"
+
 /**** Global variables ****/
 extern CipConnectionObject explicit_connection_object_pool[
   OPENER_CIP_NUM_EXPLICIT_CONNS];
 
 CipConnectionObject *GetFreeExplicitConnection(void);
 
+void Class3ConnectionTimeoutHandler(CipConnectionObject *connection_object) {
+  CheckForTimedOutConnectionsAndCloseTCPConnections(connection_object,
+                                                    CloseSessionBySessionHandle);
+  CloseConnection(connection_object);
+}
+
 /**** Implementation ****/
 EipStatus EstablishClass3Connection(
   CipConnectionObject *RESTRICT const connection_object,
@@ -42,7 +50,7 @@ EipStatus EstablishClass3Connection(
       CloseConnection;
     /* explicit connection have to be closed on time out*/
     explicit_connection->connection_timeout_function =
-      CloseConnection;
+      Class3ConnectionTimeoutHandler;
 
     AddNewActiveConnection(explicit_connection);
   }

+ 15 - 9
source/src/cip/cipcommon.c

@@ -74,7 +74,8 @@ void ShutdownCipStack(void) {
 EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
                       CipMessageRouterRequest *const message_router_request,
                       CipMessageRouterResponse *const message_router_response,
-                      struct sockaddr *originator_address) {
+                      struct sockaddr *originator_address,
+                      const int encapsulation_session) {
 
   /* find the instance: if instNr==0, the class is addressed, else find the instance */
   EipUint16 instance_number = message_router_request->request_path
@@ -97,7 +98,8 @@ EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
           OPENER_ASSERT(NULL != service->service_function);
           return service->service_function(instance, message_router_request,
                                            message_router_response,
-                                           originator_address);
+                                           originator_address,
+                                           encapsulation_session);
         } else {
           service++;
         }
@@ -136,8 +138,8 @@ CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class,
     instance_number++; /*    keep track of what the first new instance number will be */
   }
 
-  CipInstance *current_instance = current_instance = (CipInstance *) CipCalloc(
-                                    number_of_instances, sizeof(CipInstance) ); /* allocate a block of memory for all created instances*/
+  CipInstance *current_instance = (CipInstance *) CipCalloc(
+    number_of_instances, sizeof(CipInstance) );                                 /* allocate a block of memory for all created instances*/
   CipInstance *first_instance = current_instance; /* allocate a block of memory for all created instances*/
 
   OPENER_ASSERT(NULL != current_instance);
@@ -170,7 +172,7 @@ CipInstance *AddCIPInstance(CipClass *RESTRICT const class,
                             const EipUint32 instance_id) {
   CipInstance *instance = GetCipInstance(class, instance_id);
 
-  if (0 == instance) { /*we have no instance with given id*/
+  if (NULL == instance) { /*we have no instance with given id*/
     instance = AddCipInstances(class, 1);
     instance->instance_number = instance_id;
   }
@@ -383,7 +385,8 @@ EipStatus GetAttributeSingle(
   CipInstance *RESTRICT const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
   /* Mask for filtering get-ability */
 
   CipAttributeStruct *attribute = GetCipAttribute(
@@ -680,7 +683,8 @@ int DecodeData(const EipUint8 cip_type,
 EipStatus GetAttributeAll(CipInstance *instance,
                           CipMessageRouterRequest *message_router_request,
                           CipMessageRouterResponse *message_router_response,
-                          struct sockaddr *originator_address) {
+                          struct sockaddr *originator_address,
+                          const int encapsulation_session) {
 
   EipUint8 *reply = message_router_response->data; /* pointer into the reply */
   CipAttributeStruct *attribute = instance->attributes; /* pointer to list of attributes*/
@@ -714,7 +718,8 @@ EipStatus GetAttributeAll(CipInstance *instance,
             if ( kEipStatusOkSend
                  != service->service_function(instance, message_router_request,
                                               message_router_response,
-                                              originator_address) ) {
+                                              originator_address,
+                                              encapsulation_session) ) {
               message_router_response->data = reply;
               return kEipStatusError;
             }
@@ -961,7 +966,8 @@ size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
       break;
     case (kCipStringN): {
       CipStringN *data = (CipStringN *) attribute_struct->data;
-      return sizeof(CipUint) + sizeof(CipUint) + (data->length) * (data->size);
+      return sizeof(CipUint) + sizeof(CipUint) + (size_t)(data->length) *
+             (size_t)(data->size);
     }
     break;
     case (kCipShortString): {

+ 6 - 3
source/src/cip/cipcommon.h

@@ -36,7 +36,8 @@ static const EipUint16 kCipUintZero = 0; /**< Zero value for returning the UINT
 EipStatus NotifyClass(const CipClass *const RESTRICT cip_class,
                       CipMessageRouterRequest *const message_router_request,
                       CipMessageRouterResponse *const message_router_response,
-                      struct sockaddr *originator_address);
+                      struct sockaddr *originator_address,
+                      const int encapsulation_session);
 
 /** @brief Generic implementation of the GetAttributeSingle CIP service
  *
@@ -54,7 +55,8 @@ EipStatus GetAttributeSingle(
   message_router_request,
   CipMessageRouterResponse *const
   message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 /** @brief Generic implementation of the GetAttributeAll CIP service
  *
@@ -68,7 +70,8 @@ EipStatus GetAttributeSingle(
 EipStatus GetAttributeAll(CipInstance *instance,
                           CipMessageRouterRequest *message_router_request,
                           CipMessageRouterResponse *message_router_response,
-                          struct sockaddr *originator_address);
+                          struct sockaddr *originator_address,
+                          const int encapsulation_session);
 
 /** @brief Decodes padded EPath
  *  @param epath EPath to the receiving element

+ 38 - 8
source/src/cip/cipconnectionmanager.c

@@ -66,19 +66,22 @@ EipStatus ForwardOpen(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 EipStatus ForwardClose(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 EipStatus GetConnectionOwner(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 EipStatus AssembleForwardOpenResponse(
   CipConnectionObject *connection_object,
@@ -266,6 +269,7 @@ EipStatus HandleReceivedConnectedData(
         /* only handle the data if it is coming from the originator */
         if (connection_object->originator_address.sin_addr.s_addr
             == from_address->sin_addr.s_addr) {
+          ConnectionObjectResetLastPackageInactivityTimerValue(connection_object);
 
           if ( SEQ_GT32(
                  g_common_packet_format_data_item.address_item.data.
@@ -487,7 +491,8 @@ EipStatus ForwardOpen(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address
+  struct sockaddr *originator_address,
+  const int encapsulation_session
   ) {
   (void) instance; /*suppress compiler warning */
 
@@ -497,6 +502,8 @@ EipStatus ForwardOpen(
   /*first check if we have already a connection with the given params */
   ConnectionObjectInitializeFromMessage(&(message_router_request->data),
                                         &g_dummy_connection_object);
+  g_dummy_connection_object.associated_encapsulation_session =
+    encapsulation_session;
 
   memcpy( &(g_dummy_connection_object.originator_address), originator_address,
           sizeof(g_dummy_connection_object.originator_address) );
@@ -552,8 +559,8 @@ EipStatus ForwardClose(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address
-  ) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
   /*Suppress compiler warning*/
   (void) instance;
 
@@ -628,8 +635,8 @@ EipStatus GetConnectionOwner(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address
-  ) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
   /* suppress compiler warnings */
   (void) instance;
   (void) message_router_request;
@@ -663,6 +670,7 @@ EipStatus ManageConnections(MilliSeconds elapsed_time) {
           connection_object->connection_timeout_function(connection_object);
         } else {
           connection_object->inactivity_watchdog_timer -= elapsed_time;
+          connection_object->last_package_watchdog_timer -= elapsed_time;
         }
       }
       /* only if the connection has not timed out check if data is to be send */
@@ -1493,6 +1501,28 @@ EipStatus TriggerConnections(
   return status;
 }
 
+void CheckForTimedOutConnectionsAndCloseTCPConnections(
+  const CipConnectionObject *const connection_object,
+  CloseSessionFunction CloseSessions) {
+
+  DoublyLinkedListNode *search_node = connection_list.first;
+  bool non_timed_out_connection_found = false;
+  while(NULL != search_node) {
+    CipConnectionObject *search_connection = search_node->data;
+    if(ConnectionObjectEqualOriginator(connection_object, search_connection)
+       && connection_object != search_connection
+       && kConnectionObjectStateTimedOut !=
+       ConnectionObjectGetState(search_connection) ) {
+      non_timed_out_connection_found = true;
+      break;
+    }
+    search_node = search_node->next;
+  }
+  if(false == non_timed_out_connection_found) {
+    CloseSessions(connection_object);
+  }
+}
+
 void InitializeConnectionManagerData() {
   memset( g_connection_management_list, 0,
           g_kNumberOfConnectableObjects *

+ 7 - 0
source/src/cip/cipconnectionmanager.h

@@ -222,4 +222,11 @@ void RemoveFromActiveConnections(CipConnectionObject *const connection_object);
 
 CipUint GetConnectionId(void);
 
+typedef void (*CloseSessionFunction)(const CipConnectionObject *const
+                                     connection_object);
+
+void CheckForTimedOutConnectionsAndCloseTCPConnections(
+  const CipConnectionObject *const connection_object,
+  CloseSessionFunction CloseSessions);
+
 #endif /* OPENER_CIPCONNECTIONMANAGER_H_ */

+ 29 - 7
source/src/cip/cipconnectionobject.c

@@ -73,11 +73,14 @@ DoublyLinkedListNode *CipConnectionObjectListArrayAllocator() {
 
 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");
+  if(NULL != node) {
+    if(NULL != *node) {
+      memset( *node, 0, sizeof(DoublyLinkedListNode) );
+      *node = NULL;
+    } else {
+      OPENER_TRACE_ERR("Attempt to delete NULL pointer to node\n");
+    }
+    OPENER_TRACE_ERR("Attempt to provide a NULL pointer to node pointer\n");
   }
 
 }
@@ -546,10 +549,18 @@ void ConnectionObjectResetInactivityWatchdogTimerValue(
       connection_object);
 }
 
+void ConnectionObjectResetLastPackageInactivityTimerValue(
+  CipConnectionObject *const connection_object) {
+  connection_object->last_package_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) );
+  return ( ( (uint64_t)(connection_object->o_to_t_requested_packet_interval) /
+             (uint64_t)1000 ) <<
+           (2 + connection_object->connection_timeout_multiplier) );
 }
 
 
@@ -786,6 +797,17 @@ void ConnectionObjectGeneralConfiguration(
   connection_object->transmission_trigger_timer = 0;
 }
 
+bool ConnectionObjectEqualOriginator(const CipConnectionObject *const object1,
+                                     const CipConnectionObject *const object2) {
+  if ( (object1->originator_vendor_id
+        == object2->originator_vendor_id)
+       && (object1->originator_serial_number
+           == object2->originator_serial_number) ) {
+    return true;
+  }
+  return false;
+}
+
 bool EqualConnectionTriad(const CipConnectionObject *const object1,
                           const CipConnectionObject *const object2) {
   if ( (object1->connection_serial_number

+ 10 - 1
source/src/cip/cipconnectionobject.h

@@ -136,6 +136,7 @@ struct cip_connection_object {
 
   uint64_t transmission_trigger_timer;
   uint64_t inactivity_watchdog_timer;
+  uint64_t last_package_watchdog_timer;
   uint64_t production_inhibit_timer;
 
   CipUint connection_serial_number;
@@ -176,6 +177,8 @@ struct cip_connection_object {
                                               for scanning if the right packet is
                                               arriving */
 
+  size_t associated_encapsulation_session; /* The session handle ID via which the forward open was sent */
+
   /* pointers to connection handling functions */
   CipConnectionStateHandler current_state_handler;
 
@@ -323,7 +326,10 @@ void ConnectionObjectSetConnectionTimeoutMultiplier(
   connection_timeout_multiplier);
 
 void ConnectionObjectResetInactivityWatchdogTimerValue(
-  CipConnectionObject *connection_object);
+  CipConnectionObject *const connection_object);
+
+void ConnectionObjectResetLastPackageInactivityTimerValue(
+  CipConnectionObject *const connection_object);
 
 CipUint ConnectionObjectGetConnectionSerialNumber(
   const CipConnectionObject *const connection_object);
@@ -414,6 +420,9 @@ void ConnectionObjectGeneralConfiguration(
 bool ConnectionObjectIsTypeIOConnection(
   const CipConnectionObject *const connection_object);
 
+bool ConnectionObjectEqualOriginator(const CipConnectionObject *const object1,
+                                     const CipConnectionObject *const object2);
+
 bool EqualConnectionTriad(const CipConnectionObject *const object1,
                           const CipConnectionObject *const object2);
 

+ 7 - 3
source/src/cip/cipethernetlink.c

@@ -38,7 +38,8 @@ EipStatus GetAttributeSingleEthernetLink(
   CipInstance *RESTRICT const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 /** @bried Configures the MAC address of the Ethernet Link object*
  *
@@ -175,7 +176,8 @@ EipStatus GetAttributeSingleEthernetLink(
   CipInstance *RESTRICT const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
   /* Mask for filtering get-ability */
 
   CipAttributeStruct *attribute = GetCipAttribute(
@@ -229,7 +231,9 @@ EipStatus GetAttributeSingleEthernetLink(
 
         default:
           GetAttributeSingle(instance, message_router_request,
-                             message_router_response, originator_address);
+                             message_router_response,
+                             originator_address,
+                             encapsulation_session);
       }
 
     }

+ 2 - 1
source/src/cip/cipethernetlink.h

@@ -30,7 +30,8 @@ EipStatus GetAttributeSingleEthernetLink(
   CipInstance *RESTRICT const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 /** @brief Data of an CIP Ethernet Link object */
 typedef struct {

+ 3 - 2
source/src/cip/cipidentity.c

@@ -72,8 +72,9 @@ static EipStatus Reset(CipInstance *instance,
 /* pointer to instance*/
                        CipMessageRouterRequest *message_router_request,
                        /* pointer to message router request*/
-                       CipMessageRouterResponse *message_router_response,
-                       struct sockaddr *originator_address) { /* pointer to message router response*/
+                       CipMessageRouterResponse *message_router_response,  /* pointer to message router response*/
+                       struct sockaddr *originator_address,
+                       const int encapsulation_session) {
   (void) instance;
 
   EipStatus eip_status = kEipStatusOkSend;

+ 11 - 4
source/src/cip/cipioconnection.c

@@ -620,12 +620,15 @@ EipUint16 HandleConfigData(CipConnectionObject *connection_object) {
     assembly_class, connection_object->configuration_path.instance_id);
 
   if (0 != g_config_data_length) {
+    OPENER_ASSERT(NULL != config_instance);
     if ( ConnectionWithSameConfigPointExists(
-           connection_object->configuration_path.instance_id) ) {                                               /* there is a connected connection with the same config point
-                                                                                                                 * we have to have the same data as already present in the config point*/
+           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;
+      OPENER_ASSERT(NULL != attribute_three);
       if (attribute_three->length != g_config_data_length) {
         connection_manager_status =
           kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
@@ -713,6 +716,12 @@ void HandleIoConnectionTimeOut(CipConnectionObject *connection_object) {
                          connection_object->consumed_path.instance_id,
                          kIoConnectionEventTimedOut);
 
+  if(connection_object->last_package_watchdog_timer ==
+     connection_object->inactivity_watchdog_timer) {
+    CheckForTimedOutConnectionsAndCloseTCPConnections(connection_object,
+                                                      CloseEncapsulationSessionBySockAddr);
+  }
+
   if ( kConnectionObjectConnectionTypeMulticast
        == ConnectionObjectGetTToOConnectionType(connection_object) ) {
     switch (ConnectionObjectGetInstanceType(connection_object) ) {
@@ -751,8 +760,6 @@ void HandleIoConnectionTimeOut(CipConnectionObject *connection_object) {
   }
 
   ConnectionObjectSetState(connection_object, kConnectionObjectStateTimedOut);
-//  OPENER_ASSERT(NULL != connection_object->connection_close_function);
-//  connection_object->connection_close_function(connection_object);
 }
 
 EipStatus SendConnectedData(CipConnectionObject *connection_object) {

+ 5 - 2
source/src/cip/cipmessagerouter.c

@@ -172,7 +172,8 @@ EipStatus RegisterCipClass(CipClass *cip_class) {
 
 EipStatus NotifyMessageRouter(EipUint8 *data,
                               int data_length,
-                              struct sockaddr *originator_address) {
+                              struct sockaddr *originator_address,
+                              const int encapsulation_session) {
   EipStatus eip_status = kEipStatusOkSend;
   EipByte status = kCipErrorSuccess;
 
@@ -217,7 +218,9 @@ EipStatus NotifyMessageRouter(EipUint8 *data,
         registered_object->cip_class->class_name);
       eip_status = NotifyClass(registered_object->cip_class,
                                &g_message_router_request,
-                               &g_message_router_response, originator_address);
+                               &g_message_router_response,
+                               originator_address,
+                               encapsulation_session);
 
 #ifdef OPENER_TRACE_ENABLED
       if (eip_status == kEipStatusError) {

+ 2 - 1
source/src/cip/cipmessagerouter.h

@@ -40,7 +40,8 @@ void DeleteAllClasses(void);
  */
 EipStatus NotifyMessageRouter(EipUint8 *data,
                               int data_length,
-                              struct sockaddr *originator_address);
+                              struct sockaddr *originator_address,
+                              const int encapsulation_session);
 
 /*! Register a class at the message router.
  *  In order that the message router can deliver

+ 6 - 3
source/src/cip/cipqos.c

@@ -30,17 +30,20 @@ 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,
+  const int encapsulation_session) {
 
   return GetAttributeSingle(instance, message_router_request,
-                            message_router_response, originator_address);
+                            message_router_response, originator_address,
+                            encapsulation_session);
 }
 
 EipStatus SetAttributeSingleQoS(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
 
   CipAttributeStruct *attribute = GetCipAttribute(
     instance, message_router_request->request_path.attribute_number);

+ 13 - 6
source/src/cip/ciptcpipinterface.c

@@ -67,19 +67,22 @@ EipStatus GetAttributeSingleTcpIpInterface(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 EipStatus GetAttributeAllTcpIpInterface(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 EipStatus SetAttributeSingleTcp(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
   CipAttributeStruct *attribute = GetCipAttribute(
     instance, message_router_request->request_path.attribute_number);
   (void) instance; /*Suppress compiler warning */
@@ -226,7 +229,8 @@ EipStatus GetAttributeSingleTcpIpInterface(
   CipInstance *const RESTRICT instance,
   CipMessageRouterRequest *RESTRICT const message_router_request,
   CipMessageRouterResponse *RESTRICT const message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
 
   EipStatus status = kEipStatusOkSend;
   EipByte *message = message_router_response->data;
@@ -323,7 +327,8 @@ EipStatus GetAttributeAllTcpIpInterface(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
   CipMessageRouterResponse *message_router_response,
-  struct sockaddr *originator_address) {
+  struct sockaddr *originator_address,
+  const int encapsulation_session) {
 
   EipUint8 *response = message_router_response->data; /* pointer into the reply */
   CipAttributeStruct *attribute = instance->attributes;
@@ -343,7 +348,8 @@ EipStatus GetAttributeAllTcpIpInterface(
       if ( kEipStatusOkSend
            != GetAttributeSingleTcpIpInterface(instance, message_router_request,
                                                message_router_response,
-                                               originator_address) ) {
+                                               originator_address,
+                                               encapsulation_session) ) {
         message_router_response->data = response;
         return kEipStatusError;
       }
@@ -378,6 +384,7 @@ EipStatus GetAttributeAllTcpIpInterface(
 
 EipUint16 GetEncapsulationInactivityTimeout(CipInstance *instance) {
   CipAttributeStruct *attribute = GetCipAttribute(instance, 13);
+  OPENER_ASSERT(NULL != attribute);
   CipUint *data = (CipUint *) attribute->data;
   EipUint16 encapsulation_inactivity_timeout = *data;
   return encapsulation_inactivity_timeout;

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

@@ -273,7 +273,8 @@ typedef EipStatus (*CipServiceFunction)(
   CipInstance *const instance,
   CipMessageRouterRequest *const message_router_request,
   CipMessageRouterResponse *const message_router_response,
-  struct sockaddr *originator_address);
+  struct sockaddr *originator_address,
+  const int encapsulation_session);
 
 /** @brief Service descriptor. These are stored in an array */
 typedef struct cip_service_struct {

+ 33 - 29
source/src/enet_encap/cpf.c

@@ -42,7 +42,8 @@ int NotifyCommonPacketFormat(EncapsulationData *const receive_data,
         return_value = NotifyMessageRouter(
           g_common_packet_format_data_item.data_item.data,
           g_common_packet_format_data_item.data_item.length,
-          originator_address);
+          originator_address,
+          receive_data->session_handle);
         if (return_value != kEipStatusError) {
           return_value = AssembleLinearMessage(
             &g_message_router_response, &g_common_packet_format_data_item,
@@ -94,7 +95,8 @@ int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
           return_value = NotifyMessageRouter(
             buffer,
             g_common_packet_format_data_item.data_item.length - 2,
-            originator_address);
+            originator_address,
+            received_data->session_handle);
 
           if (return_value != kEipStatusError) {
             g_common_packet_format_data_item.address_item.data
@@ -162,34 +164,36 @@ EipStatus CreateCommonPacketFormatStructure(
     common_packet_format_data->data_item.data = (EipUint8 *)data;
     data += common_packet_format_data->data_item.length;
     length_count += (4 + common_packet_format_data->data_item.length);
-  }
-  for (int j = 0; j < (common_packet_format_data->item_count - 2); j++) /* TODO there needs to be a limit check here???*/
-  {
-    common_packet_format_data->address_info_item[j].type_id = GetIntFromMessage(
-      &data);
-    OPENER_TRACE_INFO("Sockaddr type id: %x\n",
-                      common_packet_format_data->address_info_item[j].type_id);
-    length_count += 2;
-    if ( (common_packet_format_data->address_info_item[j].type_id
-          == kCipItemIdSocketAddressInfoOriginatorToTarget)
-         || (common_packet_format_data->address_info_item[j].type_id
-             == kCipItemIdSocketAddressInfoTargetToOriginator) ) {
-      common_packet_format_data->address_info_item[j].length =
-        GetIntFromMessage(&data);
-      common_packet_format_data->address_info_item[j].sin_family =
-        GetIntFromMessage(&data);
-      common_packet_format_data->address_info_item[j].sin_port =
-        GetIntFromMessage(&data);
-      common_packet_format_data->address_info_item[j].sin_addr =
-        GetDintFromMessage(&data);
-      for (int i = 0; i < 8; i++) {
-        common_packet_format_data->address_info_item[j].nasin_zero[i] = *data;
-        data++;
+
+    for (size_t j = 0; j < (common_packet_format_data->item_count - 2); j++) /* TODO there needs to be a limit check here???*/
+    {
+      common_packet_format_data->address_info_item[j].type_id =
+        GetIntFromMessage(
+          &data);
+      OPENER_TRACE_INFO("Sockaddr type id: %x\n",
+                        common_packet_format_data->address_info_item[j].type_id);
+      length_count += 2;
+      if ( (common_packet_format_data->address_info_item[j].type_id
+            == kCipItemIdSocketAddressInfoOriginatorToTarget)
+           || (common_packet_format_data->address_info_item[j].type_id
+               == kCipItemIdSocketAddressInfoTargetToOriginator) ) {
+        common_packet_format_data->address_info_item[j].length =
+          GetIntFromMessage(&data);
+        common_packet_format_data->address_info_item[j].sin_family =
+          GetIntFromMessage(&data);
+        common_packet_format_data->address_info_item[j].sin_port =
+          GetIntFromMessage(&data);
+        common_packet_format_data->address_info_item[j].sin_addr =
+          GetDintFromMessage(&data);
+        for (size_t i = 0; i < 8; i++) {
+          common_packet_format_data->address_info_item[j].nasin_zero[i] = *data;
+          data++;
+        }
+        length_count += 18;
+      } else { /* no sockaddr item found */
+        common_packet_format_data->address_info_item[j].type_id = 0; /* mark as not set */
+        data -= 2;
       }
-      length_count += 18;
-    } else { /* no sockaddr item found */
-      common_packet_format_data->address_info_item[j].type_id = 0; /* mark as not set */
-      data -= 2;
     }
   }
   /* set the addressInfoItems to not set if they were not received */

+ 60 - 0
source/src/enet_encap/encap.c

@@ -19,6 +19,7 @@
 #include "generic_networkhandler.h"
 #include "trace.h"
 #include "socket_timer.h"
+#include "opener_error.h"
 
 /*Identity data from cipidentity.c*/
 extern EipUint16 vendor_id_;
@@ -525,6 +526,7 @@ EipStatus HandleReceivedUnregisterSessionCommand(EncapsulationData *receive_data
     if (kEipInvalidSocket != g_registered_sessions[i]) {
       CloseTcpSocket(g_registered_sessions[i]);
       g_registered_sessions[i] = kEipInvalidSocket;
+      CloseClass3ConnectionBasedOnSession(i + 1);
       return kEipStatusOk;
     }
   }
@@ -676,12 +678,22 @@ SessionStatus CheckRegisteredSessions(EncapsulationData *receive_data) {
   return kSessionStatusInvalid;
 }
 
+void CloseSessionBySessionHandle(
+  const CipConnectionObject *const connection_object) {
+  OPENER_TRACE_INFO("encap.c: Close session by handle\n");
+  size_t session_handle = connection_object->associated_encapsulation_session;
+  CloseTcpSocket(g_registered_sessions[session_handle - 1]);
+  g_registered_sessions[session_handle - 1] = kEipInvalidSocket;
+  OPENER_TRACE_INFO("encap.c: Close session by handle done\n");
+}
+
 void CloseSession(int socket) {
   OPENER_TRACE_INFO("encap.c: Close session\n");
   for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
     if (g_registered_sessions[i] == socket) {
       CloseTcpSocket(socket);
       g_registered_sessions[i] = kEipInvalidSocket;
+      CloseClass3ConnectionBasedOnSession(i + 1);
       break;
     }
   }
@@ -693,6 +705,7 @@ void RemoveSession(const int socket) {
   for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
     if (g_registered_sessions[i] == socket) {
       g_registered_sessions[i] = kEipInvalidSocket;
+      CloseClass3ConnectionBasedOnSession(i + 1);
       break;
     }
   }
@@ -726,3 +739,50 @@ void ManageEncapsulationMessages(const MilliSeconds elapsed_time) {
     }
   }
 }
+
+void CloseEncapsulationSessionBySockAddr(
+  const CipConnectionObject *const connection_object) {
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if (kEipInvalidSocket != g_registered_sessions[i]) {
+      struct sockaddr_in encapsulation_session_addr = {0};
+      socklen_t addrlength = sizeof(encapsulation_session_addr);
+      if (getpeername(g_registered_sessions[i], &encapsulation_session_addr,
+                      &addrlength) <= 0) {                                                                  /* got error */
+        int error_code = GetSocketErrorNumber();
+        char *error_message = GetErrorMessage(error_code);
+        OPENER_TRACE_ERR(
+          "encap.c: error on getting peer name on closing session: %d - %s\n",
+          error_code,
+          error_message);
+        FreeErrorMessage(error_message);
+      }
+      if(encapsulation_session_addr.sin_addr.s_addr ==
+         connection_object->originator_address.sin_addr.s_addr) {
+        CloseSession(g_registered_sessions[i]);
+      }
+    }
+  }
+}
+
+size_t GetSessionFromSocket(const int socket_handle) {
+  for (size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
+    if(socket_handle == g_registered_sessions[i]) {
+      return i;
+    }
+  }
+  return OPENER_NUMBER_OF_SUPPORTED_SESSIONS;
+}
+
+void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle) {
+  DoublyLinkedListNode *node = connection_list.first;
+  while(NULL != node) {
+    CipConnectionObject *connection_object = node->data;
+    if(kConnectionObjectTransportClassTriggerTransportClass3 ==
+       ConnectionObjectGetTransportClassTriggerTransportClass(connection_object)
+       && connection_object->associated_encapsulation_session ==
+       encapsulation_session_handle ) {
+      connection_object->connection_close_function(connection_object);
+    }
+    node = node->next;
+  }
+}

+ 11 - 0
source/src/enet_encap/encap.h

@@ -7,6 +7,7 @@
 #define OPENER_ENCAP_H_
 
 #include "typedefs.h"
+#include "cipconnectionobject.h"
 
 /** @file encap.h
  * @brief This file contains the public interface of the encapsulation layer
@@ -80,6 +81,16 @@ void EncapsulationShutDown(void);
  */
 void ManageEncapsulationMessages(const MilliSeconds elapsed_time);
 
+size_t GetSessionFromSocket(const int socket_handle);
+
 void RemoveSession(const int socket);
 
+void CloseSessionBySessionHandle(
+  const CipConnectionObject *const connection_object);
+
+void CloseEncapsulationSessionBySockAddr(
+  const CipConnectionObject *const connection_object);
+
+void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle);
+
 #endif /* OPENER_ENCAP_H_ */

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

@@ -42,6 +42,7 @@ void ConfigureMacAddress(const char *interface) {
     memcpy( &(g_ethernet_link.physical_address), &ifr.ifr_hwaddr.sa_data,
             sizeof(g_ethernet_link.physical_address) );
   }
+  CloseSocket(fd);
 }
 
 EipStatus ConfigureNetworkInterface(const char *const network_interface) {
@@ -104,6 +105,8 @@ EipStatus ConfigureNetworkInterface(const char *const network_interface) {
   g_multicast_configuration.starting_multicast_address = htonl(
     ntohl( inet_addr("239.192.1.0") ) + (host_id << 5) );
 
+  CloseSocket(fd);
+
   return kEipStatusOk;
 }
 

+ 4 - 3
source/src/ports/POSIX/networkhandler.c

@@ -53,9 +53,10 @@ int SetSocketToNonBlocking(int socket_handle) {
                                              0) | O_NONBLOCK);
 }
 
-void SetQosOnSocket(int socket,
-                    CipUsint qos_value) {
+//TODO: Return setsocket return value
+int SetQosOnSocket(int socket,
+                   CipUsint qos_value) {
 
   int set_tos = qos_value;
-  setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos) );
+  return setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos) );
 }

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

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

+ 64 - 11
source/src/ports/generic_networkhandler.c

@@ -96,7 +96,11 @@ EipStatus NetworkHandlerInitialize(void) {
     return kEipStatusError;
   }
 
-  SetSocketToNonBlocking(g_network_status.tcp_listener);
+  if (SetSocketToNonBlocking(g_network_status.tcp_listener) < 0) {
+    OPENER_TRACE_ERR(
+      "error setting socket to non-blocking on new socket\n");
+    return kEipStatusError;
+  }
 
   /* create a new UDP socket */
   if ( ( g_network_status.udp_global_broadcast_listener = socket(AF_INET,
@@ -134,7 +138,12 @@ EipStatus NetworkHandlerInitialize(void) {
     return kEipStatusError;
   }
 
-  SetSocketToNonBlocking(g_network_status.udp_global_broadcast_listener);
+  if (SetSocketToNonBlocking(g_network_status.udp_global_broadcast_listener) <
+      0) {
+    OPENER_TRACE_ERR(
+      "error setting socket to non-blocking on new socket\n");
+    return kEipStatusError;
+  }
 
   /* Activates address reuse */
   if (setsockopt( g_network_status.udp_unicast_listener, SOL_SOCKET,
@@ -145,7 +154,11 @@ EipStatus NetworkHandlerInitialize(void) {
     return kEipStatusError;
   }
 
-  SetSocketToNonBlocking(g_network_status.udp_unicast_listener);
+  if (SetSocketToNonBlocking(g_network_status.udp_unicast_listener) < 0) {
+    OPENER_TRACE_ERR(
+      "error setting socket to non-blocking on udp_unicast_listener\n");
+    return kEipStatusError;
+  }
 
   struct sockaddr_in my_address = { .sin_family = AF_INET, .sin_port = htons(
                                       kOpenerEthernetPort),
@@ -289,7 +302,16 @@ void CheckAndHandleTcpListenerSocket(void) {
       return;
     }
 
-    SetQosOnSocket( new_socket, GetPriorityForSocket(0xFFF) );
+    if (SetQosOnSocket( new_socket, GetPriorityForSocket(0xFFF) ) <= 0) { /* got error */
+      int error_code = GetSocketErrorNumber();
+      char *error_message = GetErrorMessage(error_code);
+      OPENER_TRACE_ERR(
+        "networkhandler: error on set QoS on on new socket %d: %d - %s\n",
+        new_socket,
+        error_code,
+        error_message);
+      FreeErrorMessage(error_message);
+    }
 
     OPENER_TRACE_INFO(">>> network handler: accepting new TCP socket: %d \n",
                       new_socket);
@@ -370,11 +392,15 @@ EipStatus NetworkHandlerProcessOnce(void) {
     CheckEncapsulationInactivity(socket);
   }
 
+  /* Check if all connections from one originator times out */
+  //CheckForTimedOutConnectionsAndCloseTCPConnections();
+
   //OPENER_TRACE_INFO("Socket Loop done\n");
 
   g_actual_time = GetMilliSeconds();
   g_network_status.elapsed_time += g_actual_time - g_last_time;
   g_last_time = g_actual_time;
+  //OPENER_TRACE_INFO("Elapsed time: %u\n", g_network_status.elapsed_time);
 
   /* check if we had been not able to update the connection manager for several OPENER_TIMER_TICK.
    * This should compensate the jitter of the windows timer
@@ -631,7 +657,6 @@ EipStatus HandleDataOnTcpSocket(int socket) {
       }
     } while (0 < data_size);
     SocketTimerSetLastUpdate(socket_timer, g_actual_time);
-    OPENER_ASSERT(0 <= data_size);
     return kEipStatusOk;
   }
 
@@ -676,7 +701,14 @@ EipStatus HandleDataOnTcpSocket(int socket) {
     struct sockaddr sender_address;
     memset( &sender_address, 0, sizeof(sender_address) );
     socklen_t fromlen = sizeof(sender_address);
-    getpeername(socket, (struct sockaddr *)&sender_address, &fromlen);
+    if (getpeername(socket, (struct sockaddr *)&sender_address, &fromlen) < 0) {
+      int error_code = GetSocketErrorNumber();
+      char *error_message = GetErrorMessage(error_code);
+      OPENER_TRACE_ERR("networkhandler: could not get peername: %d - %s\n",
+                       error_code,
+                       error_message);
+      FreeErrorMessage(error_message);
+    }
 
     number_of_read_bytes = HandleReceivedExplictTcpData(
       socket, g_ethernet_communication_buffer, data_size, &remaining_bytes,
@@ -738,18 +770,32 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
 
   socklen_t peer_address_length = sizeof(struct sockaddr_in);
   /* create a new UDP socket */
-  if ( ( new_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) ) == -1 ) {
+  if ( ( new_socket =
+           socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) ) == kEipInvalidSocket ) {
     int error_code = GetSocketErrorNumber();
     char *error_message = GetErrorMessage(error_code);
     OPENER_TRACE_ERR("networkhandler: cannot create UDP socket: %d- %s\n",
                      error_code,
                      error_message);
     FreeErrorMessage(error_message);
-    return kEipInvalidSocket;
+    return new_socket;
   }
 
-  SetSocketToNonBlocking(new_socket);
-  SetQosOnSocket(new_socket, GetPriorityForSocket(qos_for_socket) );
+  if (SetSocketToNonBlocking(new_socket) < 0) {
+    OPENER_TRACE_ERR(
+      "error setting socket to non-blocking on new socket\n");
+    return kEipStatusError;
+  }
+
+  if (SetQosOnSocket(new_socket, GetPriorityForSocket(qos_for_socket) ) <= 0) { /* got error */
+    int error_code = GetSocketErrorNumber();
+    char *error_message = GetErrorMessage(error_code);
+    OPENER_TRACE_ERR(
+      "networkhandler: error on set QoS on socket on new socket: %d - %s\n",
+      error_code,
+      error_message);
+    FreeErrorMessage(error_message);
+  }
 
   OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", new_socket);
 
@@ -772,6 +818,7 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
       OPENER_TRACE_ERR("error on bind udp: %d - %s\n", error_code,
                        error_message);
       FreeErrorMessage(error_message);
+      CloseSocket(new_socket);
       return kEipInvalidSocket;
     }
 
@@ -783,7 +830,7 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
       if (1 != g_time_to_live_value) { /* we need to set a TTL value for the socket */
         if ( setsockopt(new_socket, IPPROTO_IP, IP_MULTICAST_TTL,
                         &g_time_to_live_value,
-                        sizeof(g_time_to_live_value) < 0) ) {
+                        sizeof(g_time_to_live_value) ) < 0 ) {
           int error_code = GetSocketErrorNumber();
           char *error_message = GetErrorMessage(error_code);
           OPENER_TRACE_ERR(
@@ -930,6 +977,12 @@ void CheckEncapsulationInactivity(int socket_handle) {
 
       if ( diff_milliseconds >=
            (MilliSeconds) (1000UL * g_encapsulation_inactivity_timeout) ) {
+
+        size_t encapsulation_session_handle =
+          GetSessionFromSocket(socket_handle);
+
+        CloseClass3ConnectionBasedOnSession(encapsulation_session_handle);
+
         CloseTcpSocket(socket_handle);
         RemoveSession(socket_handle);
       }