mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-09-08 09:46:31 +00:00
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:
parent
0ae2c5391c
commit
35133b6a63
21 changed files with 4434 additions and 0 deletions
2
netutils/s2opc/.gitignore
vendored
Normal file
2
netutils/s2opc/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/s2opc
|
||||
/S2OPC_Toolkit_*.tar.gz
|
||||
254
netutils/s2opc/CMakeLists.txt
Normal file
254
netutils/s2opc/CMakeLists.txt
Normal 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
109
netutils/s2opc/Kconfig
Normal 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
68
netutils/s2opc/Make.defs
Normal 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
195
netutils/s2opc/Makefile
Normal 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
|
||||
114
netutils/s2opc/port/nuttx/p_sopc_askpass.c
Normal file
114
netutils/s2opc/port/nuttx/p_sopc_askpass.c
Normal 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;
|
||||
}
|
||||
77
netutils/s2opc/port/nuttx/p_sopc_atomic.c
Normal file
77
netutils/s2opc/port/nuttx/p_sopc_atomic.c
Normal 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);
|
||||
}
|
||||
83
netutils/s2opc/port/nuttx/p_sopc_date_time.c
Normal file
83
netutils/s2opc/port/nuttx/p_sopc_date_time.c
Normal 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, ¤t) < 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;
|
||||
}
|
||||
678
netutils/s2opc/port/nuttx/p_sopc_eth_sockets.c
Normal file
678
netutils/s2opc/port/nuttx/p_sopc_eth_sockets.c
Normal 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 */
|
||||
225
netutils/s2opc/port/nuttx/p_sopc_filesystem.c
Normal file
225
netutils/s2opc/port/nuttx/p_sopc_filesystem.c
Normal 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);
|
||||
}
|
||||
72
netutils/s2opc/port/nuttx/p_sopc_mem_alloc.c
Normal file
72
netutils/s2opc/port/nuttx/p_sopc_mem_alloc.c
Normal 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);
|
||||
}
|
||||
87
netutils/s2opc/port/nuttx/p_sopc_random.c
Normal file
87
netutils/s2opc/port/nuttx/p_sopc_random.c
Normal 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;
|
||||
}
|
||||
874
netutils/s2opc/port/nuttx/p_sopc_sockets.c
Normal file
874
netutils/s2opc/port/nuttx/p_sopc_sockets.c
Normal 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;
|
||||
}
|
||||
64
netutils/s2opc/port/nuttx/p_sopc_sockets.h
Normal file
64
netutils/s2opc/port/nuttx/p_sopc_sockets.h
Normal 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 */
|
||||
473
netutils/s2opc/port/nuttx/p_sopc_threads.c
Normal file
473
netutils/s2opc/port/nuttx/p_sopc_threads.c
Normal 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, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
}
|
||||
}
|
||||
52
netutils/s2opc/port/nuttx/p_sopc_threads.h
Normal file
52
netutils/s2opc/port/nuttx/p_sopc_threads.h
Normal 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 */
|
||||
309
netutils/s2opc/port/nuttx/p_sopc_time_reference.c
Normal file
309
netutils/s2opc/port/nuttx/p_sopc_time_reference.c
Normal 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, ¤t) < 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(¤t);
|
||||
now = ¤t;
|
||||
}
|
||||
|
||||
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(¤t);
|
||||
time = ¤t;
|
||||
}
|
||||
|
||||
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, ¤t);
|
||||
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));
|
||||
}
|
||||
}
|
||||
498
netutils/s2opc/port/nuttx/p_sopc_udp_sockets.c
Normal file
498
netutils/s2opc/port/nuttx/p_sopc_udp_sockets.c
Normal 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);
|
||||
}
|
||||
31
netutils/s2opc/port/nuttx/s2opc_common_export.h
Normal file
31
netutils/s2opc/port/nuttx/s2opc_common_export.h
Normal 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 */
|
||||
90
netutils/s2opc/port/nuttx/sopc_build_info.c
Normal file
90
netutils/s2opc/port/nuttx/sopc_build_info.c
Normal 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;
|
||||
}
|
||||
79
netutils/s2opc/port/nuttx/sopc_nuttx_config.h
Normal file
79
netutils/s2opc/port/nuttx/sopc_nuttx_config.h
Normal 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 */
|
||||
Loading…
Add table
Add a link
Reference in a new issue