Example #1
0
void
CheckAndHandleUdpUnicastSocket()
{
	int nReceived_size;
	int nRemainingBytes;
	int nReplyLen;
	EipUint8 *rxp;
	struct sockaddr_in stFrom;
	unsigned long nFromLen;

	/* see if this is an unsolicited inbound UDP message */
	if (true == checkSocketSet(g_network_status.udp_unicast_listener))
	{

		nFromLen = sizeof(stFrom);

		OPENER_TRACE_STATE(
			"networkhandler: unsolicited UDP message on EIP broadcast socket\n");

		/*Handle udp broadcast messages */
		nReceived_size = recvfrom(g_network_status.udp_unicast_listener,
			g_ethernet_communciation_buffer, 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_ethernet_communciation_buffer[0];
		do
		{
			nReplyLen = HandleReceivedExplictUdpData(
				g_network_status.udp_unicast_listener, &stFrom, rxp, nReceived_size,
				&nRemainingBytes, true);

			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(g_network_status.udp_unicast_listener,
					(char *)g_ethernet_communciation_buffer, nReplyLen, 0,
					(struct sockaddr *) &stFrom, sizeof(stFrom)) != nReplyLen)
				{
					OPENER_TRACE_INFO(
						"networkhandler: UDP response was not fully sent\n");
				}
			}
		} while (nRemainingBytes > 0);
	}
}
Example #2
0
void
CheckAndHandleTcpListenerSocket()
{
  int newfd;
  /* see if this is a connection request to the TCP listener*/
  if (true == checkSocketSet(g_network_status.tcp_listener))
    {
      OPENER_TRACE_INFO("networkhandler: new TCP connection\n");

      newfd = accept(g_network_status.tcp_listener, 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);
    }
}
Example #3
0
void
CloseSocket(int pa_nSockFd)
{

  OPENER_TRACE_INFO("networkhandler: closing socket %d\n", pa_nSockFd);
  if (kEipInvalidSocket != pa_nSockFd)
    {
      FD_CLR(pa_nSockFd, &master);
#ifdef WIN32
      closesocket(pa_nSockFd);
#else
      shutdown(pa_nSockFd, SHUT_RDWR);
      close(pa_nSockFd);
#endif
    }
}
Example #4
0
CipBool
checkSocketSet(int pa_nSocket)
{
  CipBool 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;
}
Example #5
0
void ConfigureDomainName() {
  // This was a parameter!
  int interface_index = 0;

  CipDword dwSize = 0;
  int i = 0;
  // Set the flags to pass to GetAdaptersAddresses
  CipUdint flags = GAA_FLAG_INCLUDE_PREFIX;
  CipDword dwRetVal = 0;
  // default to unspecified address family (both)
  CipUdint family = AF_UNSPEC;

  LPVOID lpMsgBuf = NULL;

  PIP_ADAPTER_ADDRESSES pAddresses = NULL;
  PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
  IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
  CipUdint outBufLen = 0;
  CipUdint tries = 0;

  family = AF_INET;
  // Allocate a 15 KB buffer to start with.
  outBufLen = WORKING_BUFFER_SIZE;

  do {

    pAddresses = (IP_ADAPTER_ADDRESSES *)CipCalloc(1,outBufLen);
    if (pAddresses == NULL) {
      printf
        ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
      exit(1);
    }

    dwRetVal =
      GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);

    if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
      CipFree(pAddresses);
      pAddresses = NULL;
    }
    else {
      break;
    }

    tries++;

  } while ( (dwRetVal == ERROR_BUFFER_OVERFLOW) && (tries < MAX_TRIES) );

  if (dwRetVal == NO_ERROR) {
    // If successful, output some information from the data we received
    pCurrAddresses = pAddresses;
    while (pCurrAddresses) {
      if (interface_index == pCurrAddresses->IfIndex) {
        pDnServer = pCurrAddresses->FirstDnsServerAddress;
        if (pDnServer) {
          for (i = 0; pDnServer != NULL; i++) {
            pDnServer = pDnServer->Next;
          }
        }

        char pStringBuf[INET_ADDRSTRLEN];
        if (i != 0) {

          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(
            pCurrAddresses->DnsSuffix);
          if (interface_configuration_.domain_name.length) {
            interface_configuration_.domain_name.string = (CipByte *)CipCalloc(
              interface_configuration_.domain_name.length + 1,
              sizeof(CipUsint) );
            strcpy(interface_configuration_.domain_name.string,
                   pCurrAddresses->DnsSuffix);
          }
          else {
            interface_configuration_.domain_name.string = NULL;
          }
/*
          inet_ntop(AF_INET,
                   pCurrAddresses->FirstDnsServerAddress->Address.lpSockaddr->sa_data + 2,
                   interface_configuration_.name_server,
                   sizeof(interface_configuration_.name_server) );
          inet_ntop(AF_INET,
                   pCurrAddresses->FirstDnsServerAddress->Next->Address.lpSockaddr->sa_data + 2,
                   interface_configuration_.name_server_2,
                   sizeof(interface_configuration_.name_server_2) );
 */
        }
        else{ interface_configuration_.domain_name.length = 0;}

      }
      pCurrAddresses = pCurrAddresses->Next;
    }
  }
  else {
    OPENER_TRACE_INFO("Call to GetAdaptersAddresses failed with error: %d\n",
                      dwRetVal);
    if (dwRetVal == ERROR_NO_DATA) {
      OPENER_TRACE_INFO(
        "\tNo addresses were found for the requested parameters\n");
    }
    else {

      if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                        FORMAT_MESSAGE_FROM_SYSTEM |
                        FORMAT_MESSAGE_IGNORE_INSERTS,
                        NULL, dwRetVal,
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                        // Default language
                        (LPTSTR)&lpMsgBuf, 0, NULL) ) {
        OPENER_TRACE_INFO("\tError: %s", lpMsgBuf);
        CipFree(lpMsgBuf);
        if (pAddresses) {
          CipFree(pAddresses);
        }
        exit(1);
      }
    }
  }

  if (pAddresses) {
    CipFree(pAddresses);
  }


}
Example #6
0
EIP_STATUS
setAssemblyAttributeSingle(S_CIP_Instance * pa_pstInstance,
                           S_CIP_MR_Request * pa_pstMRRequest,
                           S_CIP_MR_Response * pa_pstMRResponse)
{


  EIP_UINT8 * acReqData;
  S_CIP_attribute_struct * p;
  OPENER_TRACE_INFO(" setAttribute %d\n", pa_pstMRRequest->RequestPath.AttributNr);

  acReqData = pa_pstMRRequest->Data;

  pa_pstMRResponse->DataLength = 0;
  pa_pstMRResponse->ReplyService = (0x80 | pa_pstMRRequest->Service);
  pa_pstMRResponse->GeneralStatus = CIP_ERROR_ATTRIBUTE_NOT_SUPPORTED;
  pa_pstMRResponse->SizeofAdditionalStatus = 0;


  p = getAttribute(pa_pstInstance,
                   pa_pstMRRequest->RequestPath.AttributNr);

  if((p != 0) && (3 == pa_pstMRRequest->RequestPath.AttributNr))
    {
      if(p->pt2data != 0)
        {
          S_CIP_Byte_Array * pacData = (S_CIP_Byte_Array *) p->pt2data;

          //TODO: check for ATTRIBUTE_SET/GETABLE MASK
          if(true == isConnectedOutputAssembly(pa_pstInstance->nInstanceNr))
            {
              OPENER_TRACE_WARN("Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r");
              pa_pstMRResponse->GeneralStatus = CIP_ERROR_ATTRIBUTE_NOT_SETTABLE;
            }
          else
            {
              if(pa_pstMRRequest->DataLength < pacData->len)
                {
                  OPENER_TRACE_INFO("Assembly setAssemblyAttributeSingle: not enough data received.\r\n");
                  pa_pstMRResponse->GeneralStatus = CIP_ERROR_NOT_ENOUGH_DATA;
                }
              else
                {
                  if(pa_pstMRRequest->DataLength > pacData->len)
                    {
                      OPENER_TRACE_INFO("Assembly setAssemblyAttributeSingle: too much data received.\r\n");
                      pa_pstMRResponse->GeneralStatus = CIP_ERROR_TOO_MUCH_DATA;
                    }
                  else
                    {
                      memcpy(pacData->Data, acReqData, pacData->len);

                      if(IApp_AfterAssemblyDataReceived(pa_pstInstance)
                         != EIP_OK)
                        {
                          /* punt early without updating the status... though I don't know
                           * how much this helps us here, as the attribute's data has already
                           * been overwritten.
                           *
                           * however this is the task of the application side which will
                           * take the data. In addition we have to inform the sender that the
                           * data was not ok.
                           */
                          pa_pstMRResponse->GeneralStatus
                            = CIP_ERROR_INVALID_ATTRIBUTE_VALUE;
                        }
                      else
                        {
                          pa_pstMRResponse->GeneralStatus = CIP_ERROR_SUCCESS;
                        }
                    }
                }
            }
        }
      else
        {
          /* the attribute was zero we are a heartbeat assembly */
          pa_pstMRResponse->GeneralStatus = CIP_ERROR_TOO_MUCH_DATA;
        }
    }

  return EIP_OK_SEND;
}
Example #7
0
/* create a new UDP socket for the connection manager
 returns the fd if successful, else -1 */
int
CreateUdpSocket(int pa_nDirection, struct sockaddr_in *pa_pstAddr)
{
  struct sockaddr_in stPeerAdr;
  int newfd;
#ifdef WIN32
  unsigned long nPeerAddrLen;
#else
  socklen_t nPeerAddrLen;
#endif

  nPeerAddrLen = sizeof(struct sockaddr_in);
  /* create a new UDP socket */
  if ((newfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
    {
      OPENER_TRACE_ERR("networkhandler: cannot create UDP socket: %s\n", strerror(errno));
      return kEipInvalidSocket;
    }

  OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", newfd);

  /* check if it is sending or receiving */
  if (pa_nDirection == kUdpCommuncationDirectionConsuming)
    {
      int nOptVal = 1;
      if (setsockopt(newfd, SOL_SOCKET, SO_REUSEADDR, (char *)&nOptVal, sizeof(nOptVal))
          == -1)
        {
          OPENER_TRACE_ERR("error setting socket option SO_REUSEADDR on consuming udp socket\n");
          return kEipStatusError;
        }

      /* bind is only for consuming necessary */
      if ((bind(newfd, (struct sockaddr *) pa_pstAddr, sizeof(struct sockaddr)))
          == -1)
        {
          OPENER_TRACE_ERR("error on bind udp: %s\n", strerror(errno));
          return kEipInvalidSocket;
        }

      OPENER_TRACE_INFO("networkhandler: bind UDP socket %d\n", newfd);
    }
  else
    { /* we have a producing udp socket */

      if (pa_pstAddr->sin_addr.s_addr == g_multicast_configuration.starting_multicast_address)
        {
          if (1 != g_time_to_live_value)
            { /* we need to set a TTL value for the socket */
              if (setsockopt(newfd, IPPROTO_IP, IP_MULTICAST_TTL,
                  &g_time_to_live_value, sizeof(g_time_to_live_value) < 0))
                {
                  OPENER_TRACE_ERR("networkhandler: could not set the TTL to: %d, error: %s\n", g_time_to_live_value, strerror(errno));
                  return kEipInvalidSocket;
                }
            }
        }
    }

  if ((pa_nDirection == kUdpCommuncationDirectionConsuming) || (0 == pa_pstAddr->sin_addr.s_addr))
    {
      /* we have a peer to peer producer or a consuming connection*/
      if (getpeername(g_current_active_tcp_socket, (struct sockaddr *) &stPeerAdr,
          &nPeerAddrLen) < 0)
        {
          OPENER_TRACE_ERR("networkhandler: could not get peername: %s\n", strerror(errno));
          return kEipInvalidSocket;
        }
      /* store the originators address */
      pa_pstAddr->sin_addr.s_addr = stPeerAdr.sin_addr.s_addr;
    }

  /* add new fd to the master list                                             */
  FD_SET(newfd, &master);
  if (newfd > fdmax)
    {
      fdmax = newfd;
    }
  return newfd;
}
Example #8
0
EipStatus
handleDataOnTCPSocket(int pa_nSocket)
{
  EipUint8 *rxp;
  long nCheckVal;
  size_t unDataSize;
  long nDataSent;
  int nRemainingBytes = 0;

  /* We will handle just one EIP packet here the rest is done by the select
   * method which will inform us if more data is available in the socket
   because of the current implementation of the main loop this may not be
   the fastest way and a loop here with a non blocking socket would better
   fit*/

  /*Check how many data is here -- read the first four bytes from the connection */
  nCheckVal = recv(pa_nSocket, g_ethernet_communciation_buffer, 4, 0); /*TODO we may have to set the socket to a non blocking socket */

  if (nCheckVal == 0)
    {
      OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n", strerror(errno));
      return kEipStatusError;
    }
  if (nCheckVal < 0)
    {
      OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
      return kEipStatusError;
    }

  rxp = &g_ethernet_communciation_buffer[2]; /* at this place EIP stores the data length */
  unDataSize = GetIntFromMessage(&rxp) + ENCAPSULATION_HEADER_LENGTH - 4; /* -4 is for the 4 bytes we have already read*/
  /* (NOTE this advances the buffer pointer) */
  if (PC_OPENER_ETHERNET_BUFFER_SIZE - 4 < unDataSize)
    { /*TODO can this be handled in a better way?*/
      OPENER_TRACE_ERR("too large packet received will be ignored, will drop the data\n");
      /* Currently we will drop the whole packet */
      nDataSent = PC_OPENER_ETHERNET_BUFFER_SIZE;

      do
        {
          nCheckVal = recv(pa_nSocket, g_ethernet_communciation_buffer, nDataSent, 0);

          if (nCheckVal == 0) /* got error or connection closed by client */
            {
              OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n", strerror(errno));
              return kEipStatusError;
            }
          if (nCheckVal < 0)
            {
              OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
              return kEipStatusError;
            }
          unDataSize -= nCheckVal;
          if ((unDataSize < PC_OPENER_ETHERNET_BUFFER_SIZE)
              && (unDataSize != 0))
            {
              nDataSent = unDataSize;
            }
        }
      while (0 != unDataSize); /*TODO fragile end statement */
      return kEipStatusOk;
    }

  nCheckVal = recv(pa_nSocket, &g_ethernet_communciation_buffer[4], unDataSize, 0);

  if (nCheckVal == 0) /* got error or connection closed by client */
    {
      OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n", strerror(errno));
      return kEipStatusError;
    }
  if (nCheckVal < 0)
    {
      OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
      return kEipStatusError;
    }

  if ((unsigned) nCheckVal == unDataSize)
    {
      /*we got the right amount of data */
      unDataSize += 4;
      /*TODO handle partial packets*/
      OPENER_TRACE_INFO("Data received on tcp:\n");

      g_current_active_tcp_socket = pa_nSocket;

      nCheckVal = HandleReceivedExplictTcpData(pa_nSocket,
          g_ethernet_communciation_buffer, unDataSize, &nRemainingBytes);

      g_current_active_tcp_socket = -1;

      if (nRemainingBytes != 0)
        {
          OPENER_TRACE_WARN("Warning: received packet was to long: %d Bytes left!\n",
              nRemainingBytes);
        }

      if (nCheckVal > 0)
        {
          OPENER_TRACE_INFO("reply sent:\n");

          nDataSent = send(pa_nSocket, (char *) g_ethernet_communciation_buffer,
              nCheckVal, 0);
          if (nDataSent != nCheckVal)
            {
              OPENER_TRACE_WARN("TCP response was not fully sent\n");
            }
        }

      return kEipStatusOk;
    }
  else
    {
      /* we got a fragmented packet currently we cannot handle this will
       * for this we would need a network buffer per TCP socket
       *
       * However with typical packet sizes of EIP this should't be a big issue.
       */
      /*TODO handle fragmented packets */
    }
  return kEipStatusError;
}