Browse Source

added the pubsubtsn architecture, that allows to send all UDP traffic with highest routing priority 7

thomas 4 years ago
parent
commit
d85503f975

+ 1 - 0
arch/CMakeLists.txt

@@ -8,6 +8,7 @@ add_subdirectory(freertosLWIP)
 add_subdirectory(vxworks)
 add_subdirectory(eCos)
 add_subdirectory(wec7)
+add_subdirectory(pubsubtsn)
 
 SET(UA_ARCH_EXTRA_INCLUDES "" CACHE STRING "Folders to include from the architecture")
 mark_as_advanced(UA_ARCH_EXTRA_INCLUDES)

+ 36 - 0
arch/pubsubtsn/CMakeLists.txt

@@ -0,0 +1,36 @@
+SET(SOURCE_GROUP ${SOURCE_GROUP}\\pubsubtsn)
+
+ua_add_architecture("pubsubtsn")
+
+list (FIND UA_AMALGAMATION_ARCHITECTURES "pubsubtsn" _index)
+if (${_index} GREATER -1 OR "${UA_ARCHITECTURE}" STREQUAL "pubsubtsn")
+
+    ua_add_architecture_file(${CMAKE_CURRENT_SOURCE_DIR}/ua_clock.c)
+    ua_add_architecture_file(${CMAKE_CURRENT_SOURCE_DIR}/ua_architecture_functions.c)
+
+
+    if("${UA_ARCHITECTURE}" STREQUAL "pubsubtsn")
+        if(NOT CYGWIN AND NOT QNXNTO AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
+            ua_architecture_add_definitions(-Wshadow -Wconversion -fvisibility=hidden -fPIC)
+        endif()
+
+        if(QNXNTO)
+          ua_architecture_append_to_library(socket c stdc++)
+        elseif(OS9)
+          ua_architecture_append_to_library(netdb ndblib socket)
+        else()
+          ua_architecture_append_to_library(m)
+          #TODO - Error on first make run if pthread is included conditional?
+          ua_architecture_append_to_library(pthread)
+          if(UA_ENABLE_MULTITHREADING OR UA_BUILD_UNIT_TESTS)
+            ua_architecture_append_to_library(pthread)
+          endif()
+          if(NOT APPLE AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
+            ua_architecture_append_to_library(rt)
+          endif()
+        endif()
+
+    endif()
+
+
+endif()

+ 271 - 0
arch/pubsubtsn/ua_architecture.h

@@ -0,0 +1,271 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ *    Thomas Frühwirht, TU Wien
+ *    based on the posix architecture by
+ *    Copyright 2016-2017 (c) Julius Pfrommer, Fraunhofer IOSB
+ *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ */
+
+#ifdef UA_ARCHITECTURE_PUBSUBTSN
+
+#ifndef PLUGINS_ARCH_PUBSUBTSN_UA_ARCHITECTURE_H_
+#define PLUGINS_ARCH_PUBSUBTSN_UA_ARCHITECTURE_H_
+
+#include <open62541/architecture_base.h>
+
+/* Enable OpenIL_TSN features */
+#if !defined(_XOPEN_SOURCE)
+# define _XOPEN_SOURCE 600
+#endif
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
+/* On older systems we need to define _BSD_SOURCE.
+ * _DEFAULT_SOURCE is an alias for that. */
+#ifndef _BSD_SOURCE
+# define _BSD_SOURCE
+#endif
+
+#include <errno.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <net/if.h>
+#ifndef UA_sleep_ms
+# include <unistd.h>
+# define UA_sleep_ms(X) usleep(X * 1000)
+#endif
+
+#define OPTVAL_TYPE int
+
+#include <fcntl.h>
+#include <unistd.h> // read, write, close
+
+#ifdef __QNX__
+# include <sys/socket.h>
+#endif
+#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
+# include <sys/param.h>
+# if defined(BSD)
+#  include<sys/socket.h>
+# endif
+#endif
+#if !defined(__CYGWIN__)
+# include <netinet/tcp.h>
+#endif
+
+/* unsigned int for windows and workaround to a glibc bug */
+/* Additionally if GNU_LIBRARY is not defined, it may be using
+ * musl libc (e.g. Docker Alpine) */
+#if  defined(__OpenBSD__) || \
+    (defined(__GNU_LIBRARY__) && (__GNU_LIBRARY__ <= 6) && \
+     (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 16) || \
+    !defined(__GNU_LIBRARY__))
+# define UA_fd_set(fd, fds) FD_SET((unsigned int)fd, fds)
+# define UA_fd_isset(fd, fds) FD_ISSET((unsigned int)fd, fds)
+#else
+# define UA_fd_set(fd, fds) FD_SET(fd, fds)
+# define UA_fd_isset(fd, fds) FD_ISSET(fd, fds)
+#endif
+
+#define UA_access access
+
+#define UA_IPV6 1
+#define UA_SOCKET int
+#define UA_INVALID_SOCKET -1
+#define UA_ERRNO errno
+#define UA_INTERRUPTED EINTR
+#define UA_AGAIN EAGAIN
+#define UA_EAGAIN EAGAIN
+#define UA_WOULDBLOCK EWOULDBLOCK
+#define UA_ERR_CONNECTION_PROGRESS EINPROGRESS
+
+#define UA_ENABLE_LOG_COLORS
+
+#define UA_getnameinfo getnameinfo
+#define UA_send send_TSN
+#define UA_recv recv
+#define UA_sendto sendto_TSN
+#define UA_recvfrom recvfrom
+#define UA_htonl htonl
+#define UA_ntohl ntohl
+#define UA_close close
+#define UA_select select
+#define UA_shutdown shutdown
+#define UA_socket socket_TSN
+#define UA_bind bind_TSN
+#define UA_listen listen
+#define UA_accept accept
+#define UA_connect connect
+#define UA_getaddrinfo getaddrinfo
+#define UA_getsockopt getsockopt
+#define UA_setsockopt setsockopt
+#define UA_freeaddrinfo freeaddrinfo
+#define UA_gethostname gethostname
+#define UA_getsockname getsockname
+#define UA_inet_pton inet_pton
+#if UA_IPV6
+# define UA_if_nametoindex if_nametoindex
+#endif
+
+int socket_TSN(int domain, int type, int protocol);
+int bind_TSN(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+ssize_t send_TSN(int sockfd, const void *buf, size_t len, int flags);
+ssize_t sendto_TSN(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
+
+#ifdef UA_ENABLE_MALLOC_SINGLETON
+extern void * (*UA_globalMalloc)(size_t size);
+extern void (*UA_globalFree)(void *ptr);
+extern void * (*UA_globalCalloc)(size_t nelem, size_t elsize);
+extern void * (*UA_globalRealloc)(void *ptr, size_t size);
+
+# define UA_free(ptr) UA_globalFree(ptr)
+# define UA_malloc(size) UA_globalMalloc(size)
+# define UA_calloc(num, size) UA_globalCalloc(num, size)
+# define UA_realloc(ptr, size) UA_globalRealloc(ptr, size)
+#endif
+
+#include <stdlib.h>
+#ifndef UA_free
+# define UA_free free
+#endif
+#ifndef UA_malloc
+# define UA_malloc malloc
+#endif
+#ifndef UA_calloc
+# define UA_calloc calloc
+#endif
+#ifndef UA_realloc
+# define UA_realloc realloc
+#endif
+
+#include <stdio.h>
+#define UA_snprintf snprintf
+
+#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) { \
+    char *errno_str = strerror(errno); \
+    LOG; \
+}
+#define UA_LOG_SOCKET_ERRNO_GAI_WRAP(LOG) { \
+    const char *errno_str = gai_strerror(errno); \
+    LOG; \
+}
+
+#include <open62541/architecture_functions.h>
+
+#if defined(__APPLE__)  && defined(_SYS_QUEUE_H_)
+//  in some compilers there's already a _SYS_QUEUE_H_ which is included first and doesn't have all functions
+
+#undef SLIST_HEAD
+#undef SLIST_HEAD_INITIALIZER
+#undef SLIST_ENTRY
+#undef SLIST_FIRST
+#undef SLIST_END
+#undef SLIST_EMPTY
+#undef SLIST_NEXT
+#undef SLIST_FOREACH
+#undef SLIST_FOREACH_SAFE
+#undef SLIST_INIT
+#undef SLIST_INSERT_AFTER
+#undef SLIST_INSERT_HEAD
+#undef SLIST_REMOVE_AFTER
+#undef SLIST_REMOVE_HEAD
+#undef SLIST_REMOVE
+#undef LIST_HEAD
+#undef LIST_HEAD_INITIALIZER
+#undef LIST_ENTRY
+#undef LIST_FIRST
+#undef LIST_END
+#undef LIST_EMPTY
+#undef LIST_NEXT
+#undef LIST_FOREACH
+#undef LIST_FOREACH_SAFE
+#undef LIST_INIT
+#undef LIST_INSERT_AFTER
+#undef LIST_INSERT_BEFORE
+#undef LIST_INSERT_HEAD
+#undef LIST_REMOVE
+#undef LIST_REPLACE
+#undef SIMPLEQ_HEAD
+#undef SIMPLEQ_HEAD_INITIALIZER
+#undef SIMPLEQ_ENTRY
+#undef SIMPLEQ_FIRST
+#undef SIMPLEQ_END
+#undef SIMPLEQ_EMPTY
+#undef SIMPLEQ_NEXT
+#undef SIMPLEQ_FOREACH
+#undef SIMPLEQ_FOREACH_SAFE
+#undef SIMPLEQ_INIT
+#undef SIMPLEQ_INSERT_HEAD
+#undef SIMPLEQ_INSERT_TAIL
+#undef SIMPLEQ_INSERT_AFTER
+#undef SIMPLEQ_REMOVE_HEAD
+#undef SIMPLEQ_REMOVE_AFTER
+#undef XSIMPLEQ_HEAD
+#undef XSIMPLEQ_ENTRY
+#undef XSIMPLEQ_XOR
+#undef XSIMPLEQ_FIRST
+#undef XSIMPLEQ_END
+#undef XSIMPLEQ_EMPTY
+#undef XSIMPLEQ_NEXT
+#undef XSIMPLEQ_FOREACH
+#undef XSIMPLEQ_FOREACH_SAFE
+#undef XSIMPLEQ_INIT
+#undef XSIMPLEQ_INSERT_HEAD
+#undef XSIMPLEQ_INSERT_TAIL
+#undef XSIMPLEQ_INSERT_AFTER
+#undef XSIMPLEQ_REMOVE_HEAD
+#undef XSIMPLEQ_REMOVE_AFTER
+#undef TAILQ_HEAD
+#undef TAILQ_HEAD_INITIALIZER
+#undef TAILQ_ENTRY
+#undef TAILQ_FIRST
+#undef TAILQ_END
+#undef TAILQ_NEXT
+#undef TAILQ_LAST
+#undef TAILQ_PREV
+#undef TAILQ_EMPTY
+#undef TAILQ_FOREACH
+#undef TAILQ_FOREACH_SAFE
+#undef TAILQ_FOREACH_REVERSE
+#undef TAILQ_FOREACH_REVERSE_SAFE
+#undef TAILQ_INIT
+#undef TAILQ_INSERT_HEAD
+#undef TAILQ_INSERT_TAIL
+#undef TAILQ_INSERT_AFTER
+#undef TAILQ_INSERT_BEFORE
+#undef TAILQ_REMOVE
+#undef TAILQ_REPLACE
+#undef CIRCLEQ_HEAD
+#undef CIRCLEQ_HEAD_INITIALIZER
+#undef CIRCLEQ_ENTRY
+#undef CIRCLEQ_FIRST
+#undef CIRCLEQ_LAST
+#undef CIRCLEQ_END
+#undef CIRCLEQ_NEXT
+#undef CIRCLEQ_PREV
+#undef CIRCLEQ_EMPTY
+#undef CIRCLEQ_FOREACH
+#undef CIRCLEQ_FOREACH_SAFE
+#undef CIRCLEQ_FOREACH_REVERSE
+#undef CIRCLEQ_FOREACH_REVERSE_SAFE
+#undef CIRCLEQ_INIT
+#undef CIRCLEQ_INSERT_AFTER
+#undef CIRCLEQ_INSERT_BEFORE
+#undef CIRCLEQ_INSERT_HEAD
+#undef CIRCLEQ_INSERT_TAIL
+#undef CIRCLEQ_REMOVE
+#undef CIRCLEQ_REPLACE
+
+#undef _SYS_QUEUE_H_
+
+#endif /* defined(__APPLE__)  && defined(_SYS_QUEUE_H_) */
+
+
+#endif /* PLUGINS_ARCH_PUBSUBTSN_UA_ARCHITECTURE_H_ */
+
+#endif /* UA_ARCHITECTURE_PUBSUBTSN */

+ 87 - 0
arch/pubsubtsn/ua_architecture_functions.c

@@ -0,0 +1,87 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ *    Copyright 2018 (c) Jose Cabral, fortiss GmbH
+ */
+
+#ifdef UA_ARCHITECTURE_PUBSUBTSN
+
+#include <open62541/types.h>
+
+/* Global malloc singletons */
+#ifdef UA_ENABLE_MALLOC_SINGLETON
+void * (*UA_globalMalloc)(size_t size) = malloc;
+void (*UA_globalFree)(void *ptr) = free;
+void * (*UA_globalCalloc)(size_t nelem, size_t elsize) = calloc;
+void * (*UA_globalRealloc)(void *ptr, size_t size) = realloc;
+#endif
+
+unsigned int UA_socket_set_blocking(UA_SOCKET sockfd){
+  int opts = fcntl(sockfd, F_GETFL);
+  if(opts < 0 || fcntl(sockfd, F_SETFL, opts & (~O_NONBLOCK)) < 0)
+      return UA_STATUSCODE_BADINTERNALERROR;
+  return UA_STATUSCODE_GOOD;
+}
+
+unsigned int UA_socket_set_nonblocking(UA_SOCKET sockfd){
+  int opts = fcntl(sockfd, F_GETFL);
+  if(opts < 0 || fcntl(sockfd, F_SETFL, opts | O_NONBLOCK) < 0)
+    return UA_STATUSCODE_BADINTERNALERROR;
+  return UA_STATUSCODE_GOOD;
+}
+
+void UA_initialize_architecture_network(void){
+}
+
+void UA_deinitialize_architecture_network(void){
+}
+
+unsigned int scheduledTrafficClass=7; // valid values are in the range [1,7]; 1−low priority, 7−high priority
+int socket_TSN(int domain, int type, int protocol){
+    int socketfd = socket(domain, type, protocol);
+
+    if(type == SOCK_STREAM) {
+        printf("socket_TSN: creating a TCP socket\n");
+    } else if(type == SOCK_DGRAM) {
+        // TFR: It is assumed that UDP sockets are only used for PubSub and shell be sent as scheduled traffic with highest priority
+        // TFR: This assumption may not be accurate in any circumstance, but is goot enough for testing at the moment
+        printf("socket_TSN: creating a UDP socket\n");
+        int res = setsockopt(socketfd, SOL_SOCKET, SO_PRIORITY, &scheduledTrafficClass, sizeof(scheduledTrafficClass));
+        if(res != 0){
+            fprintf(stderr, "Could not set socket priority. Failed with error code %d\n", res);
+            return EXIT_FAILURE;
+        } else {
+            printf("socket_TSN: Successfully set priority for socket %d to 7\n", socketfd);
+        }
+    } else {
+        printf("socket_TSN: creating a socket of unknown type\n");
+    }
+
+    return socketfd;
+}
+
+int bind_TSN(int sockfd, const struct sockaddr *addr, socklen_t addrlen){
+    // printf("bind_TSN\n");
+    // char *ip = inet_ntoa(addr->sin_addr);
+    // printf("bind_TSN to %s\n", ip);
+    // TFR TODO: Check if the socket should be used for scheduled traffic based on its IP address
+    // TFR TOOD: If so, set the SO_PRIORITY to 7
+    /*
+    int traffic_class=7 // valid values are in the range [1,7]; 1−low priority, 7−high priority
+    if(setsockopt(socketfd, SOL_SOCKET, SO_PRIORITY, &traffic_class, sizeof(traffic_class)) != 0)
+    {
+        fprintf(stderr,"Could not set socket priority\n");
+        exit(-3);
+    }
+    */
+    return bind(sockfd, addr, addrlen);
+}
+
+ssize_t send_TSN(int sockfd, const void *buf, size_t len, int flags){
+    return send(sockfd, buf, len, flags);
+}
+
+ssize_t sendto_TSN(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen){
+    return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
+}
+#endif /* UA_ARCHITECTURE_PUBSUBTSN */

+ 60 - 0
arch/pubsubtsn/ua_clock.c

@@ -0,0 +1,60 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. 
+ *
+ *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
+ *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
+ */
+
+#ifdef UA_ARCHITECTURE_PUBSUBTSN
+
+#include <open62541/types.h>
+
+#include <time.h>
+
+#include <sys/time.h>
+
+#if defined(__APPLE__) || defined(__MACH__)
+# include <mach/clock.h>
+# include <mach/mach.h>
+#endif
+
+UA_DateTime UA_DateTime_now(void) {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (tv.tv_sec * UA_DATETIME_SEC) + (tv.tv_usec * UA_DATETIME_USEC) + UA_DATETIME_UNIX_EPOCH;
+}
+
+/* Credit to https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c */
+UA_Int64 UA_DateTime_localTimeUtcOffset(void) {
+    time_t gmt, rawtime = time(NULL);
+    struct tm *ptm;
+    struct tm gbuf;
+    ptm = gmtime_r(&rawtime, &gbuf);
+    // Request that mktime() looksup dst in timezone database
+    ptm->tm_isdst = -1;
+    gmt = mktime(ptm);
+    return (UA_Int64) (difftime(rawtime, gmt) * UA_DATETIME_SEC);
+}
+
+UA_DateTime UA_DateTime_nowMonotonic(void) {
+#if defined(__APPLE__) || defined(__MACH__)
+    /* OS X does not have clock_gettime, use clock_get_time */
+    clock_serv_t cclock;
+    mach_timespec_t mts;
+    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+    clock_get_time(cclock, &mts);
+    mach_port_deallocate(mach_task_self(), cclock);
+    return (mts.tv_sec * UA_DATETIME_SEC) + (mts.tv_nsec / 100);
+#elif !defined(CLOCK_MONOTONIC_RAW)
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100);
+#else
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100);
+#endif
+}
+
+#endif /* UA_ARCHITECTURE_PUBSUBTSN */