Przeglądaj źródła

final fix for bug# 3495437: UDP broadcast listIdentity response delay,
furthermore I reworked the select handling by unrolling a loop reducing the necessary ifs per loop. This should make the main loop faster and easier to comprehend

Alois Zoitl 14 lat temu
rodzic
commit
45bb75aaf9

+ 123 - 65
src/enet_encap/encap.c

@@ -23,10 +23,6 @@ extern EIP_UINT16 ID_Status;
 extern EIP_UINT32 SerialNumber;
 extern S_CIP_Short_String ProductName;
 
-/* FIXME Quick fix for getting the last upd originator
- */
-extern struct sockaddr_in from;
-
 /*ip address data taken from TCPIPInterfaceObject*/
 extern S_CIP_TCPIPNetworkInterfaceConfiguration Interface_Configuration;
 
@@ -84,9 +80,15 @@ void
 handleReceivedListServicesCmd(struct S_Encapsulation_Data *pa_stReceiveData);
 void
 handleReceivedListInterfacesCmd(struct S_Encapsulation_Data *pa_stReceiveData);
+
 void
-handleReceivedListIdentityCmd(int pa_nSocket,
+handleReceivedListIdentityCmdTCP(struct S_Encapsulation_Data *pa_stReceiveData);
+
+void
+handleReceivedListIdentityCmdUDP(int pa_nSocket,
+    struct sockaddr_in *pa_pstFromAddr,
     struct S_Encapsulation_Data *pa_stReceiveData);
+
 void
 handleReceivedRegisterSessionCmd(int pa_nSockfd,
     struct S_Encapsulation_Data *pa_stReceiveData);
@@ -112,6 +114,9 @@ void
 determineDelayTime(EIP_BYTE *pa_acBufferStart,
     struct SDelayedEncapsulationMessage *pa_pstDelayedMessageBuffer);
 
+int
+encapsulateListIdentyResponseMessage(EIP_BYTE *pa_pacCommBuf);
+
 /*   void encapInit(void)
  *   initialize sessionlist and interfaceinformation.
  */
@@ -148,18 +153,9 @@ encapInit(void)
   strcpy((char *) g_stInterfaceInformation.NameofService, "communications");
 }
 
-/*   int handleReceivedExplictData(int pa_socket, EIP_UINT8* pa_buf, int pa_length. int *pa_nRemainingBytes)
- *   Read received bytes, copy to struct S_Encapsulation_data and handles the command.
- *      pa_socket	socket handle from which data is received.
- *      pa_buf		buffer to be read.
- *      pa_length	length of the data in pa_buf.
- *  return length of reply
- */
 int
-handleReceivedExplictData(int pa_socket, /* socket from which data was received*/
-EIP_UINT8 * pa_buf, /* input buffer*/
-unsigned int pa_length, /* length of input*/
-int *pa_nRemainingBytes) /* return how many bytes of the input are left over after we're done here*/
+handleReceivedExplictTCPData(int pa_socket, EIP_UINT8 * pa_buf,
+    unsigned int pa_length, int *pa_nRemainingBytes)
 {
   int nRetVal = 0;
   struct S_Encapsulation_Data sEncapData;
@@ -189,8 +185,7 @@ int *pa_nRemainingBytes) /* return how many bytes of the input are left over aft
             break;
 
           case (COMMAND_LISTIDENTITY):
-            handleReceivedListIdentityCmd(pa_socket, &sEncapData);
-            nRetVal = EIP_OK; /* as the response has to be delayed do not send it now */
+            handleReceivedListIdentityCmdTCP(&sEncapData);
             break;
 
           case (COMMAND_LISTINTERFACES):
@@ -229,11 +224,64 @@ int *pa_nRemainingBytes) /* return how many bytes of the input are left over aft
   return nRetVal;
 }
 
-/*   INT8 encapsulate_data(struct S_Encapsulation_Data *pa_stSendData)
- *   add encapsulation header and sender_context to data.
- *      pa_stSendData pointer to structure with header and datapointer.
- *  return size of reply
- */
+int
+handleReceivedExplictUDPData(int pa_socket, struct sockaddr_in *pa_pstFromAddr,
+    EIP_UINT8* pa_buf, unsigned int pa_length, int *pa_nRemainingBytes)
+{
+  int nRetVal = 0;
+  struct S_Encapsulation_Data sEncapData;
+  /* eat the encapsulation header*/
+  /* the structure contains a pointer to the encapsulated data*/
+  /* returns how many bytes are left after the encapsulated data*/
+  *pa_nRemainingBytes = createEncapsulationStructure(pa_buf, pa_length,
+      &sEncapData);
+
+  if (SUPPORTED_OPTIONS_MASK == sEncapData.nOptions) /*TODO generate appropriate error response*/
+    {
+      if (*pa_nRemainingBytes >= 0) /* check if the message is corrupt: header size + claimed payload size > than what we actually received*/
+        {
+          /* full package or more received */
+          sEncapData.nStatus = OPENER_ENCAP_STATUS_SUCCESS;
+          nRetVal = 1;
+          /* most of these functions need a reply to be send */
+          switch (sEncapData.nCommand_code)
+            {
+          case (COMMAND_LISTSERVICES):
+            handleReceivedListServicesCmd(&sEncapData);
+            break;
+
+          case (COMMAND_LISTIDENTITY):
+            handleReceivedListIdentityCmdUDP(pa_socket, pa_pstFromAddr,
+                &sEncapData);
+            nRetVal = EIP_OK; /* as the response has to be delayed do not send it now */
+            break;
+
+          case (COMMAND_LISTINTERFACES):
+            handleReceivedListInterfacesCmd(&sEncapData);
+            break;
+
+            /* Fhe following commands are not to be sent via UDP */
+          case (COMMAND_NOP):
+          case (COMMAND_REGISTERSESSION):
+          case (COMMAND_UNREGISTERSESSION):
+          case (COMMAND_SENDRRDATA):
+          case (COMMAND_SENDUNITDATA):
+          default:
+            sEncapData.nStatus = OPENER_ENCAP_STATUS_INVALID_COMMAND;
+            sEncapData.nData_length = 0;
+            break;
+            }
+          /* if nRetVal is greater then 0 data has to be sent */
+          if (0 < nRetVal)
+            {
+              nRetVal = encapsulate_data(&sEncapData);
+            }
+        }
+    }
+
+  return nRetVal;
+}
+
 int
 encapsulate_data(struct S_Encapsulation_Data *pa_stSendData)
 {
@@ -282,15 +330,17 @@ handleReceivedListInterfacesCmd(struct S_Encapsulation_Data *pa_stReceiveData)
   htols(0x0000, &pacCommBuf); /* copy Interface data to nmsg for sending */
 }
 
-/*   INT8 ListIdentity(struct S_Encapsulation_Data *pa_S_ReceiveData)
- *   send Get_Attribute_All to Identity Object and send data + sender_context back.
- *      pa_S_ReceiveData pointer to structure with received data
- *  return status
- * 			0 .. success
- */
 void
-handleReceivedListIdentityCmd(int pa_nSocket,
-    struct S_Encapsulation_Data * pa_stReceiveData)
+handleReceivedListIdentityCmdTCP(struct S_Encapsulation_Data * pa_stReceiveData)
+{
+  pa_stReceiveData->nData_length = encapsulateListIdentyResponseMessage(
+      pa_stReceiveData->m_acCurrentCommBufferPos);
+}
+
+void
+handleReceivedListIdentityCmdUDP(int pa_nSocket,
+    struct sockaddr_in *pa_pstFromAddr,
+    struct S_Encapsulation_Data *pa_stReceiveData)
 {
   struct SDelayedEncapsulationMessage *pstDelayedMessageBuffer = NULL;
   unsigned int i;
@@ -307,7 +357,8 @@ handleReceivedListIdentityCmd(int pa_nSocket,
   if (NULL != pstDelayedMessageBuffer)
     {
       pstDelayedMessageBuffer->m_nSocket = pa_nSocket;
-      memcpy((&pstDelayedMessageBuffer->m_stSendToAddr), &from, sizeof(from));
+      memcpy((&pstDelayedMessageBuffer->m_stSendToAddr), pa_pstFromAddr,
+          sizeof(struct sockaddr_in));
 
       determineDelayTime(pa_stReceiveData->m_acCommBufferStart,
           pstDelayedMessageBuffer);
@@ -315,45 +366,52 @@ handleReceivedListIdentityCmd(int pa_nSocket,
       memcpy(&(pstDelayedMessageBuffer->m_anMsg[0]),
           pa_stReceiveData->m_acCommBufferStart, ENCAPSULATION_HEADER_LENGTH);
 
-      EIP_UINT8 *pacCommBuf =
-          &(pstDelayedMessageBuffer->m_anMsg[ENCAPSULATION_HEADER_LENGTH]);
-      EIP_BYTE *acIdLenBuf;
+      pstDelayedMessageBuffer->m_unMessageSize =
+          encapsulateListIdentyResponseMessage(
+              &(pstDelayedMessageBuffer->m_anMsg[ENCAPSULATION_HEADER_LENGTH]));
+
+      EIP_UINT8 *pacCommBuf = pstDelayedMessageBuffer->m_anMsg + 2;
+      htols(pstDelayedMessageBuffer->m_unMessageSize, &pacCommBuf);
+      pstDelayedMessageBuffer->m_unMessageSize += ENCAPSULATION_HEADER_LENGTH;
+    }
+}
+
+int
+encapsulateListIdentyResponseMessage(EIP_BYTE *pa_pacCommBuf)
+{
+  EIP_UINT8 *pacCommBufRunner = pa_pacCommBuf;
+  EIP_BYTE *acIdLenBuf;
 
-      htols(1, &pacCommBuf); /* one item */
-      htols(ITEM_ID_LISTIDENTITY, &pacCommBuf);
+  htols(1, &pacCommBufRunner); /* one item */
+  htols(ITEM_ID_LISTIDENTITY, &pacCommBufRunner);
 
-      acIdLenBuf = pacCommBuf;
-      pacCommBuf += 2; /*at this place the real length will be inserted below*/
+  acIdLenBuf = pacCommBufRunner;
+  pacCommBufRunner += 2; /*at this place the real length will be inserted below*/
 
-      htols(SUPPORTED_PROTOCOL_VERSION, &pacCommBuf);
+  htols(SUPPORTED_PROTOCOL_VERSION, &pacCommBufRunner);
 
-      encapsulateIPAdress(OPENER_ETHERNET_PORT,
-          Interface_Configuration.IPAddress, pacCommBuf);
-      pacCommBuf += 8;
+  encapsulateIPAdress(OPENER_ETHERNET_PORT, Interface_Configuration.IPAddress,
+      pacCommBufRunner);
+  pacCommBufRunner += 8;
 
-      memset(pacCommBuf, 0, 8);
-      pacCommBuf += 8;
+  memset(pacCommBufRunner, 0, 8);
+  pacCommBufRunner += 8;
 
-      htols(VendorID, &pacCommBuf);
-      htols(DeviceType, &pacCommBuf);
-      htols(ProductCode, &pacCommBuf);
-      *(pacCommBuf)++ = Revison.MajorRevision;
-      *(pacCommBuf)++ = Revison.MinorRevision;
-      htols(ID_Status, &pacCommBuf);
-      htoll(SerialNumber, &pacCommBuf);
-      *pacCommBuf++ = (unsigned char) ProductName.Length;
-      memcpy(pacCommBuf, ProductName.String, ProductName.Length);
-      pacCommBuf += ProductName.Length;
-      *pacCommBuf++ = 0xFF;
+  htols(VendorID, &pacCommBufRunner);
+  htols(DeviceType, &pacCommBufRunner);
+  htols(ProductCode, &pacCommBufRunner);
+  *(pacCommBufRunner)++ = Revison.MajorRevision;
+  *(pacCommBufRunner)++ = Revison.MinorRevision;
+  htols(ID_Status, &pacCommBufRunner);
+  htoll(SerialNumber, &pacCommBufRunner);
+  *pacCommBufRunner++ = (unsigned char) ProductName.Length;
+  memcpy(pacCommBufRunner, ProductName.String, ProductName.Length);
+  pacCommBufRunner += ProductName.Length;
+  *pacCommBufRunner++ = 0xFF;
 
-      pstDelayedMessageBuffer->m_unMessageSize = pacCommBuf
-          - &(pstDelayedMessageBuffer->m_anMsg[ENCAPSULATION_HEADER_LENGTH]);
-      htols(pacCommBuf - acIdLenBuf - 2, &acIdLenBuf); /* the -2 is for not counting the length field*/
+  htols(pacCommBufRunner - acIdLenBuf - 2, &acIdLenBuf); /* the -2 is for not counting the length field*/
 
-      pacCommBuf = pstDelayedMessageBuffer->m_anMsg + 2;
-      htols(pstDelayedMessageBuffer->m_unMessageSize, &pacCommBuf);
-      pstDelayedMessageBuffer->m_unMessageSize += ENCAPSULATION_HEADER_LENGTH;
-    }
+  return pacCommBufRunner - pa_pacCommBuf;
 }
 
 void
@@ -371,8 +429,8 @@ determineDelayTime(EIP_BYTE *pa_acBufferStart,
       unMaxDelayTime = 500;
     }
 
-  pa_pstDelayedMessageBuffer->m_unTimeOut = (unMaxDelayTime * rand())
-      / RAND_MAX + 1;
+  pa_pstDelayedMessageBuffer->m_unTimeOut = (unMaxDelayTime * rand()) / RAND_MAX
+      + 1;
 }
 
 /*   void RegisterSession(struct S_Encapsulation_Data *pa_S_ReceiveData)

+ 21 - 3
src/opener_api.h

@@ -333,7 +333,7 @@ configureListenOnlyConnectionPoint(unsigned int pa_unConnNum,
     unsigned int pa_unConfigAssembly);
 
 /** \ingroup CIP_API 
- * \brief Notify the encapsulation layer that an explicit message has been received via TCP or UDP.
+ * \brief Notify the encapsulation layer that an explicit message has been received via TCP.
  * 
  * @param pa_socket socket handle from which data is received.
  * @param pa_buf buffer that contains the received data. This buffer will also contain the
@@ -343,7 +343,22 @@ configureListenOnlyConnectionPoint(unsigned int pa_unConnNum,
  * @return length of reply that need to be sent back
  */
 int
-handleReceivedExplictData(int pa_socket, EIP_UINT8* pa_buf,
+handleReceivedExplictTCPData(int pa_socket, EIP_UINT8* pa_buf,
+    unsigned int pa_length, int *pa_nRemainingBytes);
+
+/** \ingroup CIP_API
+ * \brief Notify the encapsulation layer that an explicit message has been received via UDP.
+ *
+ * @param pa_socket socket handle from which data is received.
+ * @param pa_pstFromAddr remote address from which the data is received.
+ * @param pa_buf buffer that contains the received data. This buffer will also contain the
+ *       response if one is to be sent.
+ * @param pa_length length of the data in pa_buf.
+ * @param pa_nRemainingBytes return how many bytes of the input are left over after we're done here
+ * @return length of reply that need to be sent back
+ */
+int
+handleReceivedExplictUDPData(int pa_socket, struct sockaddr_in *pa_pstFromAddr, EIP_UINT8* pa_buf,
     unsigned int pa_length, int *pa_nRemainingBytes);
 
 /*! \ingroup CIP_API
@@ -669,7 +684,10 @@ IApp_CloseSocket(int pa_nSockFd);
  *   - Establish connections requested on TCP port AF12hex
  *   - Receive explicit message data on connected TCP sockets and the UPD socket
  *     for port AF12hex. The received data has to be hand over to Ethernet
- *     encapsulation layer with the function int handleReceivedExplictData(int pa_socket, EIP_UINT8* pa_buf, int pa_length, int *pa_nRemainingBytes).\n
+ *     encapsulation layer with the functions: \n
+ *      int handleReceivedExplictTCPData(int pa_socket, EIP_UINT8* pa_buf, int pa_length, int *pa_nRemainingBytes),\n
+ *      int handleReceivedExplictUDPData(int pa_socket, struct sockaddr_in *pa_pstFromAddr, EIP_UINT8* pa_buf, unsigned int pa_length, int *pa_nRemainingBytes).\n
+ *     Depending if the data has been received from a TCP or from a UDP socket.
  *     As a result of this function a response may have to be sent. The data to
  *     be sent is in the given buffer pa_buf.
  *   - Create UDP sending and receiving sockets for implicit connected messages\n

+ 18 - 17
src/ports/platform-pc/main.c

@@ -19,9 +19,7 @@
 #define DEMO_APP_HEARBEAT_LISTEN_ONLY_ASSEMBLY_NUM 153 //0x099
 #define DEMO_APP_EXPLICT_ASSEMBLY_NUM              154 //0x09A
 
-
-/* global variables for demo application (4 assembly data fields)  ************/
-EIP_UINT8 g_assemblydata064[32]; /* Input */
+/* global variables for demo application (4 assembly data fields)  ************/EIP_UINT8 g_assemblydata064[32]; /* Input */
 EIP_UINT8 g_assemblydata096[32]; /* Output */
 EIP_UINT8 g_assemblydata097[10]; /* Config */
 EIP_UINT8 g_assemblydata09A[32]; /* Explicit */
@@ -86,23 +84,26 @@ main(int argc, char *arg[])
   CIP_Init(nUniqueConnectionID);
 
   /* Setup Network Handles */
-  NetworkHandler_Init();
-
-  g_nEndStack = 0;
+  if (EIP_OK == NetworkHandler_Init())
+    {
+      g_nEndStack = 0;
 #ifndef WIN32
-  /* register for closing signals so that we can trigger the stack to end */
-  signal(SIGHUP, leaveStack);
+      /* register for closing signals so that we can trigger the stack to end */
+      signal(SIGHUP, leaveStack);
 #endif
 
-  /* The event loop. Put other processing you need done continually in here */
-  while (1 != g_nEndStack)
-    {
-      NetworkHandler_ProcessOnce();
+      /* The event loop. Put other processing you need done continually in here */
+      while (1 != g_nEndStack)
+        {
+          if( EIP_OK != NetworkHandler_ProcessOnce())
+            {
+              break;
+            }
+        }
+
+      /* clean up network state */
+      NetworkHandler_Finish();
     }
-
-  /* clean up network state */
-  NetworkHandler_Finish();
-
   /* close remaining sessions and connections, cleanup used data */
   shutdownCIP();
 
@@ -249,7 +250,7 @@ IApp_RunIdleChanged(EIP_UINT32 pa_nRunIdleValue)
 void
 leaveStack(int pa_nSig)
 {
-  (void)pa_nSig; /* kill unused parameter warning */
+  (void) pa_nSig; /* kill unused parameter warning */
   OPENER_TRACE_STATE("got signal HUP\n");
   g_nEndStack = 1;
 }

+ 197 - 168
src/ports/platform-pc/networkhandler.c

@@ -31,7 +31,6 @@ fd_set read_fds;
 /* temporary file descriptor for select() */
 
 int fdmax;
-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
@@ -46,8 +45,23 @@ static MILLISECONDS actualtime, lasttime;
  *
  */
 void
-handleTCPConnectionRequest();
+checkAndHandleTCPListenerSocket();
 
+/*! \brief check if data has been received on the udp broadcast socket and if yes handle it correctly
+ *
+ */
+void
+checkAndHandleUDPBroadCastSocket();
+
+/*! \brief check if on one of the udp consuming sockets data has been received and if yes handle it correctly
+ *
+ */
+void
+checkAndHandleConsumingUDPSockets();
+/*! \brief check if the given socket is set in the read set
+ *
+ */EIP_BOOL8
+checkSocketSet(int pa_nSocket);
 
 /*!
  *
@@ -55,9 +69,6 @@ handleTCPConnectionRequest();
 EIP_STATUS
 handleDataOnTCPSocket(int pa_nSocket);
 
-
-
-
 static MILLISECONDS
 getmilliseconds(void)
 {
@@ -72,36 +83,12 @@ getmilliseconds(void)
 #endif
 }
 
-/*! Check if the socket identifier is associate with an active connection
- *
- *  @param pa_nFD  socket handle
- *  @return pointer to the connection if the given socket hanlder is an active connection otherwise NULL
- */
-S_CIP_ConnectionObject *
-isConnectedFd(int pa_nFD)
-{
-  S_CIP_ConnectionObject *pstRunner = g_pstActiveConnectionList;
-
-  while (NULL != pstRunner)
-    {
-      if ((pstRunner->sockfd[0] == pa_nFD) || (pstRunner->sockfd[1] == pa_nFD))
-        {
-          break;
-        }
-      pstRunner = pstRunner->m_pstNext;
-    }
-
-  return pstRunner;
-}
-
 /* INT8 Start_NetworkHandler()
  * 	start a TCP listening socket, accept connections, receive data in select loop, call manageConnections periodically.
  * 	return status
  * 			-1 .. error
  */
 
-struct sockaddr_in from;
-
 struct NetworkStatus
 {
   int nTCPListener;
@@ -125,7 +112,8 @@ NetworkHandler_Init(void)
   WSAStartup(wVersionRequested, &wsaData);
 #endif
 
-  /* clear the master an temp sets */FD_ZERO(&master);
+  /* clear the master an temp sets                                            */
+  FD_ZERO(&master);
   FD_ZERO(&read_fds);
 
   /* create a new TCP socket */
@@ -200,8 +188,8 @@ NetworkHandler_Init(void)
 
   /* keep track of the biggest file descriptor */
   fdmax =
-      (TheNetworkStatus.nTCPListener > TheNetworkStatus.nUDPListener) ? TheNetworkStatus.nTCPListener :
-          TheNetworkStatus.nUDPListener;
+      (TheNetworkStatus.nTCPListener > TheNetworkStatus.nUDPListener) ?
+          TheNetworkStatus.nTCPListener : TheNetworkStatus.nUDPListener;
 
   lasttime = getmilliseconds(); /* initialize time keeping */
   TheNetworkStatus.elapsedtime = 0;
@@ -213,36 +201,20 @@ EIP_STATUS
 NetworkHandler_ProcessOnce(void)
 {
   int fd;
-  int nReceived_size;
   int res;
-  EIP_UINT8 *rxp;
-  int nRemainingBytes;
-  int replylen;
-  S_CIP_ConnectionObject *pstConnection;
-
-#ifndef WIN32
-  socklen_t fromlen;
-#else
-  unsigned long fromlen;
-#endif
 
   read_fds = master;
-  fromlen = sizeof(from);
 
   tv.tv_sec = 0;
   tv.tv_usec = (
-      TheNetworkStatus.elapsedtime < OPENER_TIMER_TICK ? OPENER_TIMER_TICK
-          - TheNetworkStatus.elapsedtime :
-          0) * 1000; /* 10 ms */
+      TheNetworkStatus.elapsedtime < OPENER_TIMER_TICK ?
+          OPENER_TIMER_TICK - TheNetworkStatus.elapsedtime : 0) * 1000; /* 10 ms */
 
   res = select(fdmax + 1, &read_fds, 0, 0, &tv);
   if (res == -1)
     {
-      if (EINTR == errno)
+      if (EINTR == errno) /* we have somehow been interrupted. The default behavior is to go back into the select loop. */
         {
-          /* we have somehow been interrupted. The default behavior is to
-           * go back into the select loop.
-           */
           return EIP_OK;
         }
       else
@@ -253,107 +225,25 @@ NetworkHandler_ProcessOnce(void)
     }
 
   if (res > 0)
-    for (fd = 0; fd <= fdmax; fd++)
-      {
-        if (FD_ISSET(fd, &read_fds))
-          {
-            if (!FD_ISSET(fd, &master))
-              {
-                OPENER_TRACE_INFO("socket fd %d closed with pending message\n", fd);
-                return EIP_OK;
-              }
-
-            /* see if this is a connection request to the TCP listener*/
-            if (fd == TheNetworkStatus.nTCPListener) /* handle new TCP connection */
-              {
-                handleTCPConnectionRequest();
-                continue;
-              }
-
-            /* see if this is an unsolicited inbound UDP message */
-            if (fd == TheNetworkStatus.nUDPListener)
-              {
-                OPENER_TRACE_STATE(
-                    "networkhandler: unsolicited UDP message on fd %d\n",
-                    fd);
-
-                /*Handle udp broadcast messages */
-                nReceived_size = recvfrom(fd, g_acPCEthernetCommBuffer,
-                    PC_OPENER_ETHERNET_BUFFER_SIZE, 0,
-                    (struct sockaddr *) &from, &fromlen);
-
-                if (nReceived_size <= 0)
-                  { /* got error */
-                    OPENER_TRACE_ERR(
-                        "networkhandler: error on recvfrom udp broadcast port: %s\n",
-                        strerror(errno));
-                    continue;
-                  }
-
-                OPENER_TRACE_INFO("Data received on udp:\n");
-
-                rxp = &g_acPCEthernetCommBuffer[0];
-                do
-                  {
-                    replylen = handleReceivedExplictData(fd, rxp,
-                        nReceived_size, &nRemainingBytes);
-
-                    rxp += nReceived_size - nRemainingBytes;
-                    nReceived_size = nRemainingBytes;
-
-                    if (replylen > 0)
-                      {
-                        OPENER_TRACE_INFO("reply sent:\n");
-
-                        /* if the active fd matches a registered UDP callback, handle a UDP packet */
-                        res = sendto(fd, (char *) g_acPCEthernetCommBuffer,
-                            replylen, 0, (struct sockaddr *) &from,
-                            sizeof(from));
-                        if (res != replylen)
-                          {
-                            OPENER_TRACE_INFO(
-                                "networkhandler: UDP response was not fully sent\n");
-                          }
-                      }
-                  }
-                while (nRemainingBytes > 0);
-                continue;
-              }
-
-            /* see if the message is from a registered UDP socket */
-            pstConnection = isConnectedFd(fd);
-            if (NULL != pstConnection)
-              {
-                fromlen = sizeof(from);
-                nReceived_size = recvfrom(fd, g_acPCEthernetCommBuffer,
-                    PC_OPENER_ETHERNET_BUFFER_SIZE, 0,
-                    (struct sockaddr *) &from, &fromlen);
-                if (nReceived_size == 0)
-                  {
-                    OPENER_TRACE_STATE("connection closed by client\n");
-                    pstConnection->m_pfCloseFunc(pstConnection);
-                    continue;
-                  }
-                if (nReceived_size <= 0)
-                  {
-                    OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
-                    pstConnection->m_pfCloseFunc(pstConnection);
-                    continue;
-                  }
-
-                handleReceivedConnectedData(g_acPCEthernetCommBuffer,
-                    nReceived_size, &from);
-                continue;
-              }
-
-            /* if not registered UDP, handle as a TCP receive */
-            if (EIP_ERROR == handleDataOnTCPSocket(fd)) /* if error */
-              {
-                IApp_CloseSocket(fd);
-                closeSession(fd); /* clean up session and close the socket */
-              }
-          }
-      }
+    {
+
+      checkAndHandleTCPListenerSocket();
+      checkAndHandleUDPBroadCastSocket();
+      checkAndHandleConsumingUDPSockets();
+
+      for (fd = 0; fd <= fdmax; fd++)
+        {
+          if(true == checkSocketSet(fd))
+            {
+              /* if it is still checked it is a TCP receive */
+              if (EIP_ERROR == handleDataOnTCPSocket(fd)) /* if error */
+                {
+                  IApp_CloseSocket(fd);
+                  closeSession(fd); /* clean up session and close the socket */
+                }
+            }
+        }
+    }
 
   actualtime = getmilliseconds();
   TheNetworkStatus.elapsedtime += actualtime - lasttime;
@@ -379,6 +269,25 @@ NetworkHandler_Finish(void)
   return EIP_OK;
 }
 
+EIP_BOOL8
+checkSocketSet(int pa_nSocket)
+{
+  EIP_BOOL8 nRetVal = false;
+  if (FD_ISSET(pa_nSocket, &read_fds))
+    {
+      if (FD_ISSET(pa_nSocket, &master))
+        {
+          nRetVal = true;
+        }
+      else
+        {
+          OPENER_TRACE_INFO("socket: %d closed with pending message\n", pa_nSocket);
+        }
+      FD_CLR(pa_nSocket, &read_fds); /* remove it from the read set so that later checks will not find it */
+    }
+
+  return nRetVal;
+}
 EIP_STATUS
 IApp_SendUDPData(struct sockaddr_in *pa_pstAddr, int pa_nSockFd,
     EIP_UINT8 *pa_acData, EIP_UINT16 pa_nDataLength)
@@ -488,7 +397,7 @@ handleDataOnTCPSocket(int pa_nSocket)
 
       g_nCurrentActiveTCPSocket = pa_nSocket;
 
-      nCheckVal = handleReceivedExplictData(pa_nSocket,
+      nCheckVal = handleReceivedExplictTCPData(pa_nSocket,
           g_acPCEthernetCommBuffer, unDataSize, &nRemainingBytes);
 
       g_nCurrentActiveTCPSocket = -1;
@@ -531,6 +440,7 @@ int
 IApp_CreateUDPSocket(int pa_nDirection, struct sockaddr_in *pa_pstAddr)
 {
   struct sockaddr_in stPeerAdr;
+  int newfd;
 #ifdef WIN32
   unsigned long nPeerAddrLen;
 #else
@@ -582,7 +492,8 @@ IApp_CreateUDPSocket(int pa_nDirection, struct sockaddr_in *pa_pstAddr)
       pa_pstAddr->sin_addr.s_addr = stPeerAdr.sin_addr.s_addr;
     }
 
-  /* add new fd to the master list */FD_SET(newfd, &master);
+  /* add new fd to the master list                                             */
+  FD_SET(newfd, &master);
   if (newfd > fdmax)
     {
       fdmax = newfd;
@@ -608,25 +519,143 @@ IApp_CloseSocket(int pa_nSockFd)
 }
 
 void
-handleTCPConnectionRequest()
+checkAndHandleTCPListenerSocket()
 {
-  OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
-
-  newfd = accept(TheNetworkStatus.nTCPListener, NULL, NULL);
-  if (newfd == -1)
+  int newfd;
+  /* see if this is a connection request to the TCP listener*/
+  if (true == checkSocketSet(TheNetworkStatus.nTCPListener))
     {
-      OPENER_TRACE_ERR("networkhandler: error on accept: %s\n", strerror(errno));
-      return;
+      OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
+
+      newfd = accept(TheNetworkStatus.nTCPListener, NULL, NULL);
+      if (newfd == -1)
+        {
+          OPENER_TRACE_ERR("networkhandler: error on accept: %s\n", strerror(errno));
+          return;
+        }
+
+      FD_SET(newfd, &master);
+      /* add newfd to master set */
+      if (newfd > fdmax)
+        {
+          fdmax = newfd;
+        }
+
+      OPENER_TRACE_STATE(
+          "networkhandler: opened new TCP connection on fd %d\n",
+          newfd);
     }
+}
 
-  FD_SET(newfd, &master);
-  /* add newfd to master set */
-  if (newfd > fdmax)
+void
+checkAndHandleUDPBroadCastSocket()
+{
+  int nReceived_size;
+  int nRemainingBytes;
+  int nReplyLen;
+  EIP_UINT8 *rxp;
+  struct sockaddr_in stFrom;
+#ifndef WIN32
+  socklen_t nFromLen;
+#else
+  unsigned long nFromLen;
+#endif
+
+  /* see if this is an unsolicited inbound UDP message */
+  if (true == checkSocketSet(TheNetworkStatus.nUDPListener))
     {
-      fdmax = newfd;
+
+      nFromLen = sizeof(stFrom);
+
+      OPENER_TRACE_STATE(
+          "networkhandler: unsolicited UDP message on EIP broadcast socket\n");
+
+      /*Handle udp broadcast messages */
+      nReceived_size = recvfrom(TheNetworkStatus.nUDPListener,
+          g_acPCEthernetCommBuffer, PC_OPENER_ETHERNET_BUFFER_SIZE, 0,
+          (struct sockaddr *) &stFrom, &nFromLen);
+
+      if (nReceived_size <= 0)
+        { /* got error */
+          OPENER_TRACE_ERR(
+              "networkhandler: error on recvfrom udp broadcast port: %s\n",
+              strerror(errno));
+          return;
+        }
+
+      OPENER_TRACE_INFO("Data received on udp:\n");
+
+      rxp = &g_acPCEthernetCommBuffer[0];
+      do
+        {
+          nReplyLen = handleReceivedExplictUDPData(
+              TheNetworkStatus.nUDPListener, &stFrom, rxp, nReceived_size,
+              &nRemainingBytes);
+
+          rxp += nReceived_size - nRemainingBytes;
+          nReceived_size = nRemainingBytes;
+
+          if (nReplyLen > 0)
+            {
+              OPENER_TRACE_INFO("reply sent:\n");
+
+              /* if the active fd matches a registered UDP callback, handle a UDP packet */
+              if (sendto(TheNetworkStatus.nUDPListener,
+                  (char *) g_acPCEthernetCommBuffer, nReplyLen, 0,
+                  (struct sockaddr *) &stFrom, sizeof(stFrom)) != nReplyLen)
+                {
+                  OPENER_TRACE_INFO(
+                      "networkhandler: UDP response was not fully sent\n");
+                }
+            }
+        }
+      while (nRemainingBytes > 0);
     }
+}
+
+void
+checkAndHandleConsumingUDPSockets()
+{
+  int nReceived_size;
+  struct sockaddr_in stFrom;
+#ifndef WIN32
+  socklen_t nFromLen;
+#else
+  unsigned long nFromLen;
+#endif
 
-  OPENER_TRACE_STATE(
-      "networkhandler: opened new TCP connection on fd %d\n",
-      newfd);
+  S_CIP_ConnectionObject *pstRunner = g_pstActiveConnectionList;
+  S_CIP_ConnectionObject *pstCurrent;
+
+  /* see a message on one of the registered UDP sockets has been received     */
+  while (NULL != pstRunner)
+    {
+      pstCurrent = pstRunner;
+      pstRunner = pstRunner->m_pstNext; /* do this at the beginning as the close function may can make the entry invalid */
+
+      if ((-1 != pstCurrent->sockfd[CONSUMING]) && (true == checkSocketSet(pstCurrent->sockfd[CONSUMING])))
+        {
+          nFromLen = sizeof(stFrom);
+          nReceived_size = recvfrom(pstCurrent->sockfd[CONSUMING], g_acPCEthernetCommBuffer,
+              PC_OPENER_ETHERNET_BUFFER_SIZE, 0, (struct sockaddr *) &stFrom,
+              &nFromLen);
+          if (0 == nReceived_size)
+            {
+              OPENER_TRACE_STATE("connection closed by client\n");
+              pstCurrent->m_pfCloseFunc(pstCurrent);
+              continue;
+            }
+
+          if (0 > nReceived_size)
+            {
+              OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
+              pstCurrent->m_pfCloseFunc(pstCurrent);
+              continue;
+            }
+
+          handleReceivedConnectedData(g_acPCEthernetCommBuffer, nReceived_size,
+              &stFrom);
+
+        }
+    }
 }

+ 2 - 2
src/ports/platform-pc/opener_user_conf.h

@@ -33,7 +33,7 @@ typedef unsigned short in_port_t;
 /*! Identity configuration of the device */
 #define OPENER_DEVICE_VENDOR_ID           1
 #define OPENER_DEVICE_TYPE               12
-#define OPENER_DEVICE_PRODUCT_CODE      200
+#define OPENER_DEVICE_PRODUCT_CODE      65001
 #define OPENER_DEVICE_MAJOR_REVISION      1
 #define OPENER_DEVICE_MINOR_REVISION      2
 #define OPENER_DEVICE_NAME      "OpENer PC"
@@ -91,7 +91,7 @@ typedef unsigned short in_port_t;
 
 /*! Number of sessions that can be handled at the same time
  */ 
-#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 4
+#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 20
 
 /*! The time in ms of the timer used in this implementations
  */