Forráskód Böngészése

implemented support for heartbeat connections; fixed some issues with peer-to-peer connections

Alois Zoitl 16 éve
szülő
commit
e393477cde

+ 6 - 1
TODO

@@ -1,6 +1,7 @@
 This file serves as brainstorming buffer for ideas to improve and enhance OpENer:
 
 * New Features:
+  - Call-back interface to inform application on connection time outs
   - Change of State and application triggered connections
   - Implementation of common CIP-objects
   - CIP-Sync
@@ -15,7 +16,11 @@ This file serves as brainstorming buffer for ideas to improve and enhance OpENer
   - Rework I/O message handling:
      - own buffers for each connection that are preconfigured and only runtime 
        data needs to be changed.
-     - Use only one single outgoing UDP socket for I/O messages  
+  - Rework socket handling 
+     - Use only one single UDP socket for all I/O messages
+         - may not be possible for point to point consuming connections where
+           the scanner gives a different port number
+     - use the registered port number 2222 for all I/O communication 
      
      
 * Documentation

+ 6 - 2
src/cip/cipcommon.c

@@ -298,8 +298,9 @@ insertAttribute(S_CIP_Instance * pa_pInstance, EIP_UINT8 pa_nAttributeNr,
         }
       p++;
     }
+  OPENER_TRACE_ERR("Tried to insert to many attributes into class: %d, instance %d\n", pa_pInstance->pstClass->nInstanceNr, pa_pInstance->nInstanceNr );
   assert(0);
-  /* trying to insert too mmany attributes*/
+  /* trying to insert too many attributes*/
 }
 
 void
@@ -338,7 +339,10 @@ getAttribute(S_CIP_Instance * pa_pInstance, EIP_UINT8 pa_nAttributeNr)
         return p;
       else
         p++;
-    }OPENER_TRACE_WARN("attribute %d not defined\n", pa_nAttributeNr);
+    }
+
+  OPENER_TRACE_WARN("attribute %d not defined\n", pa_nAttributeNr);
+
   return 0;
 }
 

+ 40 - 38
src/cip/cipconnectionmanager.c

@@ -58,7 +58,11 @@ extern EIP_UINT32 g_nMultiCastAddress;
 #define SEQ_LEQ16(a, b) ((short)((a) - (b)) <= 0)
 #define SEQ_GEQ16(a, b) ((short)((a) - (b)) >= 0) 
 
-/*! buffer for holding the run idle infromation.*/
+
+/*The port to be used per default for I/O messages on UDP.*/
+#define OPENER_EIP_IO_UDP_PORT   0x08AE
+
+/*! buffer for holding the run idle information.*/
 EIP_UINT32 g_nRunIdleState;
 
 int
@@ -295,24 +299,28 @@ handleReceivedConnectedData(EIP_UINT8 * pa_pnData, int pa_nDataLength)
                       g_stCPFDataItem.stDataI_Item.Length -= 2;
                     }
 
-                  if (OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER)
+                  if(g_stCPFDataItem.stDataI_Item.Length > 0)
                     {
-                      EIP_UINT32 nRunIdleBuf = ltohl(
-                          &(g_stCPFDataItem.stDataI_Item.Data));
-                      if (g_nRunIdleState != nRunIdleBuf)
+                      /* we have no heartbeat connection */
+                      if (OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER)
                         {
-                          IApp_RunIdleChanged(nRunIdleBuf);
+                          EIP_UINT32 nRunIdleBuf = ltohl(
+                              &(g_stCPFDataItem.stDataI_Item.Data));
+                          if (g_nRunIdleState != nRunIdleBuf)
+                            {
+                              IApp_RunIdleChanged(nRunIdleBuf);
+                            }
+                          g_nRunIdleState = nRunIdleBuf;
+                          g_stCPFDataItem.stDataI_Item.Length -= 4;
                         }
-                      g_nRunIdleState = nRunIdleBuf;
-                      g_stCPFDataItem.stDataI_Item.Length -= 4;
-                    }
 
-                  if (notifyAssemblyConnectedDataReceived(
-                      pstConnectionObject->p_stConsumingInstance,
-                      g_stCPFDataItem.stDataI_Item.Data,
-                      g_stCPFDataItem.stDataI_Item.Length) != 0)
-                    return EIP_ERROR;
-                }
+                      if (notifyAssemblyConnectedDataReceived(
+                          pstConnectionObject->p_stConsumingInstance,
+                          g_stCPFDataItem.stDataI_Item.Data,
+                          g_stCPFDataItem.stDataI_Item.Length) != 0)
+                        return EIP_ERROR;
+                    }
+                  }
 
             }
         }
@@ -562,38 +570,31 @@ int
 OpenProducingPointToPointConnection(S_CIP_ConnectionObject *pa_pstConnObj,
     S_CIP_CPF_Data *pa_CPF_data, EIP_UINT16 *pa_pnExtendedError)
 {
-  int j = -1;
   int newfd;
+  in_port_t nPort = OPENER_EIP_IO_UDP_PORT; /* the default port to be used if no port information is part of the forward open request */
+
 
   if (CIP_ITEM_ID_SOCKADDRINFO_T_TO_O == pa_CPF_data->AddrInfo[0].TypeID)
     {
-      j = 0;
+      nPort = pa_CPF_data->AddrInfo[0].nsin_port;
     }
   else
     {
       if (CIP_ITEM_ID_SOCKADDRINFO_T_TO_O == pa_CPF_data->AddrInfo[1].TypeID)
         {
-          j = 1;
-        }
-      else
-        {
-          /* the target should send us port and adress information  */
-          *pa_pnExtendedError
-              = CIP_CON_MGR_ERROR_PARAMETER_ERROR_IN_UNCONNECTED_SEND_SERVICE;
-          return CIP_ERROR_CONNECTION_FAILURE;
+          nPort = pa_CPF_data->AddrInfo[1].nsin_port;
         }
     }
 
   pa_pstConnObj->remote_addr.sin_family = AF_INET;
-  pa_pstConnObj->remote_addr.sin_addr.s_addr
-      = pa_CPF_data->AddrInfo[j].nsin_addr;
-  pa_pstConnObj->remote_addr.sin_port = pa_CPF_data->AddrInfo[j].nsin_port;
+  pa_pstConnObj->remote_addr.sin_addr.s_addr = 0; /* we don't know the address of the originate will be set in the IApp_CreateUDPSocket */
+  pa_pstConnObj->remote_addr.sin_port = nPort;
 
   newfd = IApp_CreateUDPSocket(PRODUCING, &pa_pstConnObj->remote_addr); /* the address is only needed for bind used if consuming */
   if (newfd == -1)
     {
       OPENER_TRACE_ERR("cannot create UDP socket in OpenPointToPointConnection\n");
-      *pa_pnExtendedError = 0x0315; /*miscelanouse*/
+      *pa_pnExtendedError = 0x0315; /* miscellaneous*/
       return CIP_ERROR_CONNECTION_FAILURE;
     }
   pa_pstConnObj->sockfd[PRODUCING] = newfd;
@@ -631,7 +632,7 @@ OpenMulticastConnection(int pa_direction,
 
   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = g_nMultiCastAddress;
-  addr.sin_port = htons(OPENER_UDP_MULTICAST_PORT);
+  addr.sin_port = htons(OPENER_EIP_IO_UDP_PORT);
 
   newfd = IApp_CreateUDPSocket(pa_direction, &addr); /* the address is only needed for bind used if consuming */
   if (newfd == -1)
@@ -722,7 +723,7 @@ ForwardClose(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request * pa_MRRequest,
   EIP_UINT16 ConnectionSerialNr, OriginatorVendorID;
   EIP_UINT32 OriginatorSerialNr;
 
-  /*supress compiler warning*/
+  /*Suppress compiler warning*/
   (void) pa_pstInstance;
 
   /* set AddressInfo Items to invalid TypeID to prevent assembleLinearMsg to read them */
@@ -768,12 +769,11 @@ UnconnectedSend(S_CIP_Instance * pa_pstInstance,
   S_CIP_UnconnectedSend_Param_Struct data;
   S_Data_Item stDataItem;
 
-  /*supress compiler warning*/
+  /*Suppress compiler warning*/
   (void) pa_pstInstance;
   (void) pa_MRResponse;
   (void) pa_msg;
 
-  /* additional code from smr for communication with Devicelogix */
   p = pa_MRRequest->Data;
   data.Priority = *p++;
   data.Timeout_Ticks = *p++;
@@ -800,10 +800,10 @@ UnconnectedSend(S_CIP_Instance * pa_pstInstance,
     }
   else
     {
-      /*TODO: other packet recieved */
+      /*TODO: other packet received */
       OPENER_TRACE_WARN("Warning: Route path data of unconnected send currently not handled\n");
     }
-  /*TODO correctly handle the path, currently we just ignor it and forward to the message router which should be ok for non routing devices*/
+  /*TODO correctly handle the path, currently we just ignore it and forward to the message router which should be ok for non routing devices*/
   return notifyMR(stDataItem.Data, data.Message_Request_Size);
 }
 
@@ -908,7 +908,7 @@ getFreeConnectionObject(void)
  *      pa_CPF_data	pointer to CPF Data Item
  *      pa_msg		pointer to memory where reply has to be stored
  *  return status
- * 			0 .. no reply need to ne sent back
+ * 			0 .. no reply need to be sent back
  * 			1 .. need to send reply
  * 		  -1 .. error
  */
@@ -1421,15 +1421,17 @@ establishIOConnction(S_CIP_ConnectionObject *pa_pstConnObj,
               pstAttribute = getAttribute(pstInstance, 3);
               assert(pstAttribute != 0); /* an assembly object should always have an attribute 3 */
               nDataSize = pa_pstConnObj->ConsumedConnectionSize;
+
               if ((pa_pstConnObj->TransportTypeTrigger & 0x0F) == 1)
                 {
                   /* class 1 connection */
                   nDataSize -= 2; /* remove 16-bit sequence count length */
                 }
-              if (OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER)
-                {
+              if ((OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER) && (nDataSize > 0))
+                { /* we only have an run idle header if it is not an hearbeat connection */
                   nDataSize -= 4; /* remove the 4 bytes needed for run/idle header */
                 }
+
               if (((S_CIP_Byte_Array *) pstAttribute->pt2data)->len
                   != nDataSize)
                 {

+ 3 - 3
src/enet_encap/cpf.c

@@ -152,11 +152,11 @@ createCPFstructure(EIP_UINT8 * pa_Data, int pa_DataLength,
   for (j = 0; j < (pa_CPF_data->ItemCount - 2); j++) /* TODO there needs to be a limit check here???*/
     {
       pa_CPF_data->AddrInfo[j].TypeID = ltohs(&pa_Data);
+      len_count += 2;
       if ((pa_CPF_data->AddrInfo[j].TypeID == CIP_ITEM_ID_SOCKADDRINFO_O_TO_T)
           || (pa_CPF_data->AddrInfo[j].TypeID
               == CIP_ITEM_ID_SOCKADDRINFO_T_TO_O))
-        {
-          len_count += 16;
+        {         
           pa_CPF_data->AddrInfo[j].Length = ltohs(&pa_Data);
           pa_CPF_data->AddrInfo[j].nsin_family = ltohs(&pa_Data);
           pa_CPF_data->AddrInfo[j].nsin_port = ltohs(&pa_Data);
@@ -166,7 +166,7 @@ createCPFstructure(EIP_UINT8 * pa_Data, int pa_DataLength,
               pa_CPF_data->AddrInfo[j].nasin_zero[i] = *pa_Data;
               pa_Data++;
             }
-          len_count += 16;
+          len_count += 18;
         }
       else
         { /* no sockaddr item found */

+ 1 - 1
src/enet_encap/encap.c

@@ -414,7 +414,7 @@ int
 SendUnitData(struct S_Encapsulation_Data * pa_stReceiveData)
 {
   EIP_INT16 nSendSize;
-  /* Commandspecific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
+  /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
   /* don't use the data yet */
   ltohl(&pa_stReceiveData->pEncapsulation_Data); /* skip over null interface handle*/
   ltohs(&pa_stReceiveData->pEncapsulation_Data); /* skip over unused timeout value*/

+ 4 - 1
src/opener_api.h

@@ -17,7 +17,7 @@
  * \brief This is the public interface of the OpENer. It provides all function needed to implement an EtherNet/IP enabled slave-device.
  */
 
-/*! \ingroup CIP_API 
+/*! \ingroup CIP_API
  * \brief Configure the data of the network interface of the device
  * 
  *  This function setup the data of the network interface needed by OpENer.
@@ -341,6 +341,9 @@ IApp_RunIdleChanged(EIP_UINT32 pa_nRunIdleValue);
  * 
  * @param pa_nDirection PRODCUER or CONSUMER
  * @param pa_pstAddr pointer to the address holding structure
+ *     Attention: For producing point-to-point connection the pa_pstAddr->sin_addr.s_addr
+ *         member is set to 0 by OpENer. The network layer of the application has
+ *         to set the correct addresss of the originator.
  * @return socket identifier on success
  *         -1 on error 
  */

+ 3 - 0
src/ports/platform-pc/main.c

@@ -72,6 +72,9 @@ EIP_STATUS IApp_Init(void)
     /*CONFIG*/
     createAssemblyObject(3, &g_assemblydata3[0], sizeof(g_assemblydata3));
 
+    /*Heartbeat output assembly for Listen only connections */
+    createAssemblyObject(4, 0, 0);
+
     return EIP_OK;
   }
 

+ 27 - 0
src/ports/platform-pc/networkhandler.c

@@ -33,6 +33,12 @@ int fdmax;
 int listener;
 int newfd;
 
+/*!< This var holds the TCP socket the received to last explicit message.
+ * It is needed for opening point to point connection to determine the peer's
+ * address.
+ */
+int g_nCurrentActiveTCPSocket;
+
 static struct timeval tv;
 static MILLISECONDS actualtime, lasttime;
 
@@ -398,8 +404,13 @@ handleDataOnTCPSocket(int pa_nSocket)
   /*TODO handle partial packets*/
   OPENER_TRACE_INFO("Data received on tcp:\n");
 
+  g_nCurrentActiveTCPSocket = pa_nSocket;
+
   nDataSize = handleReceivedExplictData(pa_nSocket, g_acCommBuf, nDataSize,
       &nRemainingBytes);
+
+  g_nCurrentActiveTCPSocket = -1;
+
   if (nRemainingBytes != 0)
     {
       OPENER_TRACE_WARN("Warning: received packet was to long: %d Bytes left!\n",
@@ -425,6 +436,8 @@ handleDataOnTCPSocket(int pa_nSocket)
 int
 IApp_CreateUDPSocket(int pa_nDirection, struct sockaddr_in *pa_pstAddr)
 {
+  struct sockaddr_in stPeerAdr;
+  int nPeerAddrLen = sizeof(struct sockaddr_in);
   /* create a new UDP socket */
   if ((newfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
     {
@@ -446,6 +459,20 @@ IApp_CreateUDPSocket(int pa_nDirection, struct sockaddr_in *pa_pstAddr)
 
       OPENER_TRACE_INFO("networkhandler: bind UDP socket %d\n", newfd);
     }
+  else
+    {
+      if(0 == pa_pstAddr->sin_addr.s_addr)
+        {
+          /* we have a peer to peer producer */
+          if (getpeername(g_nCurrentActiveTCPSocket, (struct sockaddr *)&stPeerAdr, &nPeerAddrLen) < 0)
+            {
+              OPENER_TRACE_ERR("networkhandler: could not get peername: %s", strerror(errno));
+              return EIP_ERROR;
+            }
+          pa_pstAddr->sin_addr.s_addr = stPeerAdr.sin_addr.s_addr;
+        }
+
+    }
 
   /* add new fd to the master list */
   FD_SET(newfd, &master);

+ 0 - 6
src/ports/platform-pc/opener_user_conf.h

@@ -36,12 +36,6 @@
 #define OPENER_DEVICE_MINOR_REVISION      2
 #define OPENER_DEVICE_NAME      "ENetIP EC"
 
-
-/*! The port address to be used for UDP multi-cast connections
- */ 
-#define OPENER_UDP_MULTICAST_PORT   2222
-
-
 /*! Define the number of supported connections (Class 0, 1, and 3 together)
  */  
 #define OPENER_NUMBER_OF_SUPPORTED_CONNECTIONS 10