- unified HAL with lib60870 and libtase2 (LIB61850-261)

pull/356/head
Michael Zillgith 4 years ago
parent 263c34f016
commit 6b9437b8c0

@ -1,25 +1,10 @@
/* /*
* hal_base.h * hal_base.h
* *
* Copyright 2018 MZ Automation GmbH * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of Platform Abstraction Layer (libpal) * This file is part of Platform Abstraction Layer (libpal)
* for libiec61850 and lib60870. * for libiec61850, libmms, 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef HAL_INC_HAL_BASE_H_ #ifndef HAL_INC_HAL_BASE_H_

@ -1,24 +1,10 @@
/* /*
* ethernet_hal.h * ethernet_hal.h
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef ETHERNET_HAL_H_ #ifndef ETHERNET_HAL_H_

@ -1,24 +1,10 @@
/* /*
* filesystem_hal.h * filesystem_hal.h
* *
* Copyright 2014 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef FILESYSTEM_HAL_H_ #ifndef FILESYSTEM_HAL_H_

@ -1,24 +1,10 @@
/* /*
* hal_serial.h * hal_serial.h
* *
* Copyright 2017 MZ Automation GmbH * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of lib60870-C * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef SRC_IEC60870_LINK_LAYER_SERIAL_PORT_H_ #ifndef SRC_IEC60870_LINK_LAYER_SERIAL_PORT_H_

@ -1,24 +1,10 @@
/* /*
* socket_hal.h * socket_hal.h
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef SOCKET_HAL_H_ #ifndef SOCKET_HAL_H_
@ -242,6 +228,20 @@ TcpSocket_create(void);
PAL_API void PAL_API void
Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs); 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 * \brief connect to a server
* *

@ -3,24 +3,10 @@
* *
* Multi-threading abstraction layer * Multi-threading abstraction layer
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef THREAD_HAL_H_ #ifndef THREAD_HAL_H_

@ -1,24 +1,10 @@
/* /*
* time.c * time.c
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef HAL_C_ #ifndef HAL_C_

@ -1,24 +1,10 @@
/* /*
* lib_memory.h * lib_memory.h
* *
* Copyright 2014 Michael Zillgith * Copyright 2014-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef MEMORY_H_ #ifndef MEMORY_H_
@ -40,6 +26,8 @@
extern "C" { extern "C" {
#endif #endif
#include <stdlib.h>
typedef void typedef void
(*MemoryExceptionHandler) (void* parameter); (*MemoryExceptionHandler) (void* parameter);

@ -1,24 +1,10 @@
/* /*
* platform_endian.h * platform_endian.h
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#ifndef ENDIAN_H_ #ifndef ENDIAN_H_

@ -3,7 +3,7 @@
* *
* TLS Configuration API for protocol stacks using TCP/IP * 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 * Abstraction layer for configuration of different TLS implementations
* *
@ -90,21 +90,64 @@ TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate,
PAL_API bool PAL_API bool
TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename); 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 PAL_API bool
TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword); 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 PAL_API bool
TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword); 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 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 PAL_API bool
TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename); 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 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 PAL_API bool
TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename); TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename);
@ -118,6 +161,51 @@ TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* fil
PAL_API void PAL_API void
TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs); 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 PAL_API void
TLSConfiguration_destroy(TLSConfiguration self); TLSConfiguration_destroy(TLSConfiguration self);

@ -3,7 +3,7 @@
* *
* TLS socket API for protocol libraries using TCP/IP * 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 * Abstraction layer for different TLS implementations
* *

@ -1,24 +1,10 @@
/* /*
* lib_memory.c * lib_memory.c
* *
* Copyright 2014-2018 Michael Zillgith * Copyright 2014-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include <stdlib.h> #include <stdlib.h>

@ -1,24 +1,10 @@
/* /*
* serial_port_linux.c * serial_port_linux.c
* *
* Copyright 2017 MZ Automation GmbH * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of lib60870-C * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include "lib_memory.h" #include "lib_memory.h"

@ -1,24 +1,10 @@
/* /*
* serial_port_win32.c * serial_port_win32.c
* *
* Copyright 2017 MZ Automation GmbH * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of lib60870-C * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include <stdint.h> #include <stdint.h>

@ -1,25 +1,10 @@
/* /*
* socket_bsd.c * socket_bsd.c
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* contributions by Michael Clausen (School of engineering Valais).
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include "hal_socket.h" #include "hal_socket.h"
@ -199,7 +184,7 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count)
} }
static bool 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));
@ -246,7 +231,7 @@ TcpServerSocket_create(const char* address, int port)
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) { if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
struct sockaddr_in serverAddress; struct sockaddr_in serverAddress;
if (!prepareServerAddress(address, port, &serverAddress)) { if (!prepareAddress(address, port, &serverAddress)) {
close(fd); close(fd);
return NULL; return NULL;
} }
@ -257,7 +242,7 @@ TcpServerSocket_create(const char* address, int port)
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) { if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket)); serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd; serverSocket->fd = fd;
serverSocket->backLog = 0; serverSocket->backLog = 2;
setSocketNonBlocking((Socket) serverSocket); setSocketNonBlocking((Socket) serverSocket);
} }
@ -345,7 +330,7 @@ ServerSocket_destroy(ServerSocket self)
Socket Socket
TcpSocket_create() TcpSocket_create()
{ {
Socket self = NULL; Socket self = (Socket)NULL;
int sock = socket(AF_INET, SOCK_STREAM, 0); int sock = socket(AF_INET, SOCK_STREAM, 0);
@ -368,7 +353,6 @@ TcpSocket_create()
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
printf("SOCKET: out of memory\n"); printf("SOCKET: out of memory\n");
} }
} }
else { else {
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
@ -385,15 +369,24 @@ Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs)
} }
bool 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; 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 false;
}
return true; return true;
} }

@ -1,34 +1,21 @@
/* /*
* socket_linux.c * socket_linux.c
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include "hal_socket.h" #include "hal_socket.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h>
#include <sys/select.h> #include <sys/select.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
@ -215,7 +202,7 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count)
} }
static bool 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; bool retVal = true;
@ -231,6 +218,10 @@ prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr
result = getaddrinfo(address, NULL, &addressHints, &lookupResult); result = getaddrinfo(address, NULL, &addressHints, &lookupResult);
if (result != 0) { if (result != 0) {
if (DEBUG_SOCKET)
printf("SOCKET: getaddrinfo failed (code=%i)\n", result);
retVal = false; retVal = false;
goto exit_function; 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_addr.s_addr = htonl(INADDR_ANY);
sockaddr->sin_family = AF_INET; sockaddr->sin_family = AF_INET;
if (port < 0)
port = 0;
sockaddr->sin_port = htons(port); sockaddr->sin_port = htons(port);
exit_function: exit_function:
@ -273,7 +268,7 @@ TcpServerSocket_create(const char* address, int port)
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) { if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
struct sockaddr_in serverAddress; struct sockaddr_in serverAddress;
if (!prepareServerAddress(address, port, &serverAddress)) { if (!prepareAddress(address, port, &serverAddress)) {
close(fd); close(fd);
return NULL; return NULL;
} }
@ -327,9 +322,19 @@ ServerSocket_accept(ServerSocket self)
if (fd >= 0) { if (fd >= 0) {
conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket)); 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; return conSocket;
@ -350,9 +355,19 @@ closeAndShutdownSocket(int socketFd)
printf("SOCKET: call shutdown for %i!\n", socketFd); printf("SOCKET: call shutdown for %i!\n", socketFd);
/* shutdown is required to unblock read or accept in another thread! */ /* 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 Socket
TcpSocket_create() TcpSocket_create()
{ {
Socket self = NULL; Socket self = (Socket)NULL;
int sock = socket(AF_INET, SOCK_STREAM, 0); int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) { if (sock != -1) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket)); self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
self->fd = sock; if (self) {
self->connectTimeout = 5000; self->fd = sock;
self->connectTimeout = 5000;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
int tcpUserTimeout = 10000; int tcpUserTimeout = 10000;
int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout)); int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
if (result < 0) { if (result == -1) {
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
printf("SOCKET: failed to set TCP_USER_TIMEOUT\n"); printf("SOCKET: failed to set TCP_USER_TIMEOUT (errno=%i)\n", errno);
} }
#endif #endif
}
else {
/* out of memory */
close(sock);
if (DEBUG_SOCKET)
printf("SOCKET: out of memory\n");
}
} }
else { else {
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
@ -402,13 +425,35 @@ TcpSocket_create()
return self; return self;
} }
void void
Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs) Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs)
{ {
self->connectTimeout = 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 bool
Socket_connectAsync(Socket self, const char* address, int port) 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) if (DEBUG_SOCKET)
printf("SOCKET: connect: %s:%i\n", address, port); printf("SOCKET: connect: %s:%i\n", address, port);
if (!prepareServerAddress(address, port, &serverAddress)) if (!prepareAddress(address, port, &serverAddress))
return false; return false;
fd_set fdSet; fd_set fdSet;
@ -627,6 +672,8 @@ Socket_read(Socket self, uint8_t* buf, int size)
case EAGAIN: case EAGAIN:
return 0; return 0;
case EBADF:
return -1;
default: default:
@ -647,7 +694,7 @@ Socket_write(Socket self, uint8_t* buf, int size)
return -1; return -1;
/* MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket */ /* 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 (retVal == -1) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
@ -701,7 +748,7 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
{ {
struct sockaddr_in localAddress; struct sockaddr_in localAddress;
if (!prepareServerAddress(address, port, &localAddress)) { if (!prepareAddress(address, port, &localAddress)) {
close(self->fd); close(self->fd);
self->fd = 0; self->fd = 0;
return false; return false;
@ -727,7 +774,7 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
{ {
struct sockaddr_in remoteAddress; struct sockaddr_in remoteAddress;
if (!prepareServerAddress(address, port, &remoteAddress)) { if (!prepareAddress(address, port, &remoteAddress)) {
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address); printf("SOCKET: failed to lookup remote address %s\n", address);

@ -1,26 +1,14 @@
/* /*
* socket_win32.c * socket_win32.c
* *
* Copyright 2013-2020 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <windows.h> #include <windows.h>
@ -65,13 +53,14 @@ struct sUdpSocket {
HandleSet HandleSet
Handleset_new(void) Handleset_new(void)
{ {
HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet)); HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
if (result != NULL) { if (result != NULL) {
FD_ZERO(&result->handles); FD_ZERO(&result->handles);
result->maxHandle = INVALID_SOCKET; result->maxHandle = INVALID_SOCKET;
} }
return result;
return result;
} }
void void
@ -97,37 +86,40 @@ void
Handleset_removeSocket(HandleSet self, const Socket sock) Handleset_removeSocket(HandleSet self, const Socket sock)
{ {
if (self != NULL && sock != NULL && sock->fd != INVALID_SOCKET) { 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 int
Handleset_waitReady(HandleSet self, unsigned int timeoutMs) Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
{ {
int result; int result;
if ((self != NULL) && (self->maxHandle != INVALID_SOCKET)) { if ((self != NULL) && (self->maxHandle != INVALID_SOCKET)) {
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = timeoutMs / 1000; timeout.tv_sec = timeoutMs / 1000;
timeout.tv_usec = (timeoutMs % 1000) * 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); result = select(self->maxHandle + 1, &handles, NULL, NULL, &timeout);
} else { } else {
result = -1; result = -1;
} }
return result; return result;
} }
void void
Handleset_destroy(HandleSet self) Handleset_destroy(HandleSet self)
{ {
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
} }
static bool wsaStartupCalled = false; static bool wsaStartupCalled = false;
@ -172,18 +164,18 @@ setSocketNonBlocking(Socket self)
} }
static bool 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) { if (address != NULL) {
struct hostent *server; struct hostent *server;
server = gethostbyname(address); 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 else
sockaddr->sin_addr.s_addr = htonl(INADDR_ANY); sockaddr->sin_addr.s_addr = htonl(INADDR_ANY);
@ -240,7 +232,7 @@ TcpServerSocket_create(const char* address, int port)
struct sockaddr_in server_addr; struct sockaddr_in server_addr;
if (!prepareServerAddress(address, port, &server_addr)) if (!prepareAddress(address, port, &server_addr))
return NULL; return NULL;
listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
@ -269,14 +261,20 @@ TcpServerSocket_create(const char* address, int port)
return NULL; return NULL;
} }
serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket)); serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = listen_socket; if (serverSocket) {
serverSocket->backLog = 10; serverSocket->fd = listen_socket;
serverSocket->backLog = 10;
setSocketNonBlocking((Socket) serverSocket); setSocketNonBlocking((Socket)serverSocket);
socketCount++; socketCount++;
}
else {
closesocket(listen_socket);
wsaShutdown();
}
return serverSocket; return serverSocket;
} }
@ -346,14 +344,24 @@ TcpSocket_create()
if (sock != INVALID_SOCKET) { if (sock != INVALID_SOCKET) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket)); self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
self->fd = sock; if (self) {
self->connectTimeout = 5000; 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 { else {
if (DEBUG_SOCKET) 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; return self;
@ -365,6 +373,29 @@ Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs)
self->connectTimeout = 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 bool
Socket_connectAsync(Socket self, const char* address, int port) Socket_connectAsync(Socket self, const char* address, int port)
{ {
@ -381,7 +412,7 @@ Socket_connectAsync(Socket self, const char* address, int port)
return false; return false;
} }
if (!prepareServerAddress(address, port, &serverAddress)) if (!prepareAddress(address, port, &serverAddress))
return false; return false;
setSocketNonBlocking(self); setSocketNonBlocking(self);
@ -438,7 +469,7 @@ Socket_connect(Socket self, const char* address, int port)
{ {
struct sockaddr_in serverAddress; struct sockaddr_in serverAddress;
if (!prepareServerAddress(address, port, &serverAddress)) if (!prepareAddress(address, port, &serverAddress))
return false; return false;
setSocketNonBlocking(self); setSocketNonBlocking(self);
@ -456,7 +487,7 @@ Socket_connect(Socket self, const char* address, int port)
timeout.tv_sec = self->connectTimeout / 1000; timeout.tv_sec = self->connectTimeout / 1000;
timeout.tv_usec = (self->connectTimeout % 1000) * 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; return false;
else else
return true; return true;
@ -647,7 +678,7 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
{ {
struct sockaddr_in localAddress; struct sockaddr_in localAddress;
if (!prepareServerAddress(address, port, &localAddress)) { if (!prepareAddress(address, port, &localAddress)) {
closesocket(self->fd); closesocket(self->fd);
self->fd = 0; self->fd = 0;
return false; return false;
@ -673,7 +704,7 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
{ {
struct sockaddr_in remoteAddress; struct sockaddr_in remoteAddress;
if (!prepareServerAddress(address, port, &remoteAddress)) { if (!prepareAddress(address, port, &remoteAddress)) {
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address); printf("SOCKET: failed to lookup remote address %s\n", address);

@ -1,39 +1,24 @@
/** /**
* thread_bsd.c * thread_bsd.c
* *
* Copyright 2016 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include <unistd.h> #include <unistd.h>
#include "hal_thread.h" #include "hal_thread.h"
#include "lib_memory.h" #include "lib_memory.h"
struct sThread { struct sThread {
ThreadExecutionFunction function; ThreadExecutionFunction function;
void* parameter; void* parameter;
pthread_t pthread; pthread_t pthread;
int state; int state;
bool autodestroy; bool autodestroy;
}; };
Semaphore Semaphore
@ -62,7 +47,8 @@ Semaphore_post(Semaphore self)
void void
Semaphore_destroy(Semaphore self) Semaphore_destroy(Semaphore self)
{ {
sem_close(self); sem_destroy((sem_t*) self);
GLOBAL_FREEMEM(self);
} }
Thread Thread
@ -85,38 +71,39 @@ destroyAutomaticThread(void* parameter)
{ {
Thread thread = (Thread) 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 void
Thread_start(Thread thread) Thread_start(Thread thread)
{ {
if (thread->autodestroy == true) { if (thread->autodestroy == true) {
pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread);
pthread_detach(thread->pthread); pthread_detach(thread->pthread);
} }
else else
pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); pthread_create(&thread->pthread, NULL, thread->function, thread->parameter);
thread->state = 1; thread->state = 1;
} }
void void
Thread_destroy(Thread thread) Thread_destroy(Thread thread)
{ {
if (thread->state == 1) { if (thread->state == 1) {
pthread_join(thread->pthread, NULL); pthread_join(thread->pthread, NULL);
} }
GLOBAL_FREEMEM(thread); GLOBAL_FREEMEM(thread);
} }
void void
Thread_sleep(int millies) Thread_sleep(int millies)
{ {
usleep(millies * 1000); usleep(millies * 1000);
} }

@ -1,40 +1,24 @@
/* /*
* thread_linux.c * thread_linux.c
* *
* Copyright 2013 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include <unistd.h> #include <unistd.h>
#include "hal_thread.h" #include "hal_thread.h"
#include "lib_memory.h" #include "lib_memory.h"
struct sThread { struct sThread {
ThreadExecutionFunction function; ThreadExecutionFunction function;
void* parameter; void* parameter;
pthread_t pthread; pthread_t pthread;
int state; int state;
bool autodestroy; bool autodestroy;
}; };
Semaphore Semaphore
@ -70,16 +54,16 @@ Semaphore_destroy(Semaphore self)
Thread Thread
Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy) 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->parameter = parameter;
thread->function = function; thread->function = function;
thread->state = 0; thread->state = 0;
thread->autodestroy = autodestroy; thread->autodestroy = autodestroy;
} }
return thread; return thread;
} }
static void* static void*
@ -87,39 +71,39 @@ destroyAutomaticThread(void* parameter)
{ {
Thread thread = (Thread) 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 void
Thread_start(Thread thread) Thread_start(Thread thread)
{ {
if (thread->autodestroy == true) { if (thread->autodestroy == true) {
pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread); pthread_create(&thread->pthread, NULL, destroyAutomaticThread, thread);
pthread_detach(thread->pthread); pthread_detach(thread->pthread);
} }
else else
pthread_create(&thread->pthread, NULL, thread->function, thread->parameter); pthread_create(&thread->pthread, NULL, thread->function, thread->parameter);
thread->state = 1; thread->state = 1;
} }
void void
Thread_destroy(Thread thread) Thread_destroy(Thread thread)
{ {
if (thread->state == 1) { if (thread->state == 1) {
pthread_join(thread->pthread, NULL); pthread_join(thread->pthread, NULL);
} }
GLOBAL_FREEMEM(thread); GLOBAL_FREEMEM(thread);
} }
void void
Thread_sleep(int millies) Thread_sleep(int millies)
{ {
usleep(millies * 1000); usleep(millies * 1000);
} }

@ -1,7 +1,7 @@
/** /**
* thread_macos.c * thread_macos.c
* *
* Copyright 2013-2019 MZ Automation GmbH * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of Platform Abstraction Layer (libpal) * This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870. * for libiec61850, libmms, and lib60870.

@ -1,24 +1,10 @@
/* /*
* thread_win32.c * thread_win32.c
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include <windows.h> #include <windows.h>

@ -3,26 +3,11 @@
* *
* Copyright 2013-2021 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include "hal_time.h" #include "hal_time.h"
#include <time.h> #include <time.h>
#ifdef CONFIG_SYSTEM_HAS_CLOCK_GETTIME #ifdef CONFIG_SYSTEM_HAS_CLOCK_GETTIME

@ -1,61 +1,45 @@
/* /*
* time.c * time.c
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of Platform Abstraction Layer (libpal)
* * for libiec61850, libmms, and lib60870.
* 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 <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/ */
#include "hal_time.h" #include "hal_time.h"
#include <time.h> #include <time.h>
#include <windows.h> #include <windows.h>
uint64_t uint64_t
Hal_getTimeInMs() Hal_getTimeInMs()
{ {
FILETIME ft; FILETIME ft;
uint64_t now; 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 nsSinceEpoch
Hal_getTimeInNs() 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 bool
@ -65,8 +49,8 @@ Hal_setTimeInNs(nsSinceEpoch nsTime)
FILETIME ft; FILETIME ft;
ft.dwLowDateTime = (uint32_t)(t & 0xffffffff); ft.dwLowDateTime = (uint32_t)(t & 0xffffffff);
ft.dwHighDateTime = (uint32_t)(t >> 32); ft.dwHighDateTime = (uint32_t)(t >> 32);
SYSTEMTIME st; SYSTEMTIME st;

@ -40,6 +40,7 @@
#define MBEDTLS_SSL_SRV_C #define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C #define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C #define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_CRL_PARSE_C
#define MBEDTLS_X509_USE_C #define MBEDTLS_X509_USE_C
#define MBEDTLS_SSL_CACHE_C #define MBEDTLS_SSL_CACHE_C

@ -3,7 +3,7 @@
* *
* TLS API for TCP/IP protocol stacks * 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 * Implementation of the TLS abstraction layer for mbedtls
* *
@ -14,6 +14,7 @@
#include "tls_socket.h" #include "tls_socket.h"
#include "hal_thread.h" #include "hal_thread.h"
#include "lib_memory.h" #include "lib_memory.h"
#include "hal_time.h"
#include "linked_list.h" #include "linked_list.h"
#include "mbedtls/platform.h" #include "mbedtls/platform.h"
@ -27,9 +28,7 @@
#include "mbedtls/debug.h" #include "mbedtls/debug.h"
#if (CONFIG_DEBUG_TLS == 1) #if (CONFIG_DEBUG_TLS == 1)
#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, \ #define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__);
appId, \
__VA_ARGS__)
#else #else
#define DEBUG_PRINT(fmt, ...) {do {} while(0);} #define DEBUG_PRINT(fmt, ...) {do {} while(0);}
#endif #endif
@ -44,15 +43,23 @@ struct sTLSConfiguration {
mbedtls_x509_crt cacerts; mbedtls_x509_crt cacerts;
mbedtls_x509_crl crl;
mbedtls_ssl_config conf; mbedtls_ssl_config conf;
LinkedList /* <mbedtls_x509_crt*> */ allowedCertificates; LinkedList /* <mbedtls_x509_crt*> */ allowedCertificates;
bool chainValidation; bool chainValidation;
bool allowOnlyKnownCertificates; bool allowOnlyKnownCertificates;
/* TLS session renegotioation time in milliseconds */ /* TLS session renegotiation interval in milliseconds */
int renegotiationTimeInMs; 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; bool setupComplete;
}; };
@ -64,6 +71,9 @@ struct sTLSSocket {
bool storePeerCert; bool storePeerCert;
uint8_t* peerCert; uint8_t* peerCert;
int peerCertLength; int peerCertLength;
/* time of last session renegotiation (used to calculate next renegotiation time) */
uint64_t lastRenegotiationTime;
}; };
static bool static bool
@ -147,7 +157,27 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
return 0; 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
TLSConfiguration_create() TLSConfiguration_create()
@ -157,7 +187,8 @@ TLSConfiguration_create()
if (self != NULL) { if (self != NULL) {
mbedtls_ssl_config_init( &(self->conf) ); mbedtls_ssl_config_init( &(self->conf) );
mbedtls_x509_crt_init( &(self->ownCertificate) ); 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_pk_init( &(self->ownKey) );
mbedtls_entropy_init( &(self->entropy) ); mbedtls_entropy_init( &(self->entropy) );
mbedtls_ctr_drbg_init( &(self->ctr_drbg) ); 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_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}; */ /* static int hashes[] = {3,4,5,6,7,8,0}; */
/* mbedtls_ssl_conf_sig_hashes(&(self->conf), hashes); */ /* 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(); self->allowedCertificates = LinkedList_create();
/* default behavior is to allow all certificates that are signed by the CA */ /* 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; 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 void
TLSConfiguration_setChainValidation(TLSConfiguration self, bool value) 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); int ret = mbedtls_x509_crt_parse(&(self->ownCertificate), certificate, certLen);
if (ret != 0) 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); return (ret == 0);
} }
@ -309,6 +357,29 @@ TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* fil
return (ret == 0); 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 void
TLSConfiguration_setRenegotiationTime(TLSConfiguration self, int timeInMs) 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->ownCertificate));
mbedtls_x509_crt_free(&(self->cacerts)); mbedtls_x509_crt_free(&(self->cacerts));
mbedtls_x509_crl_free(&(self->crl));
mbedtls_pk_free(&(self->ownKey)); mbedtls_pk_free(&(self->ownKey));
mbedtls_ssl_config_free(&(self->conf)); mbedtls_ssl_config_free(&(self->conf));
@ -351,26 +423,42 @@ readFunction(void* ctx, unsigned char* buf, size_t len)
return ret; return ret;
} }
/* static int
* Finish configuration when used the first time. getMajorVersion(TLSConfigVersion version)
*/
static bool
TLSConfiguration_setupComplete(TLSConfiguration self)
{ {
if (self->setupComplete == false) { switch(version) {
mbedtls_ssl_conf_ca_chain( &(self->conf), &(self->cacerts), NULL ); case TLS_VERSION_NOT_SELECTED:
return 0;
int ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(self->ownCertificate), &(self->ownKey)); case TLS_VERSION_SSL_3_0:
case TLS_VERSION_TLS_1_0:
if (ret != 0) { case TLS_VERSION_TLS_1_1:
DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); case TLS_VERSION_TLS_1_2:
return false; case TLS_VERSION_TLS_1_3:
} return 3;
default:
self->setupComplete = true; 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 TLSSocket
@ -392,7 +480,34 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*) self); 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) if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret); 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 ) 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)); mbedtls_ssl_free(&(self->ssl));
if (self->peerCert) {
GLOBAL_FREEMEM(self->peerCert);
}
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
return NULL; 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; return self;
@ -439,6 +563,19 @@ TLSSocket_performHandshake(TLSSocket self)
int int
TLSSocket_read(TLSSocket self, uint8_t* buf, int size) 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); int ret = mbedtls_ssl_read(&(self->ssl), buf, size);
if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE)) if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE))

Loading…
Cancel
Save