netutils/s2opc: add NuttX platform integration

Add Make and CMake packaging for the S2OPC 1.7.3 toolkit.

Assisted-by: OpenAI Codex:gpt-5
Signed-off-by: raiden00pl <raiden00@railab.me>
This commit is contained in:
raiden00pl 2026-08-20 14:34:42 +02:00 committed by Alan C. Assis
parent 0ae2c5391c
commit 35133b6a63
21 changed files with 4434 additions and 0 deletions

2
netutils/s2opc/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/s2opc
/S2OPC_Toolkit_*.tar.gz

View file

@ -0,0 +1,254 @@
# ##############################################################################
# apps/netutils/s2opc/CMakeLists.txt
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################
if(CONFIG_NETUTILS_S2OPC)
set(S2OPC_DIR ${CMAKE_CURRENT_LIST_DIR}/s2opc)
set(S2OPC_TAG S2OPC_Toolkit_${CONFIG_S2OPC_VERSION})
set(S2OPC_URL https://gitlab.com/systerel/S2OPC/-/archive/${S2OPC_TAG})
if(NOT EXISTS ${S2OPC_DIR})
FetchContent_Declare(
s2opc_fetch
URL ${S2OPC_URL}/S2OPC-${S2OPC_TAG}.tar.gz SOURCE_DIR ${S2OPC_DIR}
BINARY_DIR ${NUTTX_BINARY_DIR}/apps/netutils/s2opc/s2opc
DOWNLOAD_NO_PROGRESS true
TIMEOUT 60)
FetchContent_GetProperties(s2opc_fetch)
if(NOT s2opc_fetch_POPULATED)
FetchContent_Populate(s2opc_fetch)
endif()
endif()
set(S2OPC_COMMON ${S2OPC_DIR}/src/Common)
set(S2OPC_CS ${S2OPC_DIR}/src/ClientServer)
set(S2OPC_PS ${S2OPC_DIR}/src/PubSub)
set(S2OPC_PLATFORM ${S2OPC_COMMON}/helpers_platform_dep)
file(
GLOB
COMMON_SRCS
${S2OPC_COMMON}/configuration/*.c
${S2OPC_COMMON}/helpers/*.c
${S2OPC_COMMON}/opcua_types/*.c
${S2OPC_COMMON}/sks/*.c
${S2OPC_COMMON}/crypto/*.c
${S2OPC_COMMON}/crypto/lib_dep/mbedtls/*.c)
list(
APPEND
COMMON_SRCS
${S2OPC_PLATFORM}/sopc_askpass.c
${S2OPC_PLATFORM}/sopc_time_reference.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_askpass.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_atomic.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_date_time.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_eth_sockets.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_filesystem.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_mem_alloc.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_random.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_sockets.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_threads.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_time_reference.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/p_sopc_udp_sockets.c
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/sopc_build_info.c)
file(
GLOB
CLIENTSERVER_SRCS
${S2OPC_CS}/address_space/*.c
${S2OPC_CS}/address_space/internal/*.c
${S2OPC_CS}/api_toolkit/*.c
${S2OPC_CS}/configuration/*.c
${S2OPC_CS}/sockets/*.c
${S2OPC_CS}/secure_channels/*.c
${S2OPC_CS}/services/*.c
${S2OPC_CS}/services/b2c/*.c
${S2OPC_CS}/services/bgenc/*.c
${S2OPC_CS}/frontend/common_wrapper/*.c
${S2OPC_CS}/frontend/common_wrapper/certificate_management/internal/*.c
${S2OPC_CS}/frontend/helper_wrapper/*.c
${S2OPC_CS}/frontend/client_wrapper/*.c
${S2OPC_CS}/frontend/client_wrapper/internal/*.c
${S2OPC_CS}/frontend/client_wrapper/alarm_conditions/*.c
${S2OPC_CS}/frontend/server_wrapper/*.c
${S2OPC_CS}/frontend/server_wrapper/internal/*.c
${S2OPC_CS}/frontend/server_wrapper/file_transfer/*.c
${S2OPC_CS}/frontend/server_wrapper/alarm_conditions/*.c
${S2OPC_CS}/frontend/server_wrapper/alarm_conditions/internal/*.c
${S2OPC_CS}/loaders/address_space_loaders/embedded/*.c)
list(REMOVE_ITEM CLIENTSERVER_SRCS
${S2OPC_CS}/frontend/client_wrapper/libs2opc_client_config_xml.c
${S2OPC_CS}/frontend/server_wrapper/libs2opc_server_config_xml.c)
file(
GLOB
PUBSUB_SRCS
${S2OPC_PS}/common/*.c
${S2OPC_PS}/dataset/*.c
${S2OPC_PS}/network/*.c
${S2OPC_PS}/protocol/*.c
${S2OPC_PS}/publisher/*.c
${S2OPC_PS}/security/*.c
${S2OPC_PS}/subscriber/*.c)
if(CONFIG_S2OPC_XML_LOADERS)
file(
GLOB
XML_SRCS
${S2OPC_CS}/loaders/helpers/*.c
${S2OPC_CS}/loaders/address_space_loaders/xml_expat/*.c
${S2OPC_CS}/loaders/config_loaders/xml_expat/*.c
${S2OPC_PS}/config_loaders/xml_expat/*.c)
list(APPEND XML_SRCS
${S2OPC_CS}/frontend/client_wrapper/libs2opc_client_config_xml.c
${S2OPC_CS}/frontend/server_wrapper/libs2opc_server_config_xml.c)
endif()
# GCC 16 diagnoses upstream integer format strings on targets where uint32_t
# is unsigned long. Keep this suppression limited to the unmodified upstream
# sources that emit the diagnostics.
set_source_files_properties(${S2OPC_PS}/publisher/sopc_pub_scheduler.c
PROPERTIES COMPILE_FLAGS -Wno-format)
if(CONFIG_S2OPC_XML_LOADERS)
set_source_files_properties(
${S2OPC_CS}/loaders/config_loaders/xml_expat/sopc_users_loader.c
PROPERTIES COMPILE_FLAGS -Wno-format)
endif()
set(S2OPC_PUBLIC_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/port/nuttx
${S2OPC_COMMON}/configuration
${S2OPC_COMMON}/helpers
${S2OPC_COMMON}/helpers_platform_dep
${S2OPC_COMMON}/opcua_types
${S2OPC_COMMON}/crypto
${S2OPC_COMMON}/crypto/lib_itf
${S2OPC_COMMON}/crypto/lib_dep
${S2OPC_COMMON}/sks
${S2OPC_CS}/address_space
${S2OPC_CS}/api_toolkit
${S2OPC_CS}/configuration
${S2OPC_CS}/frontend/common_wrapper
${S2OPC_CS}/frontend/common_wrapper/certificate_management
${S2OPC_CS}/frontend/helper_wrapper
${S2OPC_CS}/frontend/client_wrapper
${S2OPC_CS}/frontend/client_wrapper/alarm_conditions
${S2OPC_CS}/frontend/server_wrapper
${S2OPC_CS}/frontend/server_wrapper/alarm_conditions
${S2OPC_CS}/frontend/server_wrapper/file_transfer
${S2OPC_CS}/loaders/address_space_loaders/embedded
${S2OPC_PS}/common
${S2OPC_PS}/dataset
${S2OPC_PS}/network
${S2OPC_PS}/protocol
${S2OPC_PS}/publisher
${S2OPC_PS}/security
${S2OPC_PS}/subscriber)
set(S2OPC_PRIVATE_INCLUDES
${S2OPC_COMMON}/crypto/lib_dep/mbedtls
${S2OPC_CS}/address_space/internal
${S2OPC_CS}/sockets
${S2OPC_CS}/secure_channels
${S2OPC_CS}/services
${S2OPC_CS}/services/b2c
${S2OPC_CS}/services/bgenc
${S2OPC_CS}/frontend/common_wrapper/internal
${S2OPC_CS}/frontend/common_wrapper/certificate_management/internal
${S2OPC_CS}/frontend/client_wrapper/internal
${S2OPC_CS}/frontend/server_wrapper/internal
${S2OPC_CS}/frontend/server_wrapper/alarm_conditions/internal)
if(CONFIG_S2OPC_XML_LOADERS)
list(
APPEND
S2OPC_PUBLIC_INCLUDES
${S2OPC_CS}/loaders/address_space_loaders
${S2OPC_CS}/loaders/address_space_loaders/xml_expat
${S2OPC_CS}/loaders/config_loaders
${S2OPC_CS}/loaders/config_loaders/xml_expat
${S2OPC_PS}/config_loaders/xml_expat)
list(APPEND S2OPC_PRIVATE_INCLUDES ${S2OPC_CS}/loaders/helpers)
endif()
set(S2OPC_FLAGS
-std=gnu99
-D_GNU_SOURCE
-DS2OPC_COMMON_STATIC_DEFINE
-DSOPC_TIME_T_SIZE=8
-include
${CMAKE_CURRENT_LIST_DIR}/port/nuttx/sopc_nuttx_config.h
-Wno-shadow
-Wno-cast-qual
-Wno-conversion
-Wno-missing-prototypes
-Wno-strict-prototypes
-Wno-unused-but-set-variable
-Wno-unused-function
-Wno-unused-variable)
if(CONFIG_S2OPC_XML_LOADERS)
list(APPEND S2OPC_FLAGS -DUANODESET_LOADER_LOG)
endif()
if(CONFIG_S2OPC_MQTT)
list(APPEND S2OPC_FLAGS -DUSE_MQTT_PAHO=1)
list(APPEND S2OPC_PRIVATE_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/../paho_mqtt/paho_mqtt/src)
else()
list(APPEND S2OPC_FLAGS -DUSE_MQTT_PAHO=0)
endif()
if(CONFIG_ARCH_64BIT)
list(APPEND S2OPC_FLAGS -DSOPC_PTR_SIZE=8)
else()
list(APPEND S2OPC_FLAGS -DSOPC_PTR_SIZE=4)
endif()
if(CONFIG_ENDIAN_BIG)
list(APPEND S2OPC_FLAGS -DSOPC_IS_LITTLE_ENDIAN=0)
else()
list(APPEND S2OPC_FLAGS -DSOPC_IS_LITTLE_ENDIAN=1)
endif()
nuttx_add_library(s2opc STATIC)
target_sources(s2opc PRIVATE ${COMMON_SRCS} ${CLIENTSERVER_SRCS}
${PUBSUB_SRCS} ${XML_SRCS})
target_include_directories(
s2opc
PUBLIC ${S2OPC_PUBLIC_INCLUDES}
PRIVATE ${S2OPC_PRIVATE_INCLUDES})
target_compile_options(s2opc PRIVATE ${S2OPC_FLAGS})
nuttx_export_header(TARGET s2opc INCLUDE_DIRECTORIES ${S2OPC_PUBLIC_INCLUDES})
nuttx_add_dependencies(TARGET s2opc DEPENDS mbedtls)
if(CONFIG_S2OPC_XML_LOADERS)
nuttx_add_dependencies(TARGET s2opc DEPENDS expat)
endif()
if(CONFIG_S2OPC_MQTT)
nuttx_add_dependencies(TARGET s2opc DEPENDS mqtt5)
endif()
endif()

109
netutils/s2opc/Kconfig Normal file
View file

@ -0,0 +1,109 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig NETUTILS_S2OPC
bool "S2OPC OPC UA toolkit"
default n
depends on CRYPTO_MBEDTLS
depends on LIBC_NETDB && PTHREAD_MUTEX_TYPES
depends on NET_TCP && NET_UDP
depends on NET_SOCKOPTS && NET_TCP_KEEPALIVE
depends on DEV_URANDOM
depends on RR_INTERVAL > 0
depends on NET_BINDTODEVICE
---help---
Enable the S2OPC OPC UA client/server and UDP PubSub toolkit. The
selected S2OPC release is downloaded when the applications tree is
configured. A cryptographically suitable random source is required
when secure OPC UA policies are used. Certificate validation also
requires a correctly initialized system clock. A round-robin
timeslice is required for normal S2OPC worker threads.
if NETUTILS_S2OPC
config S2OPC_VERSION
string "S2OPC version"
default "1.7.3"
config S2OPC_THREAD_STACKSIZE
int "S2OPC worker thread stack size"
default 32768
range PTHREAD_STACK_MIN 1048576
---help---
Stack size assigned to worker threads created by S2OPC. Secure OPC
UA processing needs considerably more stack than small NuttX tasks.
config S2OPC_XML_LOADERS
bool "Enable XML configuration loaders"
default n
depends on ALLOW_MIT_COMPONENTS
depends on LIB_EXPAT
---help---
Enable the S2OPC client, server, user, address-space, and PubSub XML
loaders. This adds the Expat XML parser dependency. Leave this
disabled when configuration and address-space data are constructed
with the S2OPC C APIs or generated as C source.
config S2OPC_NODE_MANAGEMENT
bool "Enable OPC UA Node Management services"
default n
---help---
Enable the AddNodes and DeleteNodes services. The configured server
address space must be dynamically allocated for these services to
modify it.
config S2OPC_NODE_ADD_OPTIONAL
bool "Add optional child nodes with Node Management"
default n
depends on S2OPC_NODE_MANAGEMENT
---help---
Add optional child nodes declared by a type when AddNodes creates an
object, variable, or method node. Mandatory child nodes are added
regardless of this option.
config S2OPC_HISTORY_READ
bool "Enable external HistoryRead Raw service"
default n
---help---
Enable S2OPC's HistoryRead Raw service. The application must provide
the external history-read callback and its underlying history store.
config S2OPC_EVENT_MANAGEMENT
bool "Enable OPC UA Events"
default n
---help---
Enable server event creation, triggering, and event monitored items.
The configured address space must contain the required event types.
config S2OPC_AUDITING
bool "Enable OPC UA security auditing"
default n
depends on S2OPC_EVENT_MANAGEMENT
---help---
Enable S2OPC's auditing support. S2OPC 1.7.3 limits auditing to
security audit event types and requires OPC UA Events.
config S2OPC_MQTT
bool "Enable MQTT PubSub transport"
default n
depends on LIB_MQTT5
---help---
Enable the S2OPC MQTT PubSub transport using the Eclipse Paho MQTT
Async library packaged by NuttX.
config S2OPC_ETHERNET
bool "Enable raw Ethernet PubSub transport"
default n
depends on NET_PKT
depends on NET_MCASTGROUP
depends on NET_PKTPROTO_OPTIONS
---help---
Enable UADP PubSub over raw Ethernet packet sockets. Multicast
reception requires a network driver that implements multicast MAC
filtering. The NuttX packet-socket implementation requires an
interface name and a destination multicast MAC address. A combined
publisher/subscriber needs at least two packet-socket connections.
endif # NETUTILS_S2OPC

68
netutils/s2opc/Make.defs Normal file
View file

@ -0,0 +1,68 @@
############################################################################
# apps/netutils/s2opc/Make.defs
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifneq ($(CONFIG_NETUTILS_S2OPC),)
CONFIGURED_APPS += $(APPDIR)/netutils/s2opc
S2OPC_ROOT = $(APPDIR)/netutils/s2opc/s2opc
S2OPC_COMMON = $(S2OPC_ROOT)/src/Common
S2OPC_CLIENTSERVER = $(S2OPC_ROOT)/src/ClientServer
S2OPC_PUBSUB = $(S2OPC_ROOT)/src/PubSub
S2OPC_CS_LOADERS = $(S2OPC_CLIENTSERVER)/loaders
S2OPC_AS_LOADERS = $(S2OPC_CS_LOADERS)/address_space_loaders
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(APPDIR)/netutils/s2opc/port/nuttx
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/configuration
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/helpers
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/helpers_platform_dep
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/opcua_types
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/crypto
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/crypto/lib_itf
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/crypto/lib_dep
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_COMMON)/sks
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/address_space
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/api_toolkit
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/configuration
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/frontend/common_wrapper
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/frontend/helper_wrapper
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/frontend/client_wrapper
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CLIENTSERVER)/frontend/server_wrapper
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_AS_LOADERS)/embedded
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/common
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/dataset
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/network
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/protocol
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/publisher
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/security
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/subscriber
ifeq ($(CONFIG_S2OPC_XML_LOADERS),y)
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_AS_LOADERS)
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_AS_LOADERS)/xml_expat
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CS_LOADERS)/config_loaders
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_CS_LOADERS)/config_loaders/xml_expat
S2OPC_INCLUDES += ${INCDIR_PREFIX}$(S2OPC_PUBSUB)/config_loaders/xml_expat
endif
CFLAGS += $(S2OPC_INCLUDES)
CXXFLAGS += $(S2OPC_INCLUDES)
endif

195
netutils/s2opc/Makefile Normal file
View file

@ -0,0 +1,195 @@
############################################################################
# apps/netutils/s2opc/Makefile
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
S2OPC_VERSION = $(patsubst "%",%,$(CONFIG_S2OPC_VERSION))
S2OPC_TAG = S2OPC_Toolkit_$(S2OPC_VERSION)
S2OPC_ARCHIVE = $(S2OPC_TAG).tar.gz
S2OPC_ARCHIVES = $(wildcard S2OPC_Toolkit_*.tar.gz)
S2OPC_SRCDIR = s2opc
S2OPC_URL ?= https://gitlab.com/systerel/S2OPC/-/archive
S2OPC_COMMON = $(S2OPC_SRCDIR)/src/Common
S2OPC_CS = $(S2OPC_SRCDIR)/src/ClientServer
S2OPC_PS = $(S2OPC_SRCDIR)/src/PubSub
S2OPC_PLATFORM = $(S2OPC_COMMON)/helpers_platform_dep
S2OPC_CSCERT = $(S2OPC_CS)/frontend/common_wrapper/certificate_management
S2OPC_CSALARM = $(S2OPC_CS)/frontend/server_wrapper/alarm_conditions
S2OPC_CS_XML_WRAPPERS = \
$(S2OPC_CS)/frontend/client_wrapper/libs2opc_client_config_xml.c \
$(S2OPC_CS)/frontend/server_wrapper/libs2opc_server_config_xml.c
CSRCS += $(wildcard $(S2OPC_COMMON)/configuration/*.c)
CSRCS += $(wildcard $(S2OPC_COMMON)/helpers/*.c)
CSRCS += $(wildcard $(S2OPC_COMMON)/opcua_types/*.c)
CSRCS += $(wildcard $(S2OPC_COMMON)/sks/*.c)
CSRCS += $(wildcard $(S2OPC_COMMON)/crypto/*.c)
CSRCS += $(wildcard $(S2OPC_COMMON)/crypto/lib_dep/mbedtls/*.c)
CSRCS += $(S2OPC_PLATFORM)/sopc_askpass.c
CSRCS += $(S2OPC_PLATFORM)/sopc_time_reference.c
CSRCS += port/nuttx/p_sopc_askpass.c
CSRCS += port/nuttx/p_sopc_atomic.c
CSRCS += port/nuttx/p_sopc_date_time.c
CSRCS += port/nuttx/p_sopc_eth_sockets.c
CSRCS += port/nuttx/p_sopc_filesystem.c
CSRCS += port/nuttx/p_sopc_mem_alloc.c
CSRCS += port/nuttx/p_sopc_random.c
CSRCS += port/nuttx/p_sopc_sockets.c
CSRCS += port/nuttx/p_sopc_threads.c
CSRCS += port/nuttx/p_sopc_time_reference.c
CSRCS += port/nuttx/p_sopc_udp_sockets.c
CSRCS += port/nuttx/sopc_build_info.c
CSRCS += $(wildcard $(S2OPC_CS)/address_space/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/address_space/internal/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/api_toolkit/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/configuration/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/sockets/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/secure_channels/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/services/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/services/b2c/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/services/bgenc/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/frontend/common_wrapper/*.c)
CSRCS += $(wildcard $(S2OPC_CSCERT)/internal/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/frontend/helper_wrapper/*.c)
CSRCS += $(filter-out $(S2OPC_CS_XML_WRAPPERS), \
$(wildcard $(S2OPC_CS)/frontend/client_wrapper/*.c))
CSRCS += $(wildcard $(S2OPC_CS)/frontend/client_wrapper/internal/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/frontend/client_wrapper/alarm_conditions/*.c)
CSRCS += $(filter-out $(S2OPC_CS_XML_WRAPPERS), \
$(wildcard $(S2OPC_CS)/frontend/server_wrapper/*.c))
CSRCS += $(wildcard $(S2OPC_CS)/frontend/server_wrapper/internal/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/frontend/server_wrapper/file_transfer/*.c)
CSRCS += $(wildcard $(S2OPC_CSALARM)/*.c)
CSRCS += $(wildcard $(S2OPC_CSALARM)/internal/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/loaders/address_space_loaders/embedded/*.c)
ifeq ($(CONFIG_S2OPC_XML_LOADERS),y)
CSRCS += $(S2OPC_CS_XML_WRAPPERS)
CSRCS += $(wildcard $(S2OPC_CS)/loaders/helpers/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/loaders/address_space_loaders/xml_expat/*.c)
CSRCS += $(wildcard $(S2OPC_CS)/loaders/config_loaders/xml_expat/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/config_loaders/xml_expat/*.c)
$(S2OPC_CS)/loaders/config_loaders/xml_expat/sopc_users_loader.c_CFLAGS += \
-Wno-format
endif
CSRCS += $(wildcard $(S2OPC_PS)/common/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/dataset/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/network/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/protocol/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/publisher/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/security/*.c)
CSRCS += $(wildcard $(S2OPC_PS)/subscriber/*.c)
# GCC 16 diagnoses upstream integer format strings on targets where uint32_t
# is unsigned long. Keep this suppression limited to the unmodified upstream
# sources that emit the diagnostics.
$(S2OPC_PS)/publisher/sopc_pub_scheduler.c_CFLAGS += -Wno-format
CFLAGS += ${INCDIR_PREFIX}port/nuttx
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_COMMON)/crypto/lib_dep/mbedtls
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/address_space/internal
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/sockets
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/secure_channels
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/services
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/services/b2c
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/services/bgenc
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/frontend/common_wrapper/internal
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CSCERT)
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CSCERT)/internal
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/frontend/client_wrapper/internal
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/frontend/server_wrapper/internal
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/frontend/server_wrapper/file_transfer
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CSALARM)
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CSALARM)/internal
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/frontend/client_wrapper/alarm_conditions
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/loaders/address_space_loaders/embedded
CFLAGS += -std=gnu99 -D_GNU_SOURCE -DS2OPC_COMMON_STATIC_DEFINE
CFLAGS += -DSOPC_TIME_T_SIZE=8
CFLAGS += -include $(CURDIR)/port/nuttx/sopc_nuttx_config.h
CFLAGS += -Wno-shadow -Wno-cast-qual -Wno-conversion
CFLAGS += -Wno-missing-prototypes -Wno-strict-prototypes
CFLAGS += -Wno-unused-but-set-variable -Wno-unused-function
CFLAGS += -Wno-unused-variable
ifeq ($(CONFIG_S2OPC_XML_LOADERS),y)
CFLAGS += ${INCDIR_PREFIX}$(S2OPC_CS)/loaders/helpers
CFLAGS += -DUANODESET_LOADER_LOG
endif
ifeq ($(CONFIG_S2OPC_MQTT),y)
CFLAGS += -DUSE_MQTT_PAHO=1
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/netutils/paho_mqtt/paho_mqtt/src
else
CFLAGS += -DUSE_MQTT_PAHO=0
endif
ifeq ($(CONFIG_ARCH_64BIT),y)
CFLAGS += -DSOPC_PTR_SIZE=8
else
CFLAGS += -DSOPC_PTR_SIZE=4
endif
ifeq ($(CONFIG_ENDIAN_BIG),y)
CFLAGS += -DSOPC_IS_LITTLE_ENDIAN=0
else
CFLAGS += -DSOPC_IS_LITTLE_ENDIAN=1
endif
S2OPC_PORTDIR = port
S2OPC_PORT_CLEANFILES = $(S2OPC_PORTDIR)$(DELIM)*$(OBJEXT)
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)*.gcda
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)*.gcno
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)*.su
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)nuttx$(DELIM)*$(OBJEXT)
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)nuttx$(DELIM)*.gcda
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)nuttx$(DELIM)*.gcno
S2OPC_PORT_CLEANFILES += $(S2OPC_PORTDIR)$(DELIM)nuttx$(DELIM)*.su
clean::
$(call DELFILE, $(S2OPC_PORT_CLEANFILES))
ifeq ($(wildcard $(S2OPC_SRCDIR)/.git),)
$(S2OPC_ARCHIVE):
@echo "Downloading: $(S2OPC_ARCHIVE)"
$(Q) curl -o $(S2OPC_ARCHIVE) -L \
$(S2OPC_URL)/$(S2OPC_TAG)/S2OPC-$(S2OPC_TAG).tar.gz
$(S2OPC_SRCDIR): $(S2OPC_ARCHIVE)
$(Q) tar -xf $(S2OPC_ARCHIVE)
$(Q) mv S2OPC-$(S2OPC_TAG) $(S2OPC_SRCDIR)
context:: $(S2OPC_SRCDIR)
distclean::
$(call DELDIR, $(S2OPC_SRCDIR))
$(call DELFILE, $(S2OPC_ARCHIVES))
endif
MODULE = $(CONFIG_NETUTILS_S2OPC)
include $(APPDIR)/Application.mk

View file

@ -0,0 +1,114 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_askpass.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "sopc_askpass.h"
#include "sopc_mem_alloc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define S2OPC_PASSWORD_EXTRA 3
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_AskPass_CustomPromptFromTerminal
****************************************************************************/
bool SOPC_AskPass_CustomPromptFromTerminal(FAR const char *prompt,
FAR char **password)
{
struct termios original;
struct termios noecho;
FAR char *buffer;
FAR char *result;
size_t buffer_size;
size_t length;
int fd;
int ret;
if (prompt == NULL || password == NULL)
{
return false;
}
*password = NULL;
fd = fileno(stdin);
if (fd < 0)
{
return false;
}
buffer_size = SOPC_PASSWORD_MAX_LENGTH + S2OPC_PASSWORD_EXTRA;
buffer = SOPC_Calloc(buffer_size, sizeof(char));
if (buffer == NULL)
{
return false;
}
ret = tcgetattr(fd, &original);
if (ret == 0)
{
noecho = original;
noecho.c_lflag &= (tcflag_t)~(ECHO | ECHOE | ECHOK | ECHONL);
ret = tcsetattr(fd, TCSAFLUSH, &noecho);
}
result = NULL;
if (ret == 0)
{
fputs(prompt, stdout);
fflush(stdout);
result = fgets(buffer, buffer_size, stdin);
tcsetattr(fd, TCSAFLUSH, &original);
fputs("\n", stdout);
fflush(stdout);
}
if (result != NULL)
{
length = strlen(buffer);
if (length > 0 && buffer[length - 1] == '\n')
{
buffer[length - 1] = '\0';
*password = buffer;
return true;
}
}
explicit_bzero(buffer, buffer_size);
SOPC_Free(buffer);
return false;
}

View file

@ -0,0 +1,77 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_atomic.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "sopc_atomic.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_Atomic_Int_Get
****************************************************************************/
int32_t SOPC_Atomic_Int_Get(FAR int32_t *atomic)
{
return __atomic_load_n(atomic, __ATOMIC_SEQ_CST);
}
/****************************************************************************
* Name: SOPC_Atomic_Int_Set
****************************************************************************/
void SOPC_Atomic_Int_Set(FAR int32_t *atomic, int32_t value)
{
__atomic_store_n(atomic, value, __ATOMIC_SEQ_CST);
}
/****************************************************************************
* Name: SOPC_Atomic_Int_Add
****************************************************************************/
int32_t SOPC_Atomic_Int_Add(FAR int32_t *atomic, int32_t value)
{
return __atomic_fetch_add(atomic, value, __ATOMIC_SEQ_CST);
}
/****************************************************************************
* Name: SOPC_Atomic_Ptr_Get
****************************************************************************/
FAR void *SOPC_Atomic_Ptr_Get(FAR void **atomic)
{
return __atomic_load_n(atomic, __ATOMIC_SEQ_CST);
}
/****************************************************************************
* Name: SOPC_Atomic_Ptr_Set
****************************************************************************/
void SOPC_Atomic_Ptr_Set(FAR void **atomic, FAR void *value)
{
__atomic_store_n(atomic, value, __ATOMIC_SEQ_CST);
}

View file

@ -0,0 +1,83 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_date_time.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <limits.h>
#include <time.h>
#include "sopc_date_time.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_Time_GetCurrentTimeUTC
****************************************************************************/
SOPC_DateTime SOPC_Time_GetCurrentTimeUTC(void)
{
struct timespec current;
int64_t date_time;
int64_t units_100ns;
if (clock_gettime(CLOCK_REALTIME, &current) < 0)
{
return 0;
}
date_time = 0;
units_100ns = current.tv_nsec / 100;
if (SOPC_Time_FromUnixTime(current.tv_sec, &date_time) != SOPC_STATUS_OK ||
INT64_MAX - date_time < units_100ns)
{
return INT64_MAX;
}
return date_time + units_100ns;
}
/****************************************************************************
* Name: SOPC_Time_Breakdown_Local
****************************************************************************/
SOPC_ReturnStatus SOPC_Time_Breakdown_Local(SOPC_Unix_Time time,
FAR struct tm *result)
{
return localtime_r(&time, result) == NULL ? SOPC_STATUS_NOK :
SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Time_Breakdown_UTC
****************************************************************************/
SOPC_ReturnStatus SOPC_Time_Breakdown_UTC(SOPC_Unix_Time time,
FAR struct tm *result)
{
return gmtime_r(&time, result) == NULL ? SOPC_STATUS_NOK :
SOPC_STATUS_OK;
}

View file

@ -0,0 +1,678 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_eth_sockets.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stddef.h>
#include "sopc_eth_sockets.h"
#ifdef CONFIG_S2OPC_ETHERNET
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "p_sopc_sockets.h"
#include "sopc_mem_alloc.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct SOPC_ETH_Socket_ReceiveAddressInfo
{
struct sockaddr_ll address;
bool multicast;
bool filter_destination;
uint8_t destination[ETH_ALEN];
bool filter_source;
uint8_t source[ETH_ALEN];
};
struct SOPC_ETH_Socket_SendAddressInfo
{
struct sockaddr_ll address;
uint8_t source[ETH_ALEN];
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: s2opc_eth_hex_value
****************************************************************************/
static int s2opc_eth_hex_value(char value)
{
if (value >= '0' && value <= '9')
{
return value - '0';
}
if (value >= 'a' && value <= 'f')
{
return value - 'a' + 10;
}
if (value >= 'A' && value <= 'F')
{
return value - 'A' + 10;
}
return -1;
}
/****************************************************************************
* Name: s2opc_eth_would_block
****************************************************************************/
static bool s2opc_eth_would_block(int error)
{
#if EWOULDBLOCK == EAGAIN
return error == EAGAIN;
#else
return error == EAGAIN || error == EWOULDBLOCK;
#endif
}
/****************************************************************************
* Name: s2opc_eth_parse_address
****************************************************************************/
static bool s2opc_eth_parse_address(FAR uint8_t *address,
FAR const char *value)
{
int high;
int low;
int index;
if (address == NULL || value == NULL || strlen(value) != 17)
{
return false;
}
for (index = 0; index < ETH_ALEN; index++)
{
high = s2opc_eth_hex_value(value[index * 3]);
low = s2opc_eth_hex_value(value[index * 3 + 1]);
if (high < 0 || low < 0 ||
(index < ETH_ALEN - 1 && value[index * 3 + 2] != '-' &&
value[index * 3 + 2] != ':'))
{
return false;
}
address[index] = (uint8_t)((high << 4) | low);
}
return true;
}
/****************************************************************************
* Name: s2opc_eth_get_interface
****************************************************************************/
static bool s2opc_eth_get_interface(FAR const char *interface_name,
FAR int *interface_index,
FAR uint8_t *source)
{
struct ifreq request;
unsigned int index;
int socket_fd;
int ret;
if (interface_name == NULL || interface_index == NULL)
{
return false;
}
index = if_nametoindex(interface_name);
if (index == 0 || index > INT_MAX)
{
return false;
}
*interface_index = (int)index;
if (source == NULL)
{
return true;
}
socket_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (socket_fd < 0)
{
return false;
}
memset(&request, 0, sizeof(request));
strlcpy(request.ifr_name, interface_name, sizeof(request.ifr_name));
ret = ioctl(socket_fd, SIOCGIFHWADDR,
(unsigned long)((uintptr_t)&request));
close(socket_fd);
if (ret < 0)
{
return false;
}
memcpy(source, request.ifr_hwaddr.sa_data, ETH_ALEN);
return true;
}
/****************************************************************************
* Name: s2opc_eth_set_nonblocking
****************************************************************************/
static bool s2opc_eth_set_nonblocking(int socket_fd)
{
int flags;
flags = fcntl(socket_fd, F_GETFL, 0);
if (flags < 0)
{
return false;
}
return fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK) == 0;
}
/****************************************************************************
* Name: s2opc_eth_add_membership
****************************************************************************/
static SOPC_ReturnStatus s2opc_eth_add_membership(
int socket_fd,
FAR const SOPC_ETH_Socket_ReceiveAddressInfo *receive_address)
{
#if defined(CONFIG_NET_MCASTGROUP) && defined(CONFIG_NET_PKTPROTO_OPTIONS)
struct packet_mreq request;
int ret;
if (!receive_address->filter_destination)
{
return SOPC_STATUS_NOT_SUPPORTED;
}
memset(&request, 0, sizeof(request));
request.mr_ifindex = receive_address->address.sll_ifindex;
request.mr_type = PACKET_MR_MULTICAST;
request.mr_alen = ETH_ALEN;
memcpy(request.mr_address, receive_address->destination, ETH_ALEN);
ret = setsockopt(socket_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&request, sizeof(request));
return ret == 0 ? SOPC_STATUS_OK : SOPC_STATUS_NOK;
#else
(void)socket_fd;
(void)receive_address;
return SOPC_STATUS_NOT_SUPPORTED;
#endif
}
/****************************************************************************
* Name: s2opc_eth_create_socket
****************************************************************************/
static SOPC_ReturnStatus s2opc_eth_create_socket(
FAR const struct sockaddr_ll *address, bool nonblocking,
bool bind_socket, FAR SOPC_Socket *socket_handle)
{
FAR SOPC_Socket_Impl *socket_impl;
socket_impl = SOPC_Calloc(1, sizeof(*socket_impl));
if (socket_impl == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
socket_impl->sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
socket_impl->family = AF_PACKET;
if (socket_impl->sock < 0)
{
SOPC_Free(socket_impl);
return SOPC_STATUS_NOK;
}
if ((nonblocking && !s2opc_eth_set_nonblocking(socket_impl->sock)) ||
(bind_socket &&
bind(socket_impl->sock, (FAR const struct sockaddr *)address,
sizeof(*address)) < 0))
{
SOPC_Socket_Close(&socket_impl);
return SOPC_STATUS_NOK;
}
*socket_handle = socket_impl;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateSendAddressInfo
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateSendAddressInfo(
FAR const char *interface_name, FAR const char *destination,
FAR SOPC_ETH_Socket_SendAddressInfo **send_address)
{
FAR SOPC_ETH_Socket_SendAddressInfo *address;
if (interface_name == NULL || destination == NULL ||
send_address == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*send_address = NULL;
address = SOPC_Calloc(1, sizeof(*address));
if (address == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
address->address.sll_family = AF_PACKET;
address->address.sll_protocol = htons(ETH_P_ALL);
address->address.sll_halen = ETH_ALEN;
if (!s2opc_eth_get_interface(interface_name,
&address->address.sll_ifindex,
address->source) ||
!s2opc_eth_parse_address(address->address.sll_addr, destination))
{
SOPC_Free(address);
return SOPC_STATUS_INVALID_PARAMETERS;
}
*send_address = address;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateReceiveAddressInfo
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateReceiveAddressInfo(
FAR const char *interface_name, bool multicast,
FAR const char *destination, FAR const char *source,
FAR SOPC_ETH_Socket_ReceiveAddressInfo **receive_address)
{
FAR SOPC_ETH_Socket_ReceiveAddressInfo *address;
if (interface_name == NULL || receive_address == NULL)
{
return interface_name == NULL ? SOPC_STATUS_NOT_SUPPORTED :
SOPC_STATUS_INVALID_PARAMETERS;
}
*receive_address = NULL;
address = SOPC_Calloc(1, sizeof(*address));
if (address == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
address->address.sll_family = AF_PACKET;
address->address.sll_protocol = htons(ETH_P_ALL);
address->multicast = multicast;
address->filter_destination = destination != NULL;
address->filter_source = source != NULL;
if (!s2opc_eth_get_interface(interface_name,
&address->address.sll_ifindex, NULL) ||
(destination != NULL &&
!s2opc_eth_parse_address(address->destination, destination)) ||
(source != NULL &&
!s2opc_eth_parse_address(address->source, source)) ||
(multicast && destination != NULL &&
(address->destination[0] & 1) == 0))
{
SOPC_Free(address);
return SOPC_STATUS_INVALID_PARAMETERS;
}
*receive_address = address;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateToReceive
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateToReceive(
FAR SOPC_ETH_Socket_ReceiveAddressInfo *receive_address,
bool nonblocking, FAR SOPC_Socket *socket_handle)
{
SOPC_ReturnStatus status;
if (receive_address == NULL || socket_handle == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*socket_handle = SOPC_INVALID_SOCKET;
status = s2opc_eth_create_socket(&receive_address->address, nonblocking,
true, socket_handle);
if (status == SOPC_STATUS_OK && receive_address->multicast)
{
status = s2opc_eth_add_membership((*socket_handle)->sock,
receive_address);
if (status != SOPC_STATUS_OK)
{
SOPC_ETH_Socket_Close(socket_handle);
}
}
return status;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateToSend
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateToSend(
FAR SOPC_ETH_Socket_SendAddressInfo *send_address,
bool nonblocking, FAR SOPC_Socket *socket_handle)
{
if (send_address == NULL || socket_handle == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*socket_handle = SOPC_INVALID_SOCKET;
return s2opc_eth_create_socket(&send_address->address, nonblocking,
true, socket_handle);
}
/****************************************************************************
* Name: SOPC_ETH_Socket_SendTo
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_SendTo(
SOPC_Socket socket_handle,
FAR const SOPC_ETH_Socket_SendAddressInfo *send_address,
uint16_t ethertype, FAR SOPC_Buffer *buffer)
{
FAR SOPC_Buffer *frame;
SOPC_ReturnStatus status;
uint16_t network_ethertype;
ssize_t sent;
int error;
if (socket_handle == SOPC_INVALID_SOCKET || send_address == NULL ||
buffer == NULL || buffer->position != 0)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
frame = SOPC_Buffer_Create(ETHERNET_HEADER_SIZE + buffer->length);
if (frame == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
status = SOPC_Buffer_Write(frame, send_address->address.sll_addr,
ETH_ALEN);
if (status == SOPC_STATUS_OK)
{
status = SOPC_Buffer_Write(frame, send_address->source, ETH_ALEN);
}
if (status == SOPC_STATUS_OK)
{
network_ethertype = htons(ethertype);
status = SOPC_Buffer_Write(frame,
(FAR const uint8_t *)&network_ethertype,
sizeof(network_ethertype));
}
if (status == SOPC_STATUS_OK)
{
status = SOPC_Buffer_Write(frame, buffer->data, buffer->length);
}
if (status == SOPC_STATUS_OK)
{
do
{
sent = send(socket_handle->sock, frame->data, frame->length, 0);
}
while (sent < 0 && errno == EINTR);
error = errno;
if (sent < 0)
{
status = s2opc_eth_would_block(error) ?
SOPC_STATUS_WOULD_BLOCK : SOPC_STATUS_NOK;
}
else if ((uint32_t)sent != frame->length)
{
status = SOPC_STATUS_WOULD_BLOCK;
}
}
SOPC_Buffer_Delete(frame);
return status;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_ReceiveFrom
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_ReceiveFrom(
SOPC_Socket socket_handle,
FAR const SOPC_ETH_Socket_ReceiveAddressInfo *receive_address,
bool check_ethertype, uint16_t ethertype, FAR SOPC_Buffer *buffer)
{
uint16_t network_ethertype;
ssize_t received;
if (socket_handle == SOPC_INVALID_SOCKET || receive_address == NULL ||
buffer == NULL || buffer->current_size < ETHERNET_HEADER_SIZE)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
for (; ; )
{
do
{
received = recv(socket_handle->sock, buffer->data,
buffer->current_size, 0);
}
while (received < 0 && errno == EINTR);
if (received < 0)
{
return s2opc_eth_would_block(errno) ?
SOPC_STATUS_WOULD_BLOCK : SOPC_STATUS_NOK;
}
buffer->length = (uint32_t)received;
if (buffer->length < ETHERNET_HEADER_SIZE)
{
return SOPC_STATUS_NOK;
}
if (receive_address->filter_destination &&
memcmp(receive_address->destination, buffer->data,
ETH_ALEN) != 0)
{
continue;
}
if (receive_address->filter_source &&
memcmp(receive_address->source, buffer->data + ETH_ALEN,
ETH_ALEN) != 0)
{
continue;
}
memcpy(&network_ethertype, buffer->data + 2 * ETH_ALEN,
sizeof(network_ethertype));
if (check_ethertype && ntohs(network_ethertype) != ethertype)
{
continue;
}
return buffer->length == buffer->current_size ?
SOPC_STATUS_OUT_OF_MEMORY : SOPC_STATUS_OK;
}
}
/****************************************************************************
* Name: SOPC_ETH_Socket_Close
****************************************************************************/
void SOPC_ETH_Socket_Close(FAR SOPC_Socket *socket_handle)
{
SOPC_Socket_Close(socket_handle);
}
#else /* CONFIG_S2OPC_ETHERNET */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateSendAddressInfo
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateSendAddressInfo(
FAR const char *interface_name, FAR const char *destination,
FAR SOPC_ETH_Socket_SendAddressInfo **send_address)
{
(void)interface_name;
(void)destination;
(void)send_address;
return SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateReceiveAddressInfo
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateReceiveAddressInfo(
FAR const char *interface_name, bool multicast,
FAR const char *destination, FAR const char *source,
FAR SOPC_ETH_Socket_ReceiveAddressInfo **receive_address)
{
(void)interface_name;
(void)multicast;
(void)destination;
(void)source;
(void)receive_address;
return SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateToReceive
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateToReceive(
FAR SOPC_ETH_Socket_ReceiveAddressInfo *receive_address,
bool nonblocking, FAR SOPC_Socket *socket_handle)
{
(void)receive_address;
(void)nonblocking;
(void)socket_handle;
return SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_CreateToSend
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_CreateToSend(
FAR SOPC_ETH_Socket_SendAddressInfo *send_address,
bool nonblocking, FAR SOPC_Socket *socket_handle)
{
(void)send_address;
(void)nonblocking;
(void)socket_handle;
return SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_SendTo
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_SendTo(
SOPC_Socket socket_handle,
FAR const SOPC_ETH_Socket_SendAddressInfo *send_address,
uint16_t ethertype, FAR SOPC_Buffer *buffer)
{
(void)socket_handle;
(void)send_address;
(void)ethertype;
(void)buffer;
return SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_ReceiveFrom
****************************************************************************/
SOPC_ReturnStatus SOPC_ETH_Socket_ReceiveFrom(
SOPC_Socket socket_handle,
FAR const SOPC_ETH_Socket_ReceiveAddressInfo *receive_address,
bool check_ethertype, uint16_t ethertype, FAR SOPC_Buffer *buffer)
{
(void)socket_handle;
(void)receive_address;
(void)check_ethertype;
(void)ethertype;
(void)buffer;
return SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Name: SOPC_ETH_Socket_Close
****************************************************************************/
void SOPC_ETH_Socket_Close(FAR SOPC_Socket *socket_handle)
{
if (socket_handle != NULL)
{
*socket_handle = SOPC_INVALID_SOCKET;
}
}
#endif /* CONFIG_S2OPC_ETHERNET */

View file

@ -0,0 +1,225 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_filesystem.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "sopc_filesystem.h"
#include "sopc_helper_string.h"
#include "sopc_mem_alloc.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: s2opc_file_path
****************************************************************************/
static SOPC_ReturnStatus
s2opc_file_path(FAR const char *directory, FAR const char *name,
FAR char **path)
{
FAR char *prefix;
SOPC_ReturnStatus status;
prefix = NULL;
status = SOPC_StrConcat(directory, "/", &prefix);
if (status == SOPC_STATUS_OK)
{
status = SOPC_StrConcat(prefix, name, path);
}
SOPC_Free(prefix);
return status;
}
/****************************************************************************
* Name: s2opc_file_path_free
****************************************************************************/
static void s2opc_file_path_free(FAR void *data)
{
if (data != NULL)
{
SOPC_Free(*(FAR char **)data);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_FileSystem_mkdir
****************************************************************************/
SOPC_FileSystem_CreationResult
SOPC_FileSystem_mkdir(FAR const char *directory_path)
{
if (mkdir(directory_path,
S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0)
{
return SOPC_FileSystem_Creation_OK;
}
switch (errno)
{
case ENOENT:
return SOPC_FileSystem_Creation_Error_PathPrefixInvalid;
case EEXIST:
return SOPC_FileSystem_Creation_Error_PathAlreadyExists;
case EACCES:
return SOPC_FileSystem_Creation_Error_PathPermisionDenied;
default:
return SOPC_FileSystem_Creation_Error_PathResolutionIssue;
}
}
/****************************************************************************
* Name: SOPC_FileSystem_rmdir
****************************************************************************/
SOPC_FileSystem_RemoveResult
SOPC_FileSystem_rmdir(FAR const char *directory_path)
{
if (rmdir(directory_path) == 0)
{
return SOPC_FileSystem_Remove_OK;
}
switch (errno)
{
case ENOENT:
return SOPC_FileSystem_Remove_Error_PathInvalid;
case ENOTEMPTY:
case EEXIST:
return SOPC_FileSystem_Remove_Error_PathNotEmpty;
case EACCES:
case EPERM:
case EBUSY:
return SOPC_FileSystem_Remove_Error_PathPermisionDenied;
default:
return SOPC_FileSystem_Remove_Error_UnknownIssue;
}
}
/****************************************************************************
* Name: SOPC_FileSystem_GetDirFilePaths
****************************************************************************/
SOPC_FileSystem_GetDirResult
SOPC_FileSystem_GetDirFilePaths(FAR const char *directory_path,
FAR SOPC_Array **file_paths)
{
FAR SOPC_Array *paths;
FAR struct dirent *entry;
FAR char *path;
struct stat statbuf;
FAR DIR *directory;
SOPC_ReturnStatus status;
if (directory_path == NULL || file_paths == NULL)
{
return SOPC_FileSystem_GetDir_Error_InvalidParameters;
}
*file_paths = NULL;
directory = opendir(directory_path);
if (directory == NULL)
{
return SOPC_FileSystem_GetDir_Error_PathInvalid;
}
paths = SOPC_Array_Create(sizeof(FAR char *), 0, s2opc_file_path_free);
if (paths == NULL)
{
closedir(directory);
return SOPC_FileSystem_GetDir_Error_UnknownIssue;
}
status = SOPC_STATUS_OK;
errno = 0;
while (status == SOPC_STATUS_OK && (entry = readdir(directory)) != NULL)
{
path = NULL;
status = s2opc_file_path(directory_path, entry->d_name, &path);
if (status == SOPC_STATUS_OK && stat(path, &statbuf) < 0)
{
status = SOPC_STATUS_NOK;
}
if (status == SOPC_STATUS_OK && S_ISREG(statbuf.st_mode))
{
if (SOPC_Array_Append(paths, path))
{
path = NULL;
}
else
{
status = SOPC_STATUS_OUT_OF_MEMORY;
}
}
SOPC_Free(path);
errno = 0;
}
if (errno != 0)
{
status = SOPC_STATUS_NOK;
}
closedir(directory);
if (status != SOPC_STATUS_OK)
{
SOPC_Array_Delete(paths);
return SOPC_FileSystem_GetDir_Error_UnknownIssue;
}
*file_paths = paths;
return SOPC_FileSystem_GetDir_OK;
}
/****************************************************************************
* Name: SOPC_FileSystem_fmemopen
****************************************************************************/
FAR FILE *SOPC_FileSystem_fmemopen(FAR void *buffer, size_t size,
FAR const char *mode)
{
return fmemopen(buffer, size, mode);
}

View file

@ -0,0 +1,72 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_mem_alloc.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include "sopc_macros.h"
#include "sopc_mem_alloc.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_Malloc
****************************************************************************/
FAR void *SOPC_Malloc(size_t size)
{
return malloc(size);
}
/****************************************************************************
* Name: SOPC_Free
****************************************************************************/
void SOPC_Free(FAR void *ptr)
{
free(ptr);
}
/****************************************************************************
* Name: SOPC_Calloc
****************************************************************************/
FAR void *SOPC_Calloc(size_t count, size_t size)
{
return calloc(count, size);
}
/****************************************************************************
* Name: SOPC_Realloc
****************************************************************************/
FAR void *SOPC_Realloc(FAR void *ptr, size_t old_size, size_t new_size)
{
SOPC_UNUSED_ARG(old_size);
return realloc(ptr, new_size);
}

View file

@ -0,0 +1,87 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_random.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/random.h>
#include <errno.h>
#include <stdint.h>
#include "sopc_buffer.h"
#include "sopc_random.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_GetRandom
****************************************************************************/
SOPC_ReturnStatus SOPC_GetRandom(FAR SOPC_Buffer *buffer, uint32_t length)
{
uint8_t random_data[32];
SOPC_ReturnStatus status;
uint32_t remaining;
if (buffer == NULL || length == 0)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
remaining = length;
while (remaining > 0)
{
uint32_t chunk = remaining > sizeof(random_data) ?
sizeof(random_data) : remaining;
ssize_t nread = getrandom(random_data, chunk, 0);
if (nread < 0)
{
if (errno == EINTR)
{
continue;
}
return errno == EAGAIN ? SOPC_STATUS_WOULD_BLOCK : SOPC_STATUS_NOK;
}
if (nread == 0)
{
return SOPC_STATUS_NOK;
}
status = SOPC_Buffer_Write(buffer, random_data, nread);
if (status != SOPC_STATUS_OK)
{
return status;
}
remaining -= nread;
}
return SOPC_STATUS_OK;
}

View file

@ -0,0 +1,874 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_sockets.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netinet/tcp.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "p_sopc_sockets.h"
#include "sopc_mem_alloc.h"
#include "sopc_raw_sockets.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define S2OPC_DSEC_PER_SEC 10
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: s2opc_socket_configure
****************************************************************************/
static SOPC_ReturnStatus s2opc_socket_configure(int sock, bool nonblocking)
{
int enabled = 1;
int flags;
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &enabled,
sizeof(enabled)) < 0)
{
return SOPC_STATUS_NOK;
}
if (!nonblocking)
{
return SOPC_STATUS_OK;
}
flags = fcntl(sock, F_GETFL);
if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
{
return SOPC_STATUS_NOK;
}
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: s2opc_socket_would_block
****************************************************************************/
static bool s2opc_socket_would_block(int error)
{
#if EWOULDBLOCK == EAGAIN
return error == EAGAIN;
#else
return error == EAGAIN || error == EWOULDBLOCK;
#endif
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_Socket_Network_Enable_Keepalive
****************************************************************************/
SOPC_ReturnStatus
SOPC_Socket_Network_Enable_Keepalive(SOPC_Socket sock,
unsigned int first_probe_delay,
unsigned int interval,
unsigned int counter)
{
int enabled = 1;
int idle;
int keep_interval;
int keep_count;
if (sock == SOPC_INVALID_SOCKET ||
first_probe_delay > UINT16_MAX / S2OPC_DSEC_PER_SEC ||
interval > UINT16_MAX / S2OPC_DSEC_PER_SEC || counter > UINT8_MAX)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
/* NuttX expresses TCP_KEEPIDLE and TCP_KEEPINTVL in deciseconds. */
idle = first_probe_delay * S2OPC_DSEC_PER_SEC;
keep_interval = interval * S2OPC_DSEC_PER_SEC;
keep_count = counter;
if (setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE, &enabled,
sizeof(enabled)) < 0 ||
setsockopt(sock->sock, IPPROTO_TCP, TCP_KEEPIDLE, &idle,
sizeof(idle)) < 0 ||
setsockopt(sock->sock, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval,
sizeof(keep_interval)) < 0 ||
setsockopt(sock->sock, IPPROTO_TCP, TCP_KEEPCNT, &keep_count,
sizeof(keep_count)) < 0)
{
return SOPC_STATUS_NOK;
}
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_Network_Disable_Keepalive
****************************************************************************/
SOPC_ReturnStatus
SOPC_Socket_Network_Disable_Keepalive(SOPC_Socket sock)
{
int enabled = 0;
if (sock == SOPC_INVALID_SOCKET)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
return setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE, &enabled,
sizeof(enabled)) == 0 ? SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Socket_Network_Initialize
****************************************************************************/
bool SOPC_Socket_Network_Initialize(void)
{
return true;
}
/****************************************************************************
* Name: SOPC_Socket_Network_Clear
****************************************************************************/
bool SOPC_Socket_Network_Clear(void)
{
return true;
}
/****************************************************************************
* Name: SOPC_Socket_AddrInfo_Get
****************************************************************************/
SOPC_ReturnStatus
SOPC_Socket_AddrInfo_Get(FAR const char *hostname, FAR const char *port,
FAR SOPC_Socket_AddressInfo **addrs)
{
SOPC_Socket_AddressInfo hints;
FAR struct addrinfo *result;
int ret;
if ((hostname == NULL && port == NULL) || addrs == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*addrs = NULL;
memset(&hints, 0, sizeof(hints));
/* S2OPC opens one wildcard listener and assumes an IPv6 listener accepts
* IPv4 connections. NuttX does not implement IPV6_V6ONLY or dual-stack
* TCP listeners, so use the IPv4 wildcard when IPv4 is available. An
* explicit IPv6 address continues to resolve through AF_UNSPEC.
*/
#ifdef CONFIG_NET_IPv4
hints.addrinfo.ai_family = hostname == NULL ? AF_INET : AF_UNSPEC;
#else
hints.addrinfo.ai_family = AF_UNSPEC;
#endif
hints.addrinfo.ai_socktype = SOCK_STREAM;
hints.addrinfo.ai_flags = AI_PASSIVE;
result = NULL;
ret = getaddrinfo(hostname, port, &hints.addrinfo, &result);
if (ret != 0)
{
return SOPC_STATUS_NOK;
}
*addrs = (FAR SOPC_Socket_AddressInfo *)result;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_AddrInfo_IterNext
****************************************************************************/
FAR SOPC_Socket_AddressInfo *
SOPC_Socket_AddrInfo_IterNext(FAR SOPC_Socket_AddressInfo *addr)
{
if (addr == NULL)
{
return NULL;
}
return (FAR SOPC_Socket_AddressInfo *)addr->addrinfo.ai_next;
}
/****************************************************************************
* Name: SOPC_Socket_AddrInfo_IsIPV6
****************************************************************************/
uint8_t
SOPC_Socket_AddrInfo_IsIPV6(FAR const SOPC_Socket_AddressInfo *addr)
{
return addr != NULL && addr->addrinfo.ai_family == AF_INET6;
}
/****************************************************************************
* Name: SOPC_Socket_AddrInfoDelete
****************************************************************************/
void SOPC_Socket_AddrInfoDelete(FAR SOPC_Socket_AddressInfo **addrs)
{
if (addrs != NULL && *addrs != NULL)
{
freeaddrinfo(&(*addrs)->addrinfo);
*addrs = NULL;
}
}
/****************************************************************************
* Name: SOPC_SocketAddress_Delete
****************************************************************************/
void SOPC_SocketAddress_Delete(FAR SOPC_Socket_Address **addr)
{
if (addr != NULL && *addr != NULL)
{
SOPC_Free((*addr)->address.ai_addr);
SOPC_Free(*addr);
*addr = NULL;
}
}
/****************************************************************************
* Name: SOPC_Socket_CopyAddress
****************************************************************************/
FAR SOPC_Socket_Address *
SOPC_Socket_CopyAddress(FAR SOPC_Socket_AddressInfo *addr)
{
FAR SOPC_Socket_Address *copy;
if (addr == NULL || addr->addrinfo.ai_addr == NULL)
{
return NULL;
}
copy = SOPC_Calloc(1, sizeof(*copy));
if (copy == NULL)
{
return NULL;
}
copy->address.ai_addr = SOPC_Malloc(addr->addrinfo.ai_addrlen);
if (copy->address.ai_addr == NULL)
{
SOPC_Free(copy);
return NULL;
}
memcpy(copy->address.ai_addr, addr->addrinfo.ai_addr,
addr->addrinfo.ai_addrlen);
copy->address.ai_addrlen = addr->addrinfo.ai_addrlen;
copy->address.ai_family = addr->addrinfo.ai_family;
return copy;
}
/****************************************************************************
* Name: SOPC_Socket_GetPeerAddress
****************************************************************************/
FAR SOPC_Socket_Address *SOPC_Socket_GetPeerAddress(SOPC_Socket sock)
{
FAR SOPC_Socket_Address *address;
FAR struct sockaddr_storage *storage;
socklen_t length;
if (sock == SOPC_INVALID_SOCKET)
{
return NULL;
}
address = SOPC_Calloc(1, sizeof(*address));
storage = SOPC_Calloc(1, sizeof(*storage));
if (address == NULL || storage == NULL)
{
SOPC_Free(storage);
SOPC_Free(address);
return NULL;
}
length = sizeof(*storage);
if (getpeername(sock->sock, (FAR struct sockaddr *)storage, &length) < 0)
{
SOPC_Free(storage);
SOPC_Free(address);
return NULL;
}
address->address.ai_family = storage->ss_family;
address->address.ai_addrlen = length;
address->address.ai_addr = (FAR struct sockaddr *)storage;
return address;
}
/****************************************************************************
* Name: SOPC_SocketAddress_GetNameInfo
****************************************************************************/
SOPC_ReturnStatus
SOPC_SocketAddress_GetNameInfo(FAR const SOPC_Socket_Address *addr,
FAR char **host, FAR char **service)
{
FAR char *host_result = NULL;
FAR char *service_result = NULL;
socklen_t host_length = 0;
socklen_t service_length = 0;
int flags = 0;
int ret;
if (addr == NULL || (host == NULL && service == NULL))
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
if (host != NULL)
{
*host = NULL;
host_result = SOPC_Calloc(NI_MAXHOST, sizeof(char));
if (host_result == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
host_length = NI_MAXHOST;
flags |= NI_NUMERICHOST;
}
if (service != NULL)
{
*service = NULL;
service_result = SOPC_Calloc(NI_MAXSERV, sizeof(char));
if (service_result == NULL)
{
SOPC_Free(host_result);
return SOPC_STATUS_OUT_OF_MEMORY;
}
service_length = NI_MAXSERV;
flags |= NI_NUMERICSERV;
}
ret = getnameinfo(addr->address.ai_addr, addr->address.ai_addrlen,
host_result, host_length, service_result,
service_length, flags);
if (ret != 0)
{
SOPC_Free(host_result);
SOPC_Free(service_result);
return SOPC_STATUS_NOK;
}
if (host != NULL)
{
*host = host_result;
}
if (service != NULL)
{
*service = service_result;
}
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_Clear
****************************************************************************/
void SOPC_Socket_Clear(FAR SOPC_Socket *sock)
{
if (sock != NULL)
{
*sock = SOPC_INVALID_SOCKET;
}
}
/****************************************************************************
* Name: SOPC_Socket_CreateNew
****************************************************************************/
SOPC_ReturnStatus
SOPC_Socket_CreateNew(FAR SOPC_Socket_AddressInfo *addr, bool reuse,
bool nonblocking, FAR SOPC_Socket *sock)
{
FAR SOPC_Socket_Impl *implementation;
int enabled = 1;
if (addr == NULL || sock == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*sock = SOPC_INVALID_SOCKET;
implementation = SOPC_Calloc(1, sizeof(*implementation));
if (implementation == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
implementation->sock = socket(addr->addrinfo.ai_family,
addr->addrinfo.ai_socktype,
addr->addrinfo.ai_protocol);
implementation->family = addr->addrinfo.ai_family;
if (implementation->sock < 0 ||
s2opc_socket_configure(implementation->sock, nonblocking) !=
SOPC_STATUS_OK ||
(reuse && setsockopt(implementation->sock, SOL_SOCKET, SO_REUSEADDR,
&enabled, sizeof(enabled)) < 0))
{
if (implementation->sock >= 0)
{
close(implementation->sock);
}
SOPC_Free(implementation);
return SOPC_STATUS_NOK;
}
*sock = implementation;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_Listen
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_Listen(SOPC_Socket sock,
FAR SOPC_Socket_AddressInfo *addr)
{
if (sock == SOPC_INVALID_SOCKET || addr == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
if (bind(sock->sock, addr->addrinfo.ai_addr,
addr->addrinfo.ai_addrlen) < 0 ||
listen(sock->sock, SOMAXCONN) < 0)
{
return SOPC_STATUS_NOK;
}
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_Accept
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_Accept(SOPC_Socket listening_sock,
bool nonblocking,
FAR SOPC_Socket *accepted_sock)
{
FAR SOPC_Socket_Impl *implementation;
struct sockaddr_storage remote;
socklen_t length;
int ret;
if (listening_sock == SOPC_INVALID_SOCKET || accepted_sock == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*accepted_sock = SOPC_INVALID_SOCKET;
implementation = SOPC_Calloc(1, sizeof(*implementation));
if (implementation == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
length = sizeof(remote);
do
{
ret = accept(listening_sock->sock, (FAR struct sockaddr *)&remote,
&length);
}
while (ret < 0 && errno == EINTR);
implementation->sock = ret;
if (ret < 0 || s2opc_socket_configure(ret, nonblocking) != SOPC_STATUS_OK)
{
if (ret >= 0)
{
close(ret);
}
SOPC_Free(implementation);
return SOPC_STATUS_NOK;
}
implementation->family = remote.ss_family;
*accepted_sock = implementation;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_Connect
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_Connect(SOPC_Socket sock,
FAR SOPC_Socket_AddressInfo *addr)
{
int ret;
int error;
if (sock == SOPC_INVALID_SOCKET || addr == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
do
{
ret = connect(sock->sock, addr->addrinfo.ai_addr,
addr->addrinfo.ai_addrlen);
}
while (ret < 0 && errno == EINTR);
error = errno;
if (ret == 0 || error == EISCONN || error == EINPROGRESS ||
error == EALREADY)
{
return SOPC_STATUS_OK;
}
return SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Socket_ConnectToLocal
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_ConnectToLocal(SOPC_Socket from,
SOPC_Socket to)
{
SOPC_Socket_AddressInfo addr;
struct sockaddr_storage storage;
if (from == SOPC_INVALID_SOCKET || to == SOPC_INVALID_SOCKET)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
memset(&addr, 0, sizeof(addr));
memset(&storage, 0, sizeof(storage));
addr.addrinfo.ai_addr = (FAR struct sockaddr *)&storage;
addr.addrinfo.ai_addrlen = sizeof(storage);
if (getsockname(to->sock, addr.addrinfo.ai_addr,
&addr.addrinfo.ai_addrlen) < 0)
{
return SOPC_STATUS_NOK;
}
return SOPC_Socket_Connect(from, &addr);
}
/****************************************************************************
* Name: SOPC_Socket_CheckAckConnect
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_CheckAckConnect(SOPC_Socket sock)
{
socklen_t length;
int error = 0;
if (sock == SOPC_INVALID_SOCKET)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
length = sizeof(error);
if (getsockopt(sock->sock, SOL_SOCKET, SO_ERROR, &error, &length) < 0 ||
error != 0)
{
return SOPC_STATUS_NOK;
}
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_SocketSet_Create
****************************************************************************/
FAR SOPC_SocketSet *SOPC_SocketSet_Create(void)
{
FAR SOPC_SocketSet *set;
set = SOPC_Calloc(1, sizeof(*set));
if (set != NULL)
{
SOPC_SocketSet_Clear(set);
}
return set;
}
/****************************************************************************
* Name: SOPC_SocketSet_Delete
****************************************************************************/
void SOPC_SocketSet_Delete(FAR SOPC_SocketSet **set)
{
if (set != NULL)
{
SOPC_Free(*set);
*set = NULL;
}
}
/****************************************************************************
* Name: SOPC_SocketSet_Add
****************************************************************************/
void SOPC_SocketSet_Add(SOPC_Socket sock, FAR SOPC_SocketSet *set)
{
if (sock != SOPC_INVALID_SOCKET && set != NULL)
{
FD_SET(sock->sock, &set->set);
if (sock->sock > set->fdmax)
{
set->fdmax = sock->sock;
}
}
}
/****************************************************************************
* Name: SOPC_SocketSet_IsPresent
****************************************************************************/
bool SOPC_SocketSet_IsPresent(SOPC_Socket sock, FAR SOPC_SocketSet *set)
{
return sock != SOPC_INVALID_SOCKET && set != NULL &&
FD_ISSET(sock->sock, &set->set);
}
/****************************************************************************
* Name: SOPC_SocketSet_Clear
****************************************************************************/
void SOPC_SocketSet_Clear(FAR SOPC_SocketSet *set)
{
if (set != NULL)
{
FD_ZERO(&set->set);
set->fdmax = 0;
}
}
/****************************************************************************
* Name: SOPC_Socket_WaitSocketEvents
****************************************************************************/
int32_t SOPC_Socket_WaitSocketEvents(FAR SOPC_SocketSet *read_set,
FAR SOPC_SocketSet *write_set,
FAR SOPC_SocketSet *except_set,
uint32_t wait_ms)
{
FAR struct timeval *timeout_ptr;
struct timeval timeout;
int fdmax;
int ret;
if (read_set == NULL || write_set == NULL || except_set == NULL)
{
return -1;
}
fdmax = read_set->fdmax;
if (write_set->fdmax > fdmax)
{
fdmax = write_set->fdmax;
}
if (except_set->fdmax > fdmax)
{
fdmax = except_set->fdmax;
}
if (wait_ms == 0)
{
timeout_ptr = NULL;
}
else
{
timeout.tv_sec = wait_ms / 1000;
timeout.tv_usec = (wait_ms % 1000) * 1000;
timeout_ptr = &timeout;
}
do
{
ret = select(fdmax + 1, &read_set->set, &write_set->set,
&except_set->set, timeout_ptr);
}
while (ret < 0 && errno == EINTR);
return ret;
}
/****************************************************************************
* Name: SOPC_Socket_Write
****************************************************************************/
SOPC_ReturnStatus
SOPC_Socket_Write(SOPC_Socket sock, FAR const uint8_t *data,
uint32_t count, FAR uint32_t *sent_bytes)
{
ssize_t ret;
int error;
if (sock == SOPC_INVALID_SOCKET || data == NULL || sent_bytes == NULL ||
count > INT32_MAX)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
do
{
ret = send(sock->sock, data, count, MSG_NOSIGNAL);
}
while (ret < 0 && errno == EINTR);
error = errno;
if (ret >= 0)
{
*sent_bytes = ret;
return SOPC_STATUS_OK;
}
*sent_bytes = 0;
return s2opc_socket_would_block(error) ? SOPC_STATUS_WOULD_BLOCK :
SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Socket_Read
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_Read(SOPC_Socket sock, FAR uint8_t *data,
uint32_t size, FAR uint32_t *read_count)
{
ssize_t ret;
int error;
if (sock == SOPC_INVALID_SOCKET || data == NULL || size == 0 ||
read_count == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
do
{
ret = recv(sock->sock, data, size, 0);
}
while (ret < 0 && errno == EINTR);
error = errno;
if (ret > 0)
{
*read_count = ret;
return SOPC_STATUS_OK;
}
*read_count = 0;
if (ret == 0)
{
return SOPC_STATUS_CLOSED;
}
return s2opc_socket_would_block(error) ? SOPC_STATUS_WOULD_BLOCK :
SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Socket_BytesToRead
****************************************************************************/
SOPC_ReturnStatus SOPC_Socket_BytesToRead(SOPC_Socket sock,
FAR uint32_t *bytes_to_read)
{
int available;
int ret;
if (sock == SOPC_INVALID_SOCKET || bytes_to_read == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
do
{
ret = ioctl(sock->sock, FIONREAD, &available);
}
while (ret < 0 && errno == EINTR);
if (ret < 0 || available < 0)
{
return SOPC_STATUS_NOK;
}
*bytes_to_read = available;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Socket_Close
****************************************************************************/
void SOPC_Socket_Close(FAR SOPC_Socket *sock)
{
int ret;
if (sock == NULL || *sock == SOPC_INVALID_SOCKET)
{
return;
}
do
{
ret = close((*sock)->sock);
}
while (ret < 0 && errno == EINTR);
SOPC_Free(*sock);
*sock = SOPC_INVALID_SOCKET;
}

View file

@ -0,0 +1,64 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_sockets.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
#ifndef __APPS_NETUTILS_S2OPC_PORT_NUTTX_P_SOPC_SOCKETS_H
#define __APPS_NETUTILS_S2OPC_PORT_NUTTX_P_SOPC_SOCKETS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <netdb.h>
#include <sys/select.h>
/****************************************************************************
* Public Types
****************************************************************************/
struct SOPC_Socket_Impl
{
int sock;
sa_family_t family;
};
/* Keep addrinfo as the first member. S2OPC walks the resolver-owned list by
* casting its addrinfo elements to SOPC_Socket_AddressInfo.
*/
struct SOPC_Socket_AddressInfo
{
struct addrinfo addrinfo;
};
struct SOPC_Socket_Address
{
struct addrinfo address;
};
struct SOPC_SocketSet
{
int fdmax;
fd_set set;
};
#endif /* __APPS_NETUTILS_S2OPC_PORT_NUTTX_P_SOPC_SOCKETS_H */

View file

@ -0,0 +1,473 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_threads.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <sched.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "p_sopc_threads.h"
#include "sopc_mem_alloc.h"
#include "sopc_mutexes.h"
#include "sopc_threads.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define S2OPC_NSEC_PER_SEC 1000000000l
#define S2OPC_NSEC_PER_MSEC 1000000l
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: s2opc_thread_start
****************************************************************************/
static SOPC_ReturnStatus
s2opc_thread_start(FAR pthread_t *thread,
FAR void *(*entry)(FAR void *), FAR void *arg,
FAR const char *name, int priority, int affinity)
{
struct sched_param param;
pthread_attr_t attr;
#ifdef CONFIG_SMP
cpu_set_t cpuset;
#endif
char taskname[CONFIG_TASK_NAME_SIZE + 1];
int ret;
ret = pthread_attr_init(&attr);
if (ret != 0)
{
return SOPC_STATUS_NOK;
}
ret = pthread_attr_setstacksize(&attr, CONFIG_S2OPC_THREAD_STACKSIZE);
if (ret == 0)
{
param.sched_priority = priority > 0 ? priority :
SCHED_PRIORITY_DEFAULT;
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (ret == 0)
{
ret = pthread_attr_setschedpolicy(&attr, priority > 0 ?
SCHED_FIFO : SCHED_RR);
}
if (ret == 0)
{
ret = pthread_attr_setschedparam(&attr, &param);
}
}
#ifdef CONFIG_SMP
if (ret == 0 && affinity >= 0)
{
CPU_ZERO(&cpuset);
CPU_SET((size_t)affinity, &cpuset);
ret = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset);
}
#endif
if (ret == 0)
{
ret = pthread_create(thread, &attr, entry, arg);
}
pthread_attr_destroy(&attr);
if (ret != 0)
{
return SOPC_STATUS_NOK;
}
if (name != NULL)
{
strlcpy(taskname, name, sizeof(taskname));
pthread_setname_np(*thread, taskname);
}
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: s2opc_thread_create
****************************************************************************/
static SOPC_ReturnStatus
s2opc_thread_create(FAR SOPC_Thread *thread,
FAR void *(*entry)(FAR void *), FAR void *arg,
FAR const char *name, int priority, int affinity)
{
FAR SOPC_Thread_Impl *implementation;
SOPC_ReturnStatus status;
if (thread == NULL || entry == NULL || priority < 0 ||
priority > SCHED_PRIORITY_MAX || affinity >= CONFIG_SMP_NCPUS)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*thread = SOPC_INVALID_THREAD;
implementation = SOPC_Calloc(1, sizeof(*implementation));
if (implementation == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
status = s2opc_thread_start(&implementation->thread, entry, arg, name,
priority, affinity);
if (status == SOPC_STATUS_OK)
{
*thread = implementation;
}
else
{
SOPC_Free(implementation);
}
return status;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_Condition_Init
****************************************************************************/
SOPC_ReturnStatus SOPC_Condition_Init(FAR SOPC_Condition *cond)
{
FAR SOPC_Condition_Impl *implementation;
if (cond == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*cond = SOPC_INVALID_COND;
implementation = SOPC_Calloc(1, sizeof(*implementation));
if (implementation == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
if (pthread_cond_init(&implementation->cond, NULL) != 0)
{
SOPC_Free(implementation);
return SOPC_STATUS_NOK;
}
*cond = implementation;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Condition_Clear
****************************************************************************/
SOPC_ReturnStatus SOPC_Condition_Clear(FAR SOPC_Condition *cond)
{
FAR SOPC_Condition_Impl *implementation;
if (cond == NULL || *cond == SOPC_INVALID_COND)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
implementation = *cond;
if (pthread_cond_destroy(&implementation->cond) != 0)
{
return SOPC_STATUS_NOK;
}
SOPC_Free(implementation);
*cond = SOPC_INVALID_COND;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Condition_SignalAll
****************************************************************************/
SOPC_ReturnStatus SOPC_Condition_SignalAll(FAR SOPC_Condition *cond)
{
FAR SOPC_Condition_Impl *implementation;
if (cond == NULL || *cond == SOPC_INVALID_COND)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
implementation = *cond;
return pthread_cond_broadcast(&implementation->cond) == 0 ?
SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Mutex_Initialization
****************************************************************************/
SOPC_ReturnStatus SOPC_Mutex_Initialization(FAR SOPC_Mutex *mutex)
{
FAR SOPC_Mutex_Impl *implementation;
pthread_mutexattr_t attr;
int ret;
if (mutex == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*mutex = SOPC_INVALID_MUTEX;
ret = pthread_mutexattr_init(&attr);
if (ret != 0)
{
return SOPC_STATUS_NOK;
}
ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (ret == 0)
{
implementation = SOPC_Calloc(1, sizeof(*implementation));
if (implementation == NULL)
{
ret = ENOMEM;
}
else if (pthread_mutex_init(&implementation->mutex, &attr) != 0)
{
SOPC_Free(implementation);
ret = EINVAL;
}
else
{
*mutex = implementation;
}
}
pthread_mutexattr_destroy(&attr);
if (ret == ENOMEM)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
return ret == 0 ? SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Mutex_Clear
****************************************************************************/
SOPC_ReturnStatus SOPC_Mutex_Clear(FAR SOPC_Mutex *mutex)
{
FAR SOPC_Mutex_Impl *implementation;
if (mutex == NULL || *mutex == SOPC_INVALID_MUTEX)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
implementation = *mutex;
if (pthread_mutex_destroy(&implementation->mutex) != 0)
{
return SOPC_STATUS_NOK;
}
SOPC_Free(implementation);
*mutex = SOPC_INVALID_MUTEX;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Mutex_Lock
****************************************************************************/
SOPC_ReturnStatus SOPC_Mutex_Lock(FAR SOPC_Mutex *mutex)
{
FAR SOPC_Mutex_Impl *implementation;
if (mutex == NULL || *mutex == SOPC_INVALID_MUTEX)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
implementation = *mutex;
return pthread_mutex_lock(&implementation->mutex) == 0 ?
SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Mutex_Unlock
****************************************************************************/
SOPC_ReturnStatus SOPC_Mutex_Unlock(FAR SOPC_Mutex *mutex)
{
FAR SOPC_Mutex_Impl *implementation;
if (mutex == NULL || *mutex == SOPC_INVALID_MUTEX)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
implementation = *mutex;
return pthread_mutex_unlock(&implementation->mutex) == 0 ?
SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Mutex_UnlockAndWaitCond
****************************************************************************/
SOPC_ReturnStatus
SOPC_Mutex_UnlockAndWaitCond(FAR SOPC_Condition *cond,
FAR SOPC_Mutex *mutex)
{
FAR SOPC_Condition_Impl *condition;
FAR SOPC_Mutex_Impl *implementation;
if (cond == NULL || *cond == SOPC_INVALID_COND || mutex == NULL ||
*mutex == SOPC_INVALID_MUTEX)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
condition = *cond;
implementation = *mutex;
return pthread_cond_wait(&condition->cond, &implementation->mutex) == 0 ?
SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Mutex_UnlockAndTimedWaitCond
****************************************************************************/
SOPC_ReturnStatus
SOPC_Mutex_UnlockAndTimedWaitCond(FAR SOPC_Condition *cond,
FAR SOPC_Mutex *mutex,
uint32_t milliseconds)
{
FAR SOPC_Condition_Impl *condition;
FAR SOPC_Mutex_Impl *implementation;
struct timespec abstime;
uint64_t nanoseconds;
int ret;
if (cond == NULL || *cond == SOPC_INVALID_COND || mutex == NULL ||
*mutex == SOPC_INVALID_MUTEX || milliseconds == 0)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
if (clock_gettime(CLOCK_REALTIME, &abstime) < 0)
{
return SOPC_STATUS_NOK;
}
abstime.tv_sec += milliseconds / 1000;
nanoseconds = abstime.tv_nsec +
(uint64_t)(milliseconds % 1000) * S2OPC_NSEC_PER_MSEC;
abstime.tv_sec += nanoseconds / S2OPC_NSEC_PER_SEC;
abstime.tv_nsec = nanoseconds % S2OPC_NSEC_PER_SEC;
condition = *cond;
implementation = *mutex;
ret = pthread_cond_timedwait(&condition->cond, &implementation->mutex,
&abstime);
if (ret == ETIMEDOUT)
{
return SOPC_STATUS_TIMEOUT;
}
return ret == 0 ? SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_Thread_Create
****************************************************************************/
SOPC_ReturnStatus SOPC_Thread_Create(FAR SOPC_Thread *thread,
FAR void *(*entry)(FAR void *),
FAR void *arg, FAR const char *name)
{
return s2opc_thread_create(thread, entry, arg, name, 0, -1);
}
/****************************************************************************
* Name: SOPC_Thread_CreatePrioritized
****************************************************************************/
SOPC_ReturnStatus
SOPC_Thread_CreatePrioritized(FAR SOPC_Thread *thread,
FAR void *(*entry)(FAR void *), FAR void *arg,
int priority, int affinity,
FAR const char *name)
{
return s2opc_thread_create(thread, entry, arg, name, priority, affinity);
}
/****************************************************************************
* Name: SOPC_Thread_Join
****************************************************************************/
SOPC_ReturnStatus SOPC_Thread_Join(FAR SOPC_Thread *thread)
{
FAR SOPC_Thread_Impl *implementation;
if (thread == NULL || *thread == SOPC_INVALID_THREAD)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
implementation = *thread;
if (pthread_join(implementation->thread, NULL) != 0)
{
return SOPC_STATUS_NOK;
}
SOPC_Free(implementation);
*thread = SOPC_INVALID_THREAD;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_Sleep
****************************************************************************/
void SOPC_Sleep(unsigned int milliseconds)
{
struct timespec delay;
delay.tv_sec = milliseconds / 1000;
delay.tv_nsec = (milliseconds % 1000) * S2OPC_NSEC_PER_MSEC;
while (nanosleep(&delay, &delay) < 0 && errno == EINTR)
{
}
}

View file

@ -0,0 +1,52 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_threads.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
#ifndef __APPS_NETUTILS_S2OPC_PORT_NUTTX_P_SOPC_THREADS_H
#define __APPS_NETUTILS_S2OPC_PORT_NUTTX_P_SOPC_THREADS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <pthread.h>
/****************************************************************************
* Public Types
****************************************************************************/
struct SOPC_Mutex_Impl
{
pthread_mutex_t mutex;
};
struct SOPC_Condition_Impl
{
pthread_cond_t cond;
};
struct SOPC_Thread_Impl
{
pthread_t thread;
};
#endif /* __APPS_NETUTILS_S2OPC_PORT_NUTTX_P_SOPC_THREADS_H */

View file

@ -0,0 +1,309 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_time_reference.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include "sopc_assert.h"
#include "sopc_date_time.h"
#include "sopc_logger.h"
#include "sopc_mem_alloc.h"
#include "sopc_time_reference.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define S2OPC_NSEC_PER_SEC 1000000000l
#define S2OPC_NSEC_PER_MSEC 1000000l
#define S2OPC_NSEC_PER_USEC 1000l
#define S2OPC_USEC_PER_SEC 1000000l
/****************************************************************************
* Private Types
****************************************************************************/
struct SOPC_HighRes_TimeReference
{
struct timespec time;
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: s2opc_highres_add
****************************************************************************/
static void
s2opc_highres_add(FAR SOPC_HighRes_TimeReference *reference,
uint64_t duration_us)
{
reference->time.tv_sec += duration_us / S2OPC_USEC_PER_SEC;
reference->time.tv_nsec +=
(duration_us % S2OPC_USEC_PER_SEC) * S2OPC_NSEC_PER_USEC;
if (reference->time.tv_nsec >= S2OPC_NSEC_PER_SEC)
{
reference->time.tv_sec++;
reference->time.tv_nsec -= S2OPC_NSEC_PER_SEC;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_TimeReference_GetCurrent
****************************************************************************/
SOPC_TimeReference SOPC_TimeReference_GetCurrent(void)
{
struct timespec current;
uint64_t milliseconds;
if (clock_gettime(CLOCK_MONOTONIC, &current) < 0 || current.tv_sec < 0 ||
current.tv_nsec < 0 || current.tv_nsec >= S2OPC_NSEC_PER_SEC)
{
return UINT64_MAX;
}
if ((uint64_t)current.tv_sec >
(UINT64_MAX - current.tv_nsec / S2OPC_NSEC_PER_MSEC) / 1000)
{
return UINT64_MAX;
}
milliseconds = (uint64_t)current.tv_sec * 1000;
return milliseconds + current.tv_nsec / S2OPC_NSEC_PER_MSEC;
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_Create
****************************************************************************/
FAR SOPC_HighRes_TimeReference *SOPC_HighRes_TimeReference_Create(void)
{
FAR SOPC_HighRes_TimeReference *reference;
reference = SOPC_Calloc(1, sizeof(*reference));
if (reference != NULL)
{
SOPC_HighRes_TimeReference_GetTime(reference);
}
return reference;
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_Delete
****************************************************************************/
void SOPC_HighRes_TimeReference_Delete(
FAR SOPC_HighRes_TimeReference **reference)
{
if (reference != NULL)
{
SOPC_Free(*reference);
*reference = NULL;
}
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_Copy
****************************************************************************/
void SOPC_HighRes_TimeReference_Copy(
FAR SOPC_HighRes_TimeReference *destination,
FAR const SOPC_HighRes_TimeReference *source)
{
if (destination != NULL && source != NULL)
{
*destination = *source;
}
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_GetTime
****************************************************************************/
void SOPC_HighRes_TimeReference_GetTime(
FAR SOPC_HighRes_TimeReference *reference)
{
int ret;
if (reference != NULL)
{
ret = clock_gettime(CLOCK_MONOTONIC, &reference->time);
SOPC_ASSERT(ret == 0);
}
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_AddSynchedDuration
****************************************************************************/
void SOPC_HighRes_TimeReference_AddSynchedDuration(
FAR SOPC_HighRes_TimeReference *reference, uint64_t duration_us,
int32_t offset_us)
{
uint64_t window_offset;
uint64_t current_remainder;
uint64_t increment;
SOPC_ASSERT(reference != NULL);
increment = duration_us;
if (offset_us >= 0)
{
SOPC_ASSERT(duration_us > 0);
current_remainder = SOPC_Time_GetCurrentTimeUTC() / 10;
current_remainder %= duration_us;
window_offset = (duration_us + current_remainder -
(uint32_t)offset_us) % duration_us;
increment -= window_offset;
/* A wakeup in the last fifth of a period belongs to the next period.
* This absorbs small differences between the realtime and monotonic
* clocks.
*/
if (increment < duration_us / 5)
{
increment += duration_us;
}
}
s2opc_highres_add(reference, increment);
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_IsExpired
****************************************************************************/
bool SOPC_HighRes_TimeReference_IsExpired(
FAR const SOPC_HighRes_TimeReference *reference,
FAR const SOPC_HighRes_TimeReference *now)
{
SOPC_HighRes_TimeReference current;
SOPC_ASSERT(reference != NULL);
if (now == NULL)
{
SOPC_HighRes_TimeReference_GetTime(&current);
now = &current;
}
return reference->time.tv_sec < now->time.tv_sec ||
(reference->time.tv_sec == now->time.tv_sec &&
reference->time.tv_nsec <= now->time.tv_nsec);
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_DeltaUs
****************************************************************************/
int64_t SOPC_HighRes_TimeReference_DeltaUs(
FAR const SOPC_HighRes_TimeReference *reference,
FAR const SOPC_HighRes_TimeReference *time)
{
SOPC_HighRes_TimeReference current;
int64_t delta_seconds;
int64_t delta_nanoseconds;
SOPC_ASSERT(reference != NULL);
if (time == NULL)
{
SOPC_HighRes_TimeReference_GetTime(&current);
time = &current;
}
delta_seconds = time->time.tv_sec - reference->time.tv_sec;
delta_nanoseconds = time->time.tv_nsec - reference->time.tv_nsec;
return delta_seconds * S2OPC_USEC_PER_SEC +
delta_nanoseconds / S2OPC_NSEC_PER_USEC;
}
/****************************************************************************
* Name: SOPC_HighRes_TimeReference_SleepUntil
****************************************************************************/
void SOPC_HighRes_TimeReference_SleepUntil(
FAR const SOPC_HighRes_TimeReference *date)
{
struct timespec current;
struct timespec delay;
static bool warned;
int ret;
SOPC_ASSERT(date != NULL);
for (; ; )
{
ret = clock_gettime(CLOCK_MONOTONIC, &current);
if (ret < 0)
{
break;
}
if (date->time.tv_sec < current.tv_sec ||
(date->time.tv_sec == current.tv_sec &&
date->time.tv_nsec <= current.tv_nsec))
{
return;
}
delay.tv_sec = date->time.tv_sec - current.tv_sec;
delay.tv_nsec = date->time.tv_nsec - current.tv_nsec;
if (delay.tv_nsec < 0)
{
delay.tv_sec--;
delay.tv_nsec += S2OPC_NSEC_PER_SEC;
}
ret = nanosleep(&delay, NULL);
if (ret == 0)
{
return;
}
if (errno != EINTR)
{
break;
}
}
if (!warned)
{
warned = true;
SOPC_Logger_TraceError(SOPC_LOG_MODULE_COMMON,
"high-resolution sleep failed: %d (%s)",
errno, strerror(errno));
}
}

View file

@ -0,0 +1,498 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/p_sopc_udp_sockets.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to Systerel under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Systerel licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#ifdef CONFIG_NETDEV_IFINDEX
# include <ifaddrs.h>
# include <net/if.h>
#endif
#include "p_sopc_sockets.h"
#include "sopc_buffer.h"
#include "sopc_mem_alloc.h"
#include "sopc_udp_sockets.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: s2opc_udp_would_block
****************************************************************************/
static bool s2opc_udp_would_block(int error)
{
return error == EAGAIN;
}
/****************************************************************************
* Name: s2opc_udp_resolve
****************************************************************************/
static SOPC_ReturnStatus
s2opc_udp_resolve(bool ipv6, FAR const char *node, FAR const char *port,
FAR SOPC_Socket_AddressInfo **addrs)
{
SOPC_Socket_AddressInfo hints;
FAR struct addrinfo *result;
if ((node == NULL && port == NULL) || addrs == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*addrs = NULL;
memset(&hints, 0, sizeof(hints));
hints.addrinfo.ai_family = ipv6 ? AF_INET6 : AF_INET;
hints.addrinfo.ai_socktype = SOCK_DGRAM;
hints.addrinfo.ai_protocol = IPPROTO_UDP;
hints.addrinfo.ai_flags = AI_PASSIVE;
result = NULL;
if (getaddrinfo(node, port, &hints.addrinfo, &result) != 0)
{
return SOPC_STATUS_NOK;
}
*addrs = (FAR SOPC_Socket_AddressInfo *)result;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: s2opc_udp_bind_device
****************************************************************************/
static SOPC_ReturnStatus
s2opc_udp_bind_device(int sock, FAR const char *interface_name)
{
if (interface_name == NULL)
{
return SOPC_STATUS_OK;
}
#ifdef CONFIG_NET_BINDTODEVICE
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface_name,
strlen(interface_name) + 1) < 0)
{
return SOPC_STATUS_NOK;
}
return SOPC_STATUS_OK;
#else
return SOPC_STATUS_NOT_SUPPORTED;
#endif
}
/****************************************************************************
* Name: s2opc_udp_create
****************************************************************************/
static SOPC_ReturnStatus
s2opc_udp_create(FAR const SOPC_Socket_AddressInfo *addr,
FAR const char *interface_name, bool reuse,
bool nonblocking, FAR SOPC_Socket *sock)
{
FAR SOPC_Socket_Impl *implementation;
int enabled = 1;
int flags;
if (addr == NULL || sock == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
*sock = SOPC_INVALID_SOCKET;
implementation = SOPC_Calloc(1, sizeof(*implementation));
if (implementation == NULL)
{
return SOPC_STATUS_OUT_OF_MEMORY;
}
implementation->sock = socket(addr->addrinfo.ai_family,
addr->addrinfo.ai_socktype,
addr->addrinfo.ai_protocol);
implementation->family = addr->addrinfo.ai_family;
if (implementation->sock < 0)
{
SOPC_Free(implementation);
return SOPC_STATUS_NOK;
}
if ((reuse &&
setsockopt(implementation->sock, SOL_SOCKET, SO_REUSEADDR, &enabled,
sizeof(enabled)) < 0) ||
s2opc_udp_bind_device(implementation->sock, interface_name) !=
SOPC_STATUS_OK)
{
SOPC_Socket_Close(&implementation);
return SOPC_STATUS_NOK;
}
if (nonblocking)
{
flags = fcntl(implementation->sock, F_GETFL);
if (flags < 0 || fcntl(implementation->sock, F_SETFL,
flags | O_NONBLOCK) < 0)
{
SOPC_Socket_Close(&implementation);
return SOPC_STATUS_NOK;
}
}
*sock = implementation;
return SOPC_STATUS_OK;
}
/****************************************************************************
* Name: s2opc_udp_is_multicast
****************************************************************************/
static bool
s2opc_udp_is_multicast(FAR const SOPC_Socket_AddressInfo *address)
{
FAR const struct sockaddr_in *addr4;
FAR const struct sockaddr_in6 *addr6;
if (address->addrinfo.ai_family == AF_INET)
{
addr4 = (FAR const struct sockaddr_in *)address->addrinfo.ai_addr;
return IN_MULTICAST(ntohl(addr4->sin_addr.s_addr));
}
if (address->addrinfo.ai_family == AF_INET6)
{
addr6 = (FAR const struct sockaddr_in6 *)address->addrinfo.ai_addr;
return IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr);
}
return false;
}
/****************************************************************************
* Name: s2opc_udp_ipv4_interface
****************************************************************************/
static SOPC_ReturnStatus
s2opc_udp_ipv4_interface(FAR const char *interface_name,
FAR struct in_addr *address)
{
#ifdef CONFIG_NETDEV_IFINDEX
FAR struct ifaddrs *interfaces;
FAR struct ifaddrs *current;
FAR struct sockaddr_in *addr4;
#endif
address->s_addr = htonl(INADDR_ANY);
if (interface_name == NULL)
{
return SOPC_STATUS_OK;
}
#ifdef CONFIG_NETDEV_IFINDEX
interfaces = NULL;
if (getifaddrs(&interfaces) < 0)
{
return SOPC_STATUS_NOT_SUPPORTED;
}
for (current = interfaces; current != NULL; current = current->ifa_next)
{
if (current->ifa_addr != NULL &&
current->ifa_addr->sa_family == AF_INET &&
strcmp(current->ifa_name, interface_name) == 0)
{
addr4 = (FAR struct sockaddr_in *)current->ifa_addr;
*address = addr4->sin_addr;
freeifaddrs(interfaces);
return SOPC_STATUS_OK;
}
}
freeifaddrs(interfaces);
return SOPC_STATUS_NOK;
#else
return SOPC_STATUS_NOT_SUPPORTED;
#endif
}
/****************************************************************************
* Name: s2opc_udp_join_multicast
****************************************************************************/
static SOPC_ReturnStatus
s2opc_udp_join_multicast(int sock, FAR const char *interface_name,
FAR const SOPC_Socket_AddressInfo *multicast)
{
FAR const struct sockaddr_in *addr4;
FAR const struct sockaddr_in6 *addr6;
struct ipv6_mreq request6;
struct ip_mreq request4;
SOPC_ReturnStatus status;
if (multicast->addrinfo.ai_family == AF_INET6)
{
addr6 = (FAR const struct sockaddr_in6 *)multicast->addrinfo.ai_addr;
memset(&request6, 0, sizeof(request6));
request6.ipv6mr_multiaddr = addr6->sin6_addr;
if (interface_name != NULL)
{
#ifdef CONFIG_NETDEV_IFINDEX
request6.ipv6mr_interface = if_nametoindex(interface_name);
if (request6.ipv6mr_interface == 0)
{
return SOPC_STATUS_NOK;
}
#else
return SOPC_STATUS_NOT_SUPPORTED;
#endif
}
return setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &request6,
sizeof(request6)) == 0 ? SOPC_STATUS_OK :
SOPC_STATUS_NOT_SUPPORTED;
}
if (multicast->addrinfo.ai_family != AF_INET)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
addr4 = (FAR const struct sockaddr_in *)multicast->addrinfo.ai_addr;
memset(&request4, 0, sizeof(request4));
request4.imr_multiaddr = addr4->sin_addr;
status = s2opc_udp_ipv4_interface(interface_name,
&request4.imr_interface);
if (status != SOPC_STATUS_OK)
{
return status;
}
return setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &request4,
sizeof(request4)) == 0 ? SOPC_STATUS_OK :
SOPC_STATUS_NOT_SUPPORTED;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_UDP_SocketAddress_Create
****************************************************************************/
FAR SOPC_Socket_AddressInfo *
SOPC_UDP_SocketAddress_Create(bool ipv6, FAR const char *node,
FAR const char *service)
{
FAR SOPC_Socket_AddressInfo *address = NULL;
if (s2opc_udp_resolve(ipv6, node, service, &address) != SOPC_STATUS_OK)
{
return NULL;
}
return address;
}
/****************************************************************************
* Name: SOPC_UDP_SocketAddress_Delete
****************************************************************************/
void SOPC_UDP_SocketAddress_Delete(FAR SOPC_Socket_AddressInfo **address)
{
SOPC_Socket_AddrInfoDelete(address);
}
/****************************************************************************
* Name: SOPC_UDP_Socket_Set_MulticastTTL
****************************************************************************/
SOPC_ReturnStatus SOPC_UDP_Socket_Set_MulticastTTL(SOPC_Socket sock,
uint8_t scope)
{
int value = scope;
int level;
int option;
if (sock == SOPC_INVALID_SOCKET)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
if (sock->family == AF_INET6)
{
level = IPPROTO_IPV6;
option = IPV6_MULTICAST_HOPS;
}
else
{
level = IPPROTO_IP;
option = IP_MULTICAST_TTL;
}
return setsockopt(sock->sock, level, option, &value, sizeof(value)) == 0 ?
SOPC_STATUS_OK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_UDP_Socket_CreateToReceive
****************************************************************************/
SOPC_ReturnStatus
SOPC_UDP_Socket_CreateToReceive(FAR SOPC_Socket_AddressInfo *listen_address,
FAR const char *interface_name, bool reuse,
bool nonblocking, FAR SOPC_Socket *sock)
{
SOPC_ReturnStatus status;
status = s2opc_udp_create(listen_address, interface_name, reuse,
nonblocking, sock);
if (status != SOPC_STATUS_OK)
{
return status;
}
if (bind((*sock)->sock, listen_address->addrinfo.ai_addr,
listen_address->addrinfo.ai_addrlen) < 0)
{
SOPC_UDP_Socket_Close(sock);
return SOPC_STATUS_NOK;
}
if (s2opc_udp_is_multicast(listen_address))
{
status = s2opc_udp_join_multicast((*sock)->sock, interface_name,
listen_address);
if (status != SOPC_STATUS_OK)
{
SOPC_UDP_Socket_Close(sock);
}
}
return status;
}
/****************************************************************************
* Name: SOPC_UDP_Socket_CreateToSend
****************************************************************************/
SOPC_ReturnStatus
SOPC_UDP_Socket_CreateToSend(FAR SOPC_Socket_AddressInfo *destination,
FAR const char *interface_name,
bool nonblocking, FAR SOPC_Socket *sock)
{
return s2opc_udp_create(destination, interface_name, false, nonblocking,
sock);
}
/****************************************************************************
* Name: SOPC_UDP_Socket_SendTo
****************************************************************************/
SOPC_ReturnStatus
SOPC_UDP_Socket_SendTo(SOPC_Socket sock,
FAR const SOPC_Socket_AddressInfo *destination,
FAR SOPC_Buffer *buffer)
{
ssize_t ret;
int error;
if (sock == SOPC_INVALID_SOCKET || destination == NULL || buffer == NULL ||
buffer->position != 0)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
do
{
ret = sendto(sock->sock, buffer->data, buffer->length, 0,
destination->addrinfo.ai_addr,
destination->addrinfo.ai_addrlen);
}
while (ret < 0 && errno == EINTR);
error = errno;
if (ret >= 0 && (uint32_t)ret == buffer->length)
{
return SOPC_STATUS_OK;
}
return ret < 0 && s2opc_udp_would_block(error) ?
SOPC_STATUS_WOULD_BLOCK : SOPC_STATUS_NOK;
}
/****************************************************************************
* Name: SOPC_UDP_Socket_ReceiveFrom
****************************************************************************/
SOPC_ReturnStatus SOPC_UDP_Socket_ReceiveFrom(SOPC_Socket sock,
FAR SOPC_Buffer *buffer)
{
struct sockaddr_storage source;
socklen_t source_length;
ssize_t ret;
int error;
if (sock == SOPC_INVALID_SOCKET || buffer == NULL)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
source_length = sizeof(source);
do
{
ret = recvfrom(sock->sock, buffer->data, buffer->current_size, 0,
(FAR struct sockaddr *)&source, &source_length);
}
while (ret < 0 && errno == EINTR);
error = errno;
if (ret < 0)
{
return s2opc_udp_would_block(error) ? SOPC_STATUS_WOULD_BLOCK :
SOPC_STATUS_NOK;
}
buffer->length = ret;
return buffer->length == buffer->current_size ?
SOPC_STATUS_OUT_OF_MEMORY : SOPC_STATUS_OK;
}
/****************************************************************************
* Name: SOPC_UDP_Socket_Close
****************************************************************************/
void SOPC_UDP_Socket_Close(FAR SOPC_Socket *sock)
{
SOPC_Socket_Close(sock);
}

View file

@ -0,0 +1,31 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/s2opc_common_export.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
#ifndef __APPS_NETUTILS_S2OPC_PORT_NUTTX_S2OPC_COMMON_EXPORT_H
#define __APPS_NETUTILS_S2OPC_PORT_NUTTX_S2OPC_COMMON_EXPORT_H
#define S2OPC_COMMON_EXPORT
#define S2OPC_COMMON_NO_EXPORT
#define S2OPC_COMMON_DEPRECATED __attribute__((deprecated))
#define S2OPC_COMMON_DEPRECATED_EXPORT S2OPC_COMMON_DEPRECATED
#define S2OPC_COMMON_DEPRECATED_NO_EXPORT S2OPC_COMMON_DEPRECATED
#endif /* __APPS_NETUTILS_S2OPC_PORT_NUTTX_S2OPC_COMMON_EXPORT_H */

View file

@ -0,0 +1,90 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/sopc_build_info.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "sopc_common_build_info.h"
#include "sopc_pubsub_build_info.h"
#include "sopc_toolkit_build_info.h"
#include "sopc_version.h"
/****************************************************************************
* Public Data
****************************************************************************/
const SOPC_Build_Info sopc_common_build_info =
{
.buildVersion = SOPC_TOOLKIT_VERSION,
.buildSrcCommit = "S2OPC_Toolkit_" CONFIG_S2OPC_VERSION,
.buildDockerId = "",
.buildBuildDate = ""
};
const SOPC_Build_Info sopc_client_server_build_info =
{
.buildVersion = SOPC_TOOLKIT_VERSION,
.buildSrcCommit = "S2OPC_Toolkit_" CONFIG_S2OPC_VERSION,
.buildDockerId = "",
.buildBuildDate = ""
};
const SOPC_Build_Info sopc_pubsub_build_info =
{
.buildVersion = SOPC_TOOLKIT_VERSION,
.buildSrcCommit = "S2OPC_Toolkit_" CONFIG_S2OPC_VERSION,
.buildDockerId = "",
.buildBuildDate = ""
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: SOPC_Common_GetBuildInfo
****************************************************************************/
SOPC_Build_Info SOPC_Common_GetBuildInfo(void)
{
return sopc_common_build_info;
}
/****************************************************************************
* Name: SOPC_ClientServer_GetBuildInfo
****************************************************************************/
SOPC_Build_Info SOPC_ClientServer_GetBuildInfo(void)
{
return sopc_client_server_build_info;
}
/****************************************************************************
* Name: SOPC_PubSub_GetBuildInfo
****************************************************************************/
SOPC_Build_Info SOPC_PubSub_GetBuildInfo(void)
{
return sopc_pubsub_build_info;
}

View file

@ -0,0 +1,79 @@
/****************************************************************************
* apps/netutils/s2opc/port/nuttx/sopc_nuttx_config.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
****************************************************************************/
#ifndef __APPS_NETUTILS_S2OPC_PORT_NUTTX_SOPC_NUTTX_CONFIG_H
#define __APPS_NETUTILS_S2OPC_PORT_NUTTX_SOPC_NUTTX_CONFIG_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdbool.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* S2OPC uses Boolean constants in preprocessor expressions. NuttX
* deliberately defines false and true as typed expressions. Preserve the
* standard Boolean type, but provide untyped values to the S2OPC sources.
*/
#undef false
#undef true
#define false 0
#define true 1
#ifndef IPV6_ADD_MEMBERSHIP
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#endif
#ifndef IPV6_DROP_MEMBERSHIP
# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
#define SOPC_MAX_NB_ELEMENTS_ASYNC_QUEUE_WARNING_ONLY 1
#define SOPC_HAS_FILESYSTEM 1
#define SOPC_LISTENER_LISTEN_ALL_INTERFACES 1
#ifdef CONFIG_S2OPC_NODE_MANAGEMENT
# define S2OPC_NODE_MANAGEMENT 1
#endif
#ifdef CONFIG_S2OPC_NODE_ADD_OPTIONAL
# define S2OPC_NODE_ADD_OPTIONAL 1
#endif
#ifdef CONFIG_S2OPC_HISTORY_READ
# define S2OPC_EXTERNAL_HISTORY_RAW_READ_SERVICE 1
#endif
#ifdef CONFIG_S2OPC_EVENT_MANAGEMENT
# define S2OPC_EVENT_MANAGEMENT 1
#endif
#ifdef CONFIG_S2OPC_AUDITING
# define S2OPC_HAS_AUDITING 1
#endif
#endif /* __APPS_NETUTILS_S2OPC_PORT_NUTTX_SOPC_NUTTX_CONFIG_H */