From 6b9437b8c09a6a431e865752584d4d2f7b911c88 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 17 Sep 2021 15:53:10 +0200 Subject: [PATCH] - unified HAL with lib60870 and libtase2 (LIB61850-261) --- hal/inc/hal_base.h | 19 +-- hal/inc/hal_ethernet.h | 20 +-- hal/inc/hal_filesystem.h | 20 +-- hal/inc/hal_serial.h | 20 +-- hal/inc/hal_socket.h | 34 ++--- hal/inc/hal_thread.h | 20 +-- hal/inc/hal_time.h | 20 +-- hal/inc/lib_memory.h | 22 +-- hal/inc/platform_endian.h | 20 +-- hal/inc/tls_config.h | 94 ++++++++++++- hal/inc/tls_socket.h | 2 +- hal/memory/lib_memory.c | 20 +-- hal/serial/linux/serial_port_linux.c | 20 +-- hal/serial/win32/serial_port_win32.c | 20 +-- hal/socket/bsd/socket_bsd.c | 47 +++---- hal/socket/linux/socket_linux.c | 123 +++++++++++------ hal/socket/win32/socket_win32.c | 145 ++++++++++++-------- hal/thread/bsd/thread_bsd.c | 67 ++++------ hal/thread/linux/thread_linux.c | 72 ++++------ hal/thread/macos/thread_macos.c | 2 +- hal/thread/win32/thread_win32.c | 20 +-- hal/time/unix/time.c | 19 +-- hal/time/win32/time.c | 52 +++----- hal/tls/mbedtls/mbedtls_config.h | 1 + hal/tls/mbedtls/tls_mbedtls.c | 191 +++++++++++++++++++++++---- 25 files changed, 580 insertions(+), 510 deletions(-) diff --git a/hal/inc/hal_base.h b/hal/inc/hal_base.h index b8a3611b..6fe3a417 100644 --- a/hal/inc/hal_base.h +++ b/hal/inc/hal_base.h @@ -1,25 +1,10 @@ /* * hal_base.h * - * Copyright 2018 MZ Automation GmbH + * Copyright 2013-2021 Michael Zillgith * * This file is part of Platform Abstraction Layer (libpal) - * for libiec61850 and lib60870. - * - * libpal is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libpal is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libpal. If not, see . - * - * See COPYING file for the complete license text. + * for libiec61850, libmms, and lib60870. */ #ifndef HAL_INC_HAL_BASE_H_ diff --git a/hal/inc/hal_ethernet.h b/hal/inc/hal_ethernet.h index c7822407..6cf03f34 100644 --- a/hal/inc/hal_ethernet.h +++ b/hal/inc/hal_ethernet.h @@ -1,24 +1,10 @@ /* * ethernet_hal.h * - * Copyright 2013, 2014 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef ETHERNET_HAL_H_ diff --git a/hal/inc/hal_filesystem.h b/hal/inc/hal_filesystem.h index d4ff6691..56184117 100644 --- a/hal/inc/hal_filesystem.h +++ b/hal/inc/hal_filesystem.h @@ -1,24 +1,10 @@ /* * filesystem_hal.h * - * Copyright 2014 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef FILESYSTEM_HAL_H_ diff --git a/hal/inc/hal_serial.h b/hal/inc/hal_serial.h index a56a5fb5..a02a1a1b 100644 --- a/hal/inc/hal_serial.h +++ b/hal/inc/hal_serial.h @@ -1,24 +1,10 @@ /* * hal_serial.h * - * Copyright 2017 MZ Automation GmbH + * Copyright 2013-2021 Michael Zillgith * - * This file is part of lib60870-C - * - * lib60870-C is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * lib60870-C is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with lib60870-C. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef SRC_IEC60870_LINK_LAYER_SERIAL_PORT_H_ diff --git a/hal/inc/hal_socket.h b/hal/inc/hal_socket.h index 414a1a7e..5c594f83 100644 --- a/hal/inc/hal_socket.h +++ b/hal/inc/hal_socket.h @@ -1,24 +1,10 @@ /* * socket_hal.h * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef SOCKET_HAL_H_ @@ -242,6 +228,20 @@ TcpSocket_create(void); PAL_API void Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs); +/** + * \brief bind a socket to a particular IP address and port (for TcpSocket) + * + * NOTE: Don't use the socket when this functions returns false! + * + * \param self the client socket instance + * \param srcAddress the local IP address or hostname as C string + * \param srcPort the local TCP port to use. When < 1 the OS will chose the TCP port to use. + * + * \return true in case of success, false otherwise + */ +PAL_API bool +Socket_bind(Socket self, const char* srcAddress, int srcPort); + /** * \brief connect to a server * diff --git a/hal/inc/hal_thread.h b/hal/inc/hal_thread.h index 0558f9e4..0a88553e 100644 --- a/hal/inc/hal_thread.h +++ b/hal/inc/hal_thread.h @@ -3,24 +3,10 @@ * * Multi-threading abstraction layer * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef THREAD_HAL_H_ diff --git a/hal/inc/hal_time.h b/hal/inc/hal_time.h index 7d5a942c..b19bcd4b 100644 --- a/hal/inc/hal_time.h +++ b/hal/inc/hal_time.h @@ -1,24 +1,10 @@ /* * time.c * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef HAL_C_ diff --git a/hal/inc/lib_memory.h b/hal/inc/lib_memory.h index 63463a8e..927a98a7 100644 --- a/hal/inc/lib_memory.h +++ b/hal/inc/lib_memory.h @@ -1,24 +1,10 @@ /* * lib_memory.h * - * Copyright 2014 Michael Zillgith + * Copyright 2014-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef MEMORY_H_ @@ -40,6 +26,8 @@ extern "C" { #endif +#include + typedef void (*MemoryExceptionHandler) (void* parameter); diff --git a/hal/inc/platform_endian.h b/hal/inc/platform_endian.h index 76c410af..6a6cdd4c 100644 --- a/hal/inc/platform_endian.h +++ b/hal/inc/platform_endian.h @@ -1,24 +1,10 @@ /* * platform_endian.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #ifndef ENDIAN_H_ diff --git a/hal/inc/tls_config.h b/hal/inc/tls_config.h index dea44c43..2accacaa 100644 --- a/hal/inc/tls_config.h +++ b/hal/inc/tls_config.h @@ -3,7 +3,7 @@ * * TLS Configuration API for protocol stacks using TCP/IP * - * Copyright 2017-2018 MZ Automation GmbH + * Copyright 2017-2021 Michael Zillgith * * Abstraction layer for configuration of different TLS implementations * @@ -90,21 +90,64 @@ TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, PAL_API bool TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename); +/** + * \brief Set the own private key from a byte buffer + * + * \param key the private key to use + * \param keyLen the length of the key + * \param password the password of the key or null if the key is not password protected + * + * \return true, when the key was set, false otherwise (e.g. unknown key format) + */ PAL_API bool TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword); +/** + * \brief Set the own private key from a key file + * + * \param filename filename/path of the key file + * \param password the password of the key or null if the key is not password protected + * + * \return true, when the key was set, false otherwise (e.g. unknown key format) + */ PAL_API bool TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword); +/** + * Add a certificate to the list of allowed peer certificates from a byte buffer + * + * \param certificate the certificate buffer + * \param certLen the length of the certificate buffer + * \return true, when the certificate was set, false otherwise (e.g. unknown certificate format) + */ PAL_API bool -TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certifcate, int certLen); +TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certificate, int certLen); +/** + * \brief Add a certificate to the list of allowed peer certificates + * + * \param filename filename of the certificate file + * \return true, when the certificate was set, false otherwise (e.g. unknown certificate format) + */ PAL_API bool TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename); +/** + * \brief Add a CA certificate used to validate peer certificates from a byte buffer + * + * \param certificate the certificate buffer + * \param certLen the length of the certificate buffer + * \return true, when the certificate was set, false otherwise (e.g. unknown certificate format) + */ PAL_API bool -TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certifcate, int certLen); +TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, int certLen); +/** + * \brief Add a CA certificate used to validate peer certificates from a file + * + * \param filename filename of the certificate file + * \return true, when the certificate was set, false otherwise (e.g. unknown certificate format) + */ PAL_API bool TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename); @@ -118,6 +161,51 @@ TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* fil PAL_API void TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs); +typedef enum { + TLS_VERSION_NOT_SELECTED = 0, + TLS_VERSION_SSL_3_0 = 3, + TLS_VERSION_TLS_1_0 = 4, + TLS_VERSION_TLS_1_1 = 5, + TLS_VERSION_TLS_1_2 = 6, + TLS_VERSION_TLS_1_3 = 7 +} TLSConfigVersion; + +/** + * \brief Set minimal allowed TLS version to use + */ +PAL_API void +TLSConfiguration_setMinTlsVersion(TLSConfiguration self, TLSConfigVersion version); + +/** + * \brief Set maximal allowed TLS version to use + */ +PAL_API void +TLSConfiguration_setMaxTlsVersion(TLSConfiguration self, TLSConfigVersion version); + +/** + * \brief Add a CRL (certificate revocation list) from buffer + * + * \param crl the buffer containing the CRL + * \param crlLen the length of the CRL buffer + * \return true, when the CRL was imported, false otherwise (e.g. unknown format) + */ +PAL_API bool +TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen); + +/** + * \brief Add a CRL (certificate revocation list) from a file + * + * \param filename filename of the CRL file + * \return true, when the CRL was imported, false otherwise (e.g. unknown format) + */ +PAL_API bool +TLSConfiguration_addCRLFromFile(TLSConfiguration self, const char* filename); + +/** + * Release all resource allocated by the TLSConfiguration instance + * + * NOTE: Do not use the object after calling this function! + */ PAL_API void TLSConfiguration_destroy(TLSConfiguration self); diff --git a/hal/inc/tls_socket.h b/hal/inc/tls_socket.h index ac5b8c15..fa682f4f 100644 --- a/hal/inc/tls_socket.h +++ b/hal/inc/tls_socket.h @@ -3,7 +3,7 @@ * * TLS socket API for protocol libraries using TCP/IP * - * Copyright 2017-2020 Michael Zillgith, MZ Automation GmbH + * Copyright 2017-2021 Michael Zillgith, MZ Automation GmbH * * Abstraction layer for different TLS implementations * diff --git a/hal/memory/lib_memory.c b/hal/memory/lib_memory.c index 623ba212..adeb105a 100644 --- a/hal/memory/lib_memory.c +++ b/hal/memory/lib_memory.c @@ -1,24 +1,10 @@ /* * lib_memory.c * - * Copyright 2014-2018 Michael Zillgith + * Copyright 2014-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include diff --git a/hal/serial/linux/serial_port_linux.c b/hal/serial/linux/serial_port_linux.c index 64acf77d..f976e724 100644 --- a/hal/serial/linux/serial_port_linux.c +++ b/hal/serial/linux/serial_port_linux.c @@ -1,24 +1,10 @@ /* * serial_port_linux.c * - * Copyright 2017 MZ Automation GmbH + * Copyright 2013-2021 Michael Zillgith * - * This file is part of lib60870-C - * - * lib60870-C is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * lib60870-C is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with lib60870-C. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include "lib_memory.h" diff --git a/hal/serial/win32/serial_port_win32.c b/hal/serial/win32/serial_port_win32.c index 186cd214..b00ec629 100644 --- a/hal/serial/win32/serial_port_win32.c +++ b/hal/serial/win32/serial_port_win32.c @@ -1,24 +1,10 @@ /* * serial_port_win32.c * -* Copyright 2017 MZ Automation GmbH +* Copyright 2013-2021 Michael Zillgith * -* This file is part of lib60870-C -* -* lib60870-C is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* lib60870-C is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with lib60870-C. If not, see . -* -* See COPYING file for the complete license text. +* This file is part of Platform Abstraction Layer (libpal) +* for libiec61850, libmms, and lib60870. */ #include diff --git a/hal/socket/bsd/socket_bsd.c b/hal/socket/bsd/socket_bsd.c index 2079ba87..198ad227 100644 --- a/hal/socket/bsd/socket_bsd.c +++ b/hal/socket/bsd/socket_bsd.c @@ -1,25 +1,10 @@ /* * socket_bsd.c * - * Copyright 2013-2020 Michael Zillgith - * contributions by Michael Clausen (School of engineering Valais). + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include "hal_socket.h" @@ -199,7 +184,7 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count) } static bool -prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) +prepareAddress(const char* address, int port, struct sockaddr_in* sockaddr) { memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); @@ -246,7 +231,7 @@ TcpServerSocket_create(const char* address, int port) if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) { struct sockaddr_in serverAddress; - if (!prepareServerAddress(address, port, &serverAddress)) { + if (!prepareAddress(address, port, &serverAddress)) { close(fd); return NULL; } @@ -257,7 +242,7 @@ TcpServerSocket_create(const char* address, int port) if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) { serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket)); serverSocket->fd = fd; - serverSocket->backLog = 0; + serverSocket->backLog = 2; setSocketNonBlocking((Socket) serverSocket); } @@ -345,7 +330,7 @@ ServerSocket_destroy(ServerSocket self) Socket TcpSocket_create() { - Socket self = NULL; + Socket self = (Socket)NULL; int sock = socket(AF_INET, SOCK_STREAM, 0); @@ -368,7 +353,6 @@ TcpSocket_create() if (DEBUG_SOCKET) printf("SOCKET: out of memory\n"); } - } else { if (DEBUG_SOCKET) @@ -385,15 +369,24 @@ Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) } bool -Socket_setLocalAddress(Socket self, const char* address, int port) +Socket_bind(Socket self, const char* srcAddress, int srcPort) { - struct sockaddr_in clientAddress; + struct sockaddr_in localAddress; - if (!prepareServerAddress(address, port, &clientAddress)) + if (!prepareAddress(srcAddress, srcPort, &localAddress)) return false; - if (bind(self->fd, (struct sockaddr *) &clientAddress, sizeof(clientAddress)) != 0) + int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress)); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to bind TCP socket (errno=%i)\n", errno); + + close(self->fd); + self->fd = -1; + return false; + } return true; } diff --git a/hal/socket/linux/socket_linux.c b/hal/socket/linux/socket_linux.c index 3c3b284c..33ead6ab 100644 --- a/hal/socket/linux/socket_linux.c +++ b/hal/socket/linux/socket_linux.c @@ -1,34 +1,21 @@ /* * socket_linux.c * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include "hal_socket.h" #include #include -#include #include #include #include #include +#include +#include #include #include #include @@ -215,7 +202,7 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count) } static bool -prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) +prepareAddress(const char* address, int port, struct sockaddr_in* sockaddr) { bool retVal = true; @@ -231,6 +218,10 @@ prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr result = getaddrinfo(address, NULL, &addressHints, &lookupResult); if (result != 0) { + + if (DEBUG_SOCKET) + printf("SOCKET: getaddrinfo failed (code=%i)\n", result); + retVal = false; goto exit_function; } @@ -242,6 +233,10 @@ prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr sockaddr->sin_addr.s_addr = htonl(INADDR_ANY); sockaddr->sin_family = AF_INET; + + if (port < 0) + port = 0; + sockaddr->sin_port = htons(port); exit_function: @@ -273,7 +268,7 @@ TcpServerSocket_create(const char* address, int port) if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) { struct sockaddr_in serverAddress; - if (!prepareServerAddress(address, port, &serverAddress)) { + if (!prepareAddress(address, port, &serverAddress)) { close(fd); return NULL; } @@ -327,9 +322,19 @@ ServerSocket_accept(ServerSocket self) if (fd >= 0) { conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket)); - conSocket->fd = fd; - activateTcpNoDelay(conSocket); + if (conSocket) { + conSocket->fd = fd; + + activateTcpNoDelay(conSocket); + } + else { + /* out of memory */ + close(fd); + + if (DEBUG_SOCKET) + printf("SOCKET: out of memory\n"); + } } return conSocket; @@ -350,9 +355,19 @@ closeAndShutdownSocket(int socketFd) printf("SOCKET: call shutdown for %i!\n", socketFd); /* shutdown is required to unblock read or accept in another thread! */ - shutdown(socketFd, SHUT_RDWR); + int result = shutdown(socketFd, SHUT_RDWR); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: shutdown error: %i\n", errno); + } - close(socketFd); + result = close(socketFd); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: close error: %i\n", errno); + } } } @@ -373,26 +388,34 @@ ServerSocket_destroy(ServerSocket self) Socket TcpSocket_create() { - Socket self = NULL; + Socket self = (Socket)NULL; int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock != -1) { self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket)); - self->fd = sock; - self->connectTimeout = 5000; + if (self) { + self->fd = sock; + self->connectTimeout = 5000; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) - int tcpUserTimeout = 10000; - int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout)); + int tcpUserTimeout = 10000; + int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout)); - if (result < 0) { - if (DEBUG_SOCKET) - printf("SOCKET: failed to set TCP_USER_TIMEOUT\n"); - } + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to set TCP_USER_TIMEOUT (errno=%i)\n", errno); + } #endif + } + else { + /* out of memory */ + close(sock); + if (DEBUG_SOCKET) + printf("SOCKET: out of memory\n"); + } } else { if (DEBUG_SOCKET) @@ -402,13 +425,35 @@ TcpSocket_create() return self; } - void Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) { self->connectTimeout = timeoutInMs; } +bool +Socket_bind(Socket self, const char* srcAddress, int srcPort) +{ + struct sockaddr_in localAddress; + + if (!prepareAddress(srcAddress, srcPort, &localAddress)) + return false; + + int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress)); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to bind TCP socket (errno=%i)\n", errno); + + close(self->fd); + self->fd = -1; + + return false; + } + + return true; +} + bool Socket_connectAsync(Socket self, const char* address, int port) { @@ -417,7 +462,7 @@ Socket_connectAsync(Socket self, const char* address, int port) if (DEBUG_SOCKET) printf("SOCKET: connect: %s:%i\n", address, port); - if (!prepareServerAddress(address, port, &serverAddress)) + if (!prepareAddress(address, port, &serverAddress)) return false; fd_set fdSet; @@ -627,6 +672,8 @@ Socket_read(Socket self, uint8_t* buf, int size) case EAGAIN: return 0; + case EBADF: + return -1; default: @@ -647,7 +694,7 @@ Socket_write(Socket self, uint8_t* buf, int size) return -1; /* MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket */ - int retVal = send(self->fd, buf, size, MSG_NOSIGNAL); + int retVal = send(self->fd, buf, size, MSG_NOSIGNAL | MSG_DONTWAIT); if (retVal == -1) { if (errno == EAGAIN) { @@ -701,7 +748,7 @@ UdpSocket_bind(UdpSocket self, const char* address, int port) { struct sockaddr_in localAddress; - if (!prepareServerAddress(address, port, &localAddress)) { + if (!prepareAddress(address, port, &localAddress)) { close(self->fd); self->fd = 0; return false; @@ -727,7 +774,7 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in { struct sockaddr_in remoteAddress; - if (!prepareServerAddress(address, port, &remoteAddress)) { + if (!prepareAddress(address, port, &remoteAddress)) { if (DEBUG_SOCKET) printf("SOCKET: failed to lookup remote address %s\n", address); diff --git a/hal/socket/win32/socket_win32.c b/hal/socket/win32/socket_win32.c index 411265d8..2753154a 100644 --- a/hal/socket/win32/socket_win32.c +++ b/hal/socket/win32/socket_win32.c @@ -1,26 +1,14 @@ /* * socket_win32.c * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS #include #include #include @@ -65,13 +53,14 @@ struct sUdpSocket { HandleSet Handleset_new(void) { - HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); + HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); - if (result != NULL) { - FD_ZERO(&result->handles); - result->maxHandle = INVALID_SOCKET; - } - return result; + if (result != NULL) { + FD_ZERO(&result->handles); + result->maxHandle = INVALID_SOCKET; + } + + return result; } void @@ -97,37 +86,40 @@ void Handleset_removeSocket(HandleSet self, const Socket sock) { if (self != NULL && sock != NULL && sock->fd != INVALID_SOCKET) { - FD_CLR(sock->fd, &self->handles); + FD_SET(sock->fd, &self->handles); + + if ((sock->fd > self->maxHandle) || (self->maxHandle == INVALID_SOCKET)) + self->maxHandle = sock->fd; } } int Handleset_waitReady(HandleSet self, unsigned int timeoutMs) { - int result; + int result; - if ((self != NULL) && (self->maxHandle != INVALID_SOCKET)) { - struct timeval timeout; + if ((self != NULL) && (self->maxHandle != INVALID_SOCKET)) { + struct timeval timeout; - timeout.tv_sec = timeoutMs / 1000; - timeout.tv_usec = (timeoutMs % 1000) * 1000; + timeout.tv_sec = timeoutMs / 1000; + timeout.tv_usec = (timeoutMs % 1000) * 1000; - fd_set handles; + fd_set handles; - memcpy((void*)&handles, &(self->handles), sizeof(fd_set)); + memcpy((void*)&handles, &(self->handles), sizeof(fd_set)); - result = select(self->maxHandle + 1, &handles, NULL, NULL, &timeout); - } else { - result = -1; - } + result = select(self->maxHandle + 1, &handles, NULL, NULL, &timeout); + } else { + result = -1; + } - return result; + return result; } void Handleset_destroy(HandleSet self) { - GLOBAL_FREEMEM(self); + GLOBAL_FREEMEM(self); } static bool wsaStartupCalled = false; @@ -172,18 +164,18 @@ setSocketNonBlocking(Socket self) } static bool -prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr) +prepareAddress(const char *address, int port, struct sockaddr_in *sockaddr) { - - memset((char *) sockaddr , 0, sizeof(struct sockaddr_in)); + memset((char *)sockaddr, 0, sizeof(struct sockaddr_in)); if (address != NULL) { struct hostent *server; server = gethostbyname(address); - if (server == NULL) return false; + if (server == NULL) + return false; - memcpy((char *) &sockaddr->sin_addr.s_addr, (char *) server->h_addr, server->h_length); + memcpy((char *)&sockaddr->sin_addr.s_addr, (char *)server->h_addr, server->h_length); } else sockaddr->sin_addr.s_addr = htonl(INADDR_ANY); @@ -240,7 +232,7 @@ TcpServerSocket_create(const char* address, int port) struct sockaddr_in server_addr; - if (!prepareServerAddress(address, port, &server_addr)) + if (!prepareAddress(address, port, &server_addr)) return NULL; listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -269,14 +261,20 @@ TcpServerSocket_create(const char* address, int port) return NULL; } - serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket)); + serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket)); - serverSocket->fd = listen_socket; - serverSocket->backLog = 10; + if (serverSocket) { + serverSocket->fd = listen_socket; + serverSocket->backLog = 10; - setSocketNonBlocking((Socket) serverSocket); + setSocketNonBlocking((Socket)serverSocket); - socketCount++; + socketCount++; + } + else { + closesocket(listen_socket); + wsaShutdown(); + } return serverSocket; } @@ -346,14 +344,24 @@ TcpSocket_create() if (sock != INVALID_SOCKET) { self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket)); - self->fd = sock; - self->connectTimeout = 5000; + if (self) { + self->fd = sock; + self->connectTimeout = 5000; + + socketCount++; + } + else { + if (DEBUG_SOCKET) + printf("SOCKET: failed to create socket - cannot allocate memory\n"); + + closesocket(sock); + wsaShutdown(); + } - socketCount++; } else { if (DEBUG_SOCKET) - printf("WIN32_SOCKET: failed to create socket (error code=%i)\n", WSAGetLastError()); + printf("SOCKET: failed to create socket (error code=%i)\n", WSAGetLastError()); } return self; @@ -365,6 +373,29 @@ Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) self->connectTimeout = timeoutInMs; } +bool +Socket_bind(Socket self, const char* srcAddress, int srcPort) +{ + struct sockaddr_in localAddress; + + if (!prepareAddress(srcAddress, srcPort, &localAddress)) + return false; + + int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress)); + + if (result == SOCKET_ERROR) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to bind TCP socket (errno=%i)\n", WSAGetLastError()); + + closesocket(self->fd); + self->fd = -1; + + return false; + ] + + return true; +} + bool Socket_connectAsync(Socket self, const char* address, int port) { @@ -381,7 +412,7 @@ Socket_connectAsync(Socket self, const char* address, int port) return false; } - if (!prepareServerAddress(address, port, &serverAddress)) + if (!prepareAddress(address, port, &serverAddress)) return false; setSocketNonBlocking(self); @@ -438,7 +469,7 @@ Socket_connect(Socket self, const char* address, int port) { struct sockaddr_in serverAddress; - if (!prepareServerAddress(address, port, &serverAddress)) + if (!prepareAddress(address, port, &serverAddress)) return false; setSocketNonBlocking(self); @@ -456,7 +487,7 @@ Socket_connect(Socket self, const char* address, int port) timeout.tv_sec = self->connectTimeout / 1000; timeout.tv_usec = (self->connectTimeout % 1000) * 1000; - if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) <= 0) + if (select((int)self->fd + 1, NULL, &fdSet, NULL, &timeout) <= 0) return false; else return true; @@ -647,7 +678,7 @@ UdpSocket_bind(UdpSocket self, const char* address, int port) { struct sockaddr_in localAddress; - if (!prepareServerAddress(address, port, &localAddress)) { + if (!prepareAddress(address, port, &localAddress)) { closesocket(self->fd); self->fd = 0; return false; @@ -673,7 +704,7 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in { struct sockaddr_in remoteAddress; - if (!prepareServerAddress(address, port, &remoteAddress)) { + if (!prepareAddress(address, port, &remoteAddress)) { if (DEBUG_SOCKET) printf("SOCKET: failed to lookup remote address %s\n", address); diff --git a/hal/thread/bsd/thread_bsd.c b/hal/thread/bsd/thread_bsd.c index 23ed9512..ef501a9e 100644 --- a/hal/thread/bsd/thread_bsd.c +++ b/hal/thread/bsd/thread_bsd.c @@ -1,39 +1,24 @@ /** * thread_bsd.c * - * Copyright 2016 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include #include #include #include "hal_thread.h" - #include "lib_memory.h" struct sThread { - ThreadExecutionFunction function; - void* parameter; - pthread_t pthread; - int state; - bool autodestroy; + ThreadExecutionFunction function; + void* parameter; + pthread_t pthread; + int state; + bool autodestroy; }; Semaphore @@ -62,7 +47,8 @@ Semaphore_post(Semaphore self) void Semaphore_destroy(Semaphore self) { - sem_close(self); + sem_destroy((sem_t*) self); + GLOBAL_FREEMEM(self); } Thread @@ -85,38 +71,39 @@ destroyAutomaticThread(void* parameter) { Thread thread = (Thread) parameter; - thread->function(thread->parameter); + thread->function(thread->parameter); - GLOBAL_FREEMEM(thread); + GLOBAL_FREEMEM(thread); - pthread_exit(NULL); + pthread_exit(NULL); } void Thread_start(Thread thread) { - if (thread->autodestroy == true) { - pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); - pthread_detach(thread->pthread); - } - else - pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); - - thread->state = 1; + if (thread->autodestroy == true) { + pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); + pthread_detach(thread->pthread); + } + else + pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); + + thread->state = 1; } void Thread_destroy(Thread thread) { - if (thread->state == 1) { - pthread_join(thread->pthread, NULL); - } + if (thread->state == 1) { + pthread_join(thread->pthread, NULL); + } - GLOBAL_FREEMEM(thread); + GLOBAL_FREEMEM(thread); } void Thread_sleep(int millies) { - usleep(millies * 1000); + usleep(millies * 1000); } + diff --git a/hal/thread/linux/thread_linux.c b/hal/thread/linux/thread_linux.c index 488b7339..3c36d157 100644 --- a/hal/thread/linux/thread_linux.c +++ b/hal/thread/linux/thread_linux.c @@ -1,40 +1,24 @@ /* * thread_linux.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ - #include #include #include #include "hal_thread.h" - #include "lib_memory.h" struct sThread { - ThreadExecutionFunction function; - void* parameter; - pthread_t pthread; - int state; - bool autodestroy; + ThreadExecutionFunction function; + void* parameter; + pthread_t pthread; + int state; + bool autodestroy; }; Semaphore @@ -70,16 +54,16 @@ Semaphore_destroy(Semaphore self) Thread Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy) { - Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread)); + Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread)); - if (thread != NULL) { + if (thread != NULL) { thread->parameter = parameter; thread->function = function; thread->state = 0; thread->autodestroy = autodestroy; - } + } - return thread; + return thread; } static void* @@ -87,39 +71,39 @@ destroyAutomaticThread(void* parameter) { Thread thread = (Thread) parameter; - thread->function(thread->parameter); + thread->function(thread->parameter); - GLOBAL_FREEMEM(thread); + GLOBAL_FREEMEM(thread); - pthread_exit(NULL); + pthread_exit(NULL); } void Thread_start(Thread thread) { - if (thread->autodestroy == true) { - pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); - pthread_detach(thread->pthread); - } - else - pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); - - thread->state = 1; + if (thread->autodestroy == true) { + pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); + pthread_detach(thread->pthread); + } + else + pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); + + thread->state = 1; } void Thread_destroy(Thread thread) { - if (thread->state == 1) { - pthread_join(thread->pthread, NULL); - } + if (thread->state == 1) { + pthread_join(thread->pthread, NULL); + } - GLOBAL_FREEMEM(thread); + GLOBAL_FREEMEM(thread); } void Thread_sleep(int millies) { - usleep(millies * 1000); + usleep(millies * 1000); } diff --git a/hal/thread/macos/thread_macos.c b/hal/thread/macos/thread_macos.c index 64d9a6dd..2ba58b06 100644 --- a/hal/thread/macos/thread_macos.c +++ b/hal/thread/macos/thread_macos.c @@ -1,7 +1,7 @@ /** * thread_macos.c * - * Copyright 2013-2019 MZ Automation GmbH + * Copyright 2013-2021 Michael Zillgith * * This file is part of Platform Abstraction Layer (libpal) * for libiec61850, libmms, and lib60870. diff --git a/hal/thread/win32/thread_win32.c b/hal/thread/win32/thread_win32.c index aa72e613..7b17401d 100644 --- a/hal/thread/win32/thread_win32.c +++ b/hal/thread/win32/thread_win32.c @@ -1,24 +1,10 @@ /* * thread_win32.c * - * Copyright 2013, 2014 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include diff --git a/hal/time/unix/time.c b/hal/time/unix/time.c index 5c1bffe7..44094038 100644 --- a/hal/time/unix/time.c +++ b/hal/time/unix/time.c @@ -3,26 +3,11 @@ * * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include "hal_time.h" - #include #ifdef CONFIG_SYSTEM_HAS_CLOCK_GETTIME diff --git a/hal/time/win32/time.c b/hal/time/win32/time.c index 1e7adfe3..25faf710 100644 --- a/hal/time/win32/time.c +++ b/hal/time/win32/time.c @@ -1,61 +1,45 @@ /* * time.c * - * Copyright 2013, 2014 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * - * This file is part of libIEC61850. - * - * libIEC61850 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * libIEC61850 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libIEC61850. If not, see . - * - * See COPYING file for the complete license text. + * This file is part of Platform Abstraction Layer (libpal) + * for libiec61850, libmms, and lib60870. */ #include "hal_time.h" - #include - #include uint64_t Hal_getTimeInMs() { - FILETIME ft; - uint64_t now; + FILETIME ft; + uint64_t now; + + static const uint64_t DIFF_TO_UNIXTIME = 11644473600000ULL; - static const uint64_t DIFF_TO_UNIXTIME = 11644473600000ULL; - - GetSystemTimeAsFileTime(&ft); + GetSystemTimeAsFileTime(&ft); - now = (LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32LL); + now = (LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32LL); - return (now / 10000LL) - DIFF_TO_UNIXTIME; + return (now / 10000LL) - DIFF_TO_UNIXTIME; } nsSinceEpoch Hal_getTimeInNs() { - FILETIME ft; + FILETIME ft; - static const uint64_t DIFF_TO_UNIXTIME = 11644473600000000000ULL; + static const uint64_t DIFF_TO_UNIXTIME = 11644473600000000000ULL; - GetSystemTimeAsFileTime(&ft); + GetSystemTimeAsFileTime(&ft); - nsSinceEpoch nsTime = (LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32LL); + nsSinceEpoch nsTime = (LONGLONG)ft.dwLowDateTime + ((LONGLONG)(ft.dwHighDateTime) << 32LL); - nsTime = nsTime * 100LL - DIFF_TO_UNIXTIME; + nsTime = nsTime * 100LL - DIFF_TO_UNIXTIME; - return nsTime; + return nsTime; } bool @@ -65,8 +49,8 @@ Hal_setTimeInNs(nsSinceEpoch nsTime) FILETIME ft; - ft.dwLowDateTime = (uint32_t)(t & 0xffffffff); - ft.dwHighDateTime = (uint32_t)(t >> 32); + ft.dwLowDateTime = (uint32_t)(t & 0xffffffff); + ft.dwHighDateTime = (uint32_t)(t >> 32); SYSTEMTIME st; diff --git a/hal/tls/mbedtls/mbedtls_config.h b/hal/tls/mbedtls/mbedtls_config.h index 27d2aa83..e8414377 100644 --- a/hal/tls/mbedtls/mbedtls_config.h +++ b/hal/tls/mbedtls/mbedtls_config.h @@ -40,6 +40,7 @@ #define MBEDTLS_SSL_SRV_C #define MBEDTLS_SSL_TLS_C #define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CRL_PARSE_C #define MBEDTLS_X509_USE_C #define MBEDTLS_SSL_CACHE_C diff --git a/hal/tls/mbedtls/tls_mbedtls.c b/hal/tls/mbedtls/tls_mbedtls.c index 6f651769..4e3af470 100644 --- a/hal/tls/mbedtls/tls_mbedtls.c +++ b/hal/tls/mbedtls/tls_mbedtls.c @@ -3,7 +3,7 @@ * * TLS API for TCP/IP protocol stacks * - * Copyright 2017 MZ Automation GmbH + * Copyright 2017-2021 Michael Zillgith, MZ Automation GmbH * * Implementation of the TLS abstraction layer for mbedtls * @@ -14,6 +14,7 @@ #include "tls_socket.h" #include "hal_thread.h" #include "lib_memory.h" +#include "hal_time.h" #include "linked_list.h" #include "mbedtls/platform.h" @@ -27,9 +28,7 @@ #include "mbedtls/debug.h" #if (CONFIG_DEBUG_TLS == 1) -#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, \ - appId, \ - __VA_ARGS__) +#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__); #else #define DEBUG_PRINT(fmt, ...) {do {} while(0);} #endif @@ -44,15 +43,23 @@ struct sTLSConfiguration { mbedtls_x509_crt cacerts; + mbedtls_x509_crl crl; + mbedtls_ssl_config conf; LinkedList /* */ allowedCertificates; bool chainValidation; bool allowOnlyKnownCertificates; - /* TLS session renegotioation time in milliseconds */ + /* TLS session renegotiation interval in milliseconds */ int renegotiationTimeInMs; + /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_0) */ + TLSConfigVersion minVersion; + + /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */ + TLSConfigVersion maxVersion; + bool setupComplete; }; @@ -64,6 +71,9 @@ struct sTLSSocket { bool storePeerCert; uint8_t* peerCert; int peerCertLength; + + /* time of last session renegotiation (used to calculate next renegotiation time) */ + uint64_t lastRenegotiationTime; }; static bool @@ -147,7 +157,27 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth return 0; } +/* + * Finish configuration when used the first time. + */ +static bool +TLSConfiguration_setupComplete(TLSConfiguration self) +{ + if (self->setupComplete == false) { + mbedtls_ssl_conf_ca_chain( &(self->conf), &(self->cacerts), NULL ); + + int ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(self->ownCertificate), &(self->ownKey)); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); + return false; + } + self->setupComplete = true; + } + + return true; +} TLSConfiguration TLSConfiguration_create() @@ -157,7 +187,8 @@ TLSConfiguration_create() if (self != NULL) { mbedtls_ssl_config_init( &(self->conf) ); mbedtls_x509_crt_init( &(self->ownCertificate) ); - mbedtls_x509_crt_init( &(self->cacerts)); + mbedtls_x509_crt_init( &(self->cacerts) ); + mbedtls_x509_crl_init( &(self->crl) ); mbedtls_pk_init( &(self->ownKey) ); mbedtls_entropy_init( &(self->entropy) ); mbedtls_ctr_drbg_init( &(self->ctr_drbg) ); @@ -173,11 +204,16 @@ TLSConfiguration_create() mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED); - mbedtls_ssl_conf_renegotiation(&(self->conf), MBEDTLS_SSL_RENEGOTIATION_DISABLED); + mbedtls_ssl_conf_renegotiation(&(self->conf), MBEDTLS_SSL_RENEGOTIATION_ENABLED); /* static int hashes[] = {3,4,5,6,7,8,0}; */ /* mbedtls_ssl_conf_sig_hashes(&(self->conf), hashes); */ + self->minVersion = TLS_VERSION_TLS_1_0; + self->maxVersion = TLS_VERSION_NOT_SELECTED; + + self->renegotiationTimeInMs = -1; /* no automatic renegotiation */ + self->allowedCertificates = LinkedList_create(); /* default behavior is to allow all certificates that are signed by the CA */ @@ -195,6 +231,18 @@ TLSConfiguration_setClientMode(TLSConfiguration self) self->conf.endpoint = MBEDTLS_SSL_IS_CLIENT; } +void +TLSConfiguration_setMinTlsVersion(TLSConfiguration self, TLSConfigVersion version) +{ + self->minVersion = version; +} + +void +TLSConfiguration_setMaxTlsVersion(TLSConfiguration self, TLSConfigVersion version) +{ + self->maxVersion = version; +} + void TLSConfiguration_setChainValidation(TLSConfiguration self, bool value) { @@ -213,7 +261,7 @@ TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate, int ret = mbedtls_x509_crt_parse(&(self->ownCertificate), certificate, certLen); if (ret != 0) - DEBUG_PRINT("mbedtls_x509_crt_parse returned %d\n", ret); + DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned %d\n", ret); return (ret == 0); } @@ -309,6 +357,29 @@ TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* fil return (ret == 0); } +bool +TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen) +{ + int ret = mbedtls_x509_crl_parse(&(self->crl), crl, crlLen); + + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse returned %d\n", ret); + } + + return (ret == 0); +} + +bool +TLSConfiguration_addCRLFromFile(TLSConfiguration self, const char* filename) +{ + int ret = mbedtls_x509_crl_parse_file(&(self->crl), filename); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse_file returned %d\n", ret); + + return (ret == 0); +} + void TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs) { @@ -320,6 +391,7 @@ TLSConfiguration_destroy(TLSConfiguration self) { mbedtls_x509_crt_free(&(self->ownCertificate)); mbedtls_x509_crt_free(&(self->cacerts)); + mbedtls_x509_crl_free(&(self->crl)); mbedtls_pk_free(&(self->ownKey)); mbedtls_ssl_config_free(&(self->conf)); @@ -351,26 +423,42 @@ readFunction(void* ctx, unsigned char* buf, size_t len) return ret; } -/* - * Finish configuration when used the first time. - */ -static bool -TLSConfiguration_setupComplete(TLSConfiguration self) +static int +getMajorVersion(TLSConfigVersion version) { - if (self->setupComplete == false) { - mbedtls_ssl_conf_ca_chain( &(self->conf), &(self->cacerts), NULL ); - - int ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(self->ownCertificate), &(self->ownKey)); - - if (ret != 0) { - DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); - return false; - } - - self->setupComplete = true; + switch(version) { + case TLS_VERSION_NOT_SELECTED: + return 0; + case TLS_VERSION_SSL_3_0: + case TLS_VERSION_TLS_1_0: + case TLS_VERSION_TLS_1_1: + case TLS_VERSION_TLS_1_2: + case TLS_VERSION_TLS_1_3: + return 3; + default: + return 0; } +} - return true; +static int +getMinorVersion(TLSConfigVersion version) +{ + switch(version) { + case TLS_VERSION_NOT_SELECTED: + return 0; + case TLS_VERSION_SSL_3_0: + return 0; + case TLS_VERSION_TLS_1_0: + return 1; + case TLS_VERSION_TLS_1_1: + return 2; + case TLS_VERSION_TLS_1_2: + return 3; + case TLS_VERSION_TLS_1_3: + return 4; + default: + return 0; + } } TLSSocket @@ -392,7 +480,34 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*) self); - int ret = mbedtls_ssl_setup( &(self->ssl), &(self->conf) ); + int ret; + + mbedtls_ssl_conf_ca_chain( &(self->conf), &(configuration->cacerts), NULL ); + + if (configuration->minVersion != TLS_VERSION_NOT_SELECTED) { + /* set minimum TLS version */ + + int majorVer = getMajorVersion(configuration->minVersion); + int minorVer = getMinorVersion(configuration->minVersion); + + mbedtls_ssl_conf_min_version( &(self->conf), majorVer, minorVer); + } + + if (configuration->maxVersion != TLS_VERSION_NOT_SELECTED) { + /* set maximum TLS version */ + + int majorVer = getMajorVersion(configuration->maxVersion); + int minorVer = getMinorVersion(configuration->maxVersion); + + mbedtls_ssl_conf_max_version( &(self->conf), majorVer, minorVer); + } + + ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(configuration->ownCertificate), &(configuration->ownKey)); + + if (ret != 0) + DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); + + ret = mbedtls_ssl_setup( &(self->ssl), &(self->conf) ); if (ret != 0) DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret); @@ -404,15 +519,24 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { - DEBUG_PRINT("TLS", "mbedtls_ssl_handshake returned %d\n\n", ret ); + DEBUG_PRINT("TLS", "handshake failed - mbedtls_ssl_handshake --> %d\n\n", ret ); mbedtls_ssl_free(&(self->ssl)); + if (self->peerCert) { + GLOBAL_FREEMEM(self->peerCert); + } + GLOBAL_FREEMEM(self); return NULL; } } + + self->lastRenegotiationTime = Hal_getTimeInMs(); + + /* TODO check for TLS version warning or alarm condition */ + /* printf("TLS %i.%i\n", self->ssl.major_ver, self->ssl.minor_ver); */ } return self; @@ -439,6 +563,19 @@ TLSSocket_performHandshake(TLSSocket self) int TLSSocket_read(TLSSocket self, uint8_t* buf, int size) { + if (self->tlsConfig->renegotiationTimeInMs > 0) { + if (Hal_getTimeInMs() > self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs) { + if (TLSSocket_performHandshake(self) == false) { + DEBUG_PRINT("TLS", " renegotiation failed\n"); + return -1; + } + else { + DEBUG_PRINT("TLS", " started renegotiation\n"); + self->lastRenegotiationTime = Hal_getTimeInMs(); + } + } + } + int ret = mbedtls_ssl_read(&(self->ssl), buf, size); if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE))