瀏覽代碼

Merge pull request #294 from EIPStackGroup/AddUdpProtocolTests

Add udp protocol tests
Martin Melik-Merkumians 5 年之前
父節點
當前提交
2fe8c570db

+ 1 - 1
source/CMakeLists.txt

@@ -141,7 +141,7 @@ if( OpENer_TESTS )
   INCLUDE( ${OpENer_BUILDSUPPORT_DIR}/CodeCoverage.cmake )
   APPEND_COVERAGE_COMPILER_FLAGS()
   # The used CppUTest framework does not support parallel jobs
-  SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${PROJECT_NAME}_coverage EXECUTABLE OpENer_Tests EXCLUDE "tests/*" "src/ports/*/sample_application/*")
+  SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${PROJECT_NAME}_coverage EXECUTABLE OpENer_Tests EXCLUDE "tests/*" "src/ports/*/sample_application/*" "${CPPUTEST_HOME}/*")
   add_test_includes()
   add_subdirectory( tests )
 endif( OpENer_TESTS )

+ 1 - 1
source/src/cip/cipmessagerouter.c

@@ -213,7 +213,7 @@ EipStatus NotifyMessageRouter(EipUint8 *data,
       /* call notify function from Object with ClassID (gMRRequest.RequestPath.ClassID)
          object will or will not make an reply into gMRResponse*/
       message_router_response->reserved = 0;
-      OPENER_ASSERT(NULL != registered_object->cip_class)
+      OPENER_ASSERT(NULL != registered_object->cip_class);
       OPENER_TRACE_INFO(
         "NotifyMessageRouter: calling notify function of class '%s'\n",
         registered_object->cip_class->class_name);

+ 2 - 2
source/src/opener_api.h

@@ -819,8 +819,8 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
  * @return kEipStatusOk on success
  */
 EipStatus
-SendUdpData(struct sockaddr_in *socket_data,
-            int socket_handle,
+SendUdpData(const struct sockaddr_in *const socket_data,
+            const int socket_handle,
             const ENIPMessage *const outgoing_message);
 
 /** @ingroup CIP_CALLBACK_API

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

@@ -615,8 +615,8 @@ void CheckAndHandleUdpUnicastSocket(void) {
   }
 }
 
-EipStatus SendUdpData(struct sockaddr_in *address,
-                      int socket_handle,
+EipStatus SendUdpData(const struct sockaddr_in *const address,
+                      const int socket_handle,
                       const ENIPMessage *const outgoing_message) {
 
 
@@ -634,15 +634,11 @@ EipStatus SendUdpData(struct sockaddr_in *address,
          outgoing_message->message_buffer,
          outgoing_message->used_message_length);
   UDPHeaderGenerate(&header, (char *)complete_message);
-  UDPHeaderSetChecksum(&header,
-                       htons(UDPHeaderCalculateChecksum(complete_message,
-                                                        8 +
-                                                        outgoing_message->
-                                                        used_message_length,
-                                                        g_tcpip.
-                                                        interface_configuration
-                                                        .ip_address,
-                                                        address->sin_addr.s_addr) ) );
+  const uint16_t udp_checksum = UDPHeaderCalculateChecksum(complete_message,
+                                                           8 + outgoing_message->used_message_length,
+                                                           g_tcpip.interface_configuration.ip_address,
+                                                           address->sin_addr.s_addr);
+  UDPHeaderSetChecksum(&header, htons(udp_checksum) );
   UDPHeaderGenerate(&header, (char *)complete_message);
 
   int sent_length = sendto( socket_handle,
@@ -926,7 +922,8 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
 
   OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", new_socket);
 
-  {
+  /* check if it is sending or receiving */
+  if (communication_direction == kUdpCommuncationDirectionConsuming) {
     int option_value = 1;
     if (setsockopt( new_socket, SOL_SOCKET, SO_REUSEADDR,
                     (char *) &option_value,
@@ -938,10 +935,6 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
       CloseUdpSocket(new_socket);
       return kEipInvalidSocket;
     }
-  }
-
-  /* check if it is sending or receiving */
-  if (communication_direction == kUdpCommuncationDirectionConsuming) {
 
     /* bind is only for consuming necessary */
     if ( ( bind( new_socket, (struct sockaddr *) socket_data,

+ 22 - 19
source/src/ports/udp_protocol.c

@@ -4,7 +4,10 @@
  *
  ******************************************************************************/
 
+#include <assert.h>
 #include "udp_protocol.h"
+#include "trace.h"
+#include "opener_user_conf.h"
 
 #ifdef WIN32
 #include <winsock2.h>
@@ -62,39 +65,39 @@ uint16_t UDPHeaderCalculateChecksum(const void *udp_packet,
                                     const size_t udp_packet_length,
                                     const in_addr_t source_addr,
                                     const in_addr_t destination_addr) {
+  /* Checksum is calculated for 16-bit words */
   const uint16_t *udp_packet_words = udp_packet;
-  uint32_t checksum = 0;
-  size_t length = udp_packet_length;
-
-  // Process UDP packet
-  while(length > 1) {
-    checksum += *udp_packet_words++;
-    if(checksum & 0x8000000) {
-      checksum = (checksum & 0xFFFF) + (checksum >> 16);
-    }
-    length -= 2;
+  uint_fast32_t checksum = 0; /**< Carry bit access is needed (17th bit) */
+
+  uint16_t i = udp_packet_length;
+  for(; i > 1; i = i - 2 ) {
+    checksum +=  *udp_packet_words;
+    udp_packet_words++;
   }
 
-  if(0 != length % 2) {
-    // Add padding if packet length is odd
-    checksum += *( (uint8_t *)udp_packet_words );
+  OPENER_ASSERT( (0 == i) || (1 == i) ); /* data processed */
+
+  if (i > 0) {
+    checksum += (*( (uint8_t *)udp_packet_words ) << 8);
+    i--;
   }
+  OPENER_ASSERT(0 == i); /* data processed */
 
-  //Process IP pseudo header
-  uint16_t *source_addr_as_words = (void *)&source_addr;
+  const uint16_t *const source_addr_as_words =
+    (const uint16_t *const )&source_addr;
   checksum += *source_addr_as_words + *(source_addr_as_words + 1);
 
-  uint16_t *destination_addr_as_words = (void *)&destination_addr;
+  const uint16_t *const destination_addr_as_words =
+    (const uint16_t *const )&destination_addr;
   checksum += *destination_addr_as_words + *(destination_addr_as_words + 1);
-
   checksum += htons(IPPROTO_UDP);
   checksum += htons(udp_packet_length);
 
-  //Add the carries
-  while(0 != checksum >> 16) {
+  while(0xFFFF0000 & checksum) {
     checksum = (checksum & 0xFFFF) + (checksum >> 16);
   }
 
   // Return one's complement
   return (uint16_t)(~checksum);
 }
+

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

@@ -24,7 +24,8 @@
 typedef uint32_t in_addr_t;
 #endif
 
-static const size_t kUdpHeaderLength = 8U; /**< UDP header length in bytes */
+#define OPENER_UDP_HEADER_LENGTH (8U)
+static const size_t kUdpHeaderLength = OPENER_UDP_HEADER_LENGTH; /**< UDP header length in bytes */
 
 /** @brief Representing the needed information for the UDP header
  *

+ 1 - 0
source/tests/OpENerTests.h

@@ -11,3 +11,4 @@ IMPORT_TEST_GROUP(CipConnectionObject);
 IMPORT_TEST_GROUP(SocketTimer);
 IMPORT_TEST_GROUP(DoublyLinkedList);
 IMPORT_TEST_GROUP(EncapsulationProtocol);
+IMPORT_TEST_GROUP(UdpProtocol);

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

@@ -9,7 +9,7 @@ opener_common_includes()
 #######################################
 opener_platform_support("INCLUDES")
 
-set( PortsTestSrc socket_timer_tests.cpp )
+set( PortsTestSrc socket_timer_tests.cpp udp_protocol_tests.cpp)
 
 include_directories( ${SRC_DIR}/ports )
 

+ 126 - 0
source/tests/ports/udp_protocol_tests.cpp

@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2020, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+#include "ciptypes.h"
+#include "udp_protocol.h"
+}
+
+TEST_GROUP(UdpProtocol) {
+
+};
+
+TEST(UdpProtocol, SetSourcePort) {
+  UDPHeader header = {0};
+  UDPHeaderSetSourcePort(&header, 10);
+  CHECK_EQUAL( 10, header.source_port );
+}
+
+TEST(UdpProtocol, GetSourcePort) {
+  UDPHeader header = {0};
+  header.source_port =  5643;
+  CHECK_EQUAL( 5643, UDPHeaderGetSourcePort(&header) );
+}
+
+TEST(UdpProtocol, SetDestinationPort) {
+  UDPHeader header = {0};
+  header.destination_port = 1640;
+  CHECK_EQUAL( 1640, header.destination_port );
+}
+
+TEST(UdpProtocol, GetDestinationPort) {
+  UDPHeader header = {0};
+  UDPHeaderSetDestinationPort(&header, 9824);
+  CHECK_EQUAL( 9824, UDPHeaderGetDestinationPort(&header) );
+}
+
+TEST(UdpProtocol, SetPacketLength) {
+  UDPHeader header = {0};
+  UDPHeaderSetPacketLength(&header, 26814);
+  CHECK_EQUAL( 26814, header.packet_length);
+}
+
+TEST(UdpProtocol, GetPacketLength) {
+  UDPHeader header = {0};
+  header.packet_length = 36521;
+  CHECK_EQUAL( 36521, UDPHeaderGetPacketLength(&header) );
+}
+
+TEST(UdpProtocol, SetChecksum) {
+  UDPHeader header = {0};
+  UDPHeaderSetChecksum(&header, 0x8eaf);
+  CHECK_EQUAL( 0x8eaf, header.checksum);
+}
+
+TEST(UdpProtocol, GetChecksum) {
+  UDPHeader header = {0};
+  header.checksum = 0xaf8e;
+  CHECK_EQUAL( 0xaf8e, UDPHeaderGetChecksum(&header) );
+}
+
+TEST(UdpProtocol, HeaderGenerate) {
+  char message[OPENER_UDP_HEADER_LENGTH] = {0};
+  UDPHeader header = {0};
+  header.source_port =  5643;
+  header.destination_port = 1640;
+  header.packet_length = 36521;
+  header.checksum = 0xaf8e;
+  UDPHeaderGenerate(&header, message);
+  CHECK_EQUAL( htons(5643), *( (uint16_t *)message ) );
+  CHECK_EQUAL( htons(1640), *( ( (uint16_t *)message ) + 1 ) );
+  CHECK_EQUAL( htons(36521), *( ( (uint16_t *)message ) + 2 ) );
+  CHECK_EQUAL( htons(0xaf8e), *( ( (uint16_t *)message ) + 3 ) );
+}
+
+TEST(UdpProtocol, CalculateChecksumOddLength) {
+  char message[OPENER_UDP_HEADER_LENGTH + 13];
+  memset(message, 0, OPENER_UDP_HEADER_LENGTH + 13);
+  UDPHeader header = {0};
+  header.source_port =  5643;
+  header.destination_port = 1640;
+  header.packet_length = OPENER_UDP_HEADER_LENGTH + 13;
+  header.checksum = 0;
+  UDPHeaderGenerate(&header, message);
+  for(size_t i = kUdpHeaderLength; i < OPENER_UDP_HEADER_LENGTH + 13; i++) {
+    message[i] = i;
+  }
+
+  in_addr_t source_addr = 0x0A000001;
+  in_addr_t destination_addr = 0x0A000002;
+
+  uint16_t checksum = UDPHeaderCalculateChecksum(message,
+                                                 OPENER_UDP_HEADER_LENGTH + 13,
+                                                 source_addr,
+                                                 destination_addr);
+  CHECK_EQUAL(0xD591, checksum); // Aquired via the function under test - correctness verified via Wireshark
+}
+
+TEST(UdpProtocol, CalculateChecksumEvenLength) {
+  char message[OPENER_UDP_HEADER_LENGTH + 12];
+  memset(message, 0, OPENER_UDP_HEADER_LENGTH + 12);
+  UDPHeader header = {0};
+  header.source_port =  5643;
+  header.destination_port = 1640;
+  header.packet_length = OPENER_UDP_HEADER_LENGTH + 12;
+  header.checksum = 0;
+  UDPHeaderGenerate(&header, message);
+  for(size_t i = kUdpHeaderLength; i < OPENER_UDP_HEADER_LENGTH + 12; i++) {
+    message[i] = i;
+  }
+
+  in_addr_t source_addr = 0x0A000001;
+  in_addr_t destination_addr = 0x0A000002;
+
+  uint16_t checksum = UDPHeaderCalculateChecksum(message,
+                                                 OPENER_UDP_HEADER_LENGTH + 12,
+                                                 source_addr,
+                                                 destination_addr);
+  CHECK_EQUAL(0xEB91, checksum); // Aquired via the function under test - correctness verified via Wireshark
+}

+ 2 - 2
travis_scripts/linuxScript.sh

@@ -10,8 +10,8 @@ cmake -DOpENer_PLATFORM:STRING="POSIX" -DCMAKE_BUILD_TYPE:STRING="Debug" -DOpENe
   -DCPPUTEST_LIBRARY:FILEPATH=$TRAVIS_BUILD_DIR/source/dependencies/cpputest/src/CppUTest/libCppUTest.a \
   -DCPPUTESTEXT_LIBRARY:FILEPATH=$TRAVIS_BUILD_DIR/source/dependencies/cpputest/src/CppUTestExt/libCppUTestExt.a .
 build-wrapper-linux-x86-64 --out-dir bw-output make all
-make test
+ctest --output-on-failure
 make OpENer_coverage
 chmod +x $TRAVIS_BUILD_DIR/travis_scripts/compileGcovResults.sh
 $TRAVIS_BUILD_DIR/travis_scripts/compileGcovResults.sh
-sonar-scanner -Dproject.settings=$TRAVIS_BUILD_DIR/sonar-project.properties -Dsonar.sources=. -Dsonar.exclusions=OpENer_coverage/**,dependencies/**,CMakeFiles/** -Dsonar.cfamily.gcov.reportsPath=./gcov_results
+sonar-scanner -Dproject.settings=$TRAVIS_BUILD_DIR/sonar-project.properties -Dsonar.sources=. -Dsonar.exclusions=OpENer_coverage/**,dependencies/**,CMakeFiles/** -Dsonar.cfamily.gcov.reportsPath=./gcov_results