- merged HAL code from lib60870 (release/2.3.3)

v1.6
Michael Zillgith 8 months ago
parent 221a1f8615
commit 899a2bbe2e

@ -1,7 +1,7 @@
/*
* socket_hal.h
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.

@ -1,7 +1,7 @@
/*
* time.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
@ -68,6 +68,22 @@ Hal_getTimeInNs(void);
PAL_API bool
Hal_setTimeInNs(nsSinceEpoch nsTime);
/**
* Get the monotonic time or system tick time in ms
*
* \return the system time with millisecond resolution.
*/
PAL_API msSinceEpoch
Hal_getMonotonicTimeInMs(void);
/**
* Get the monotonic time or system tick in nanoseconds.
*
* \return the system time with nanosecond resolution.
*/
PAL_API nsSinceEpoch
Hal_getMonotonicTimeInNs(void);
/*! @} */
/*! @} */

@ -65,3 +65,4 @@ Memory_free(void* memb)
{
free(memb);
}

@ -1,33 +1,33 @@
/*
* socket_bsd.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
*/
#include "hal_socket.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/tcp.h> // required for TCP keepalive
#include <signal.h>
#include <poll.h>
#include <signal.h>
#include "linked_list.h"
#include "hal_thread.h"
#include "lib_memory.h"
#include "linked_list.h"
#ifndef DEBUG_SOCKET
#define DEBUG_SOCKET 0
@ -41,22 +41,26 @@
#define MSG_NOSIGNAL 0
#endif
struct sSocket {
struct sSocket
{
int fd;
uint32_t connectTimeout;
};
struct sServerSocket {
struct sServerSocket
{
int fd;
int backLog;
};
struct sUdpSocket {
struct sUdpSocket
{
int fd;
int namespace; /* IPv4: AF_INET; IPv6: AF_INET6 */
};
struct sHandleSet {
struct sHandleSet
{
LinkedList sockets;
bool pollfdIsUpdated;
struct pollfd* fds;
@ -66,9 +70,10 @@ struct sHandleSet {
HandleSet
Handleset_new(void)
{
HandleSet self = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
HandleSet self = (HandleSet)GLOBAL_MALLOC(sizeof(struct sHandleSet));
if (self) {
if (self)
{
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
self->fds = NULL;
@ -81,8 +86,10 @@ Handleset_new(void)
void
Handleset_reset(HandleSet self)
{
if (self) {
if (self->sockets) {
if (self)
{
if (self->sockets)
{
LinkedList_destroyStatic(self->sockets);
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
@ -93,7 +100,8 @@ Handleset_reset(HandleSet self)
void
Handleset_addSocket(HandleSet self, const Socket sock)
{
if (self != NULL && sock != NULL && sock->fd != -1) {
if (self != NULL && sock != NULL && sock->fd != -1)
{
LinkedList_add(self->sockets, sock);
self->pollfdIsUpdated = false;
}
@ -102,7 +110,8 @@ Handleset_addSocket(HandleSet self, const Socket sock)
void
Handleset_removeSocket(HandleSet self, const Socket sock)
{
if (self && self->sockets && sock) {
if (self && self->sockets && sock)
{
LinkedList_remove(self->sockets, sock);
self->pollfdIsUpdated = false;
}
@ -112,8 +121,10 @@ int
Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
{
/* check if pollfd array is updated */
if (self->pollfdIsUpdated == false) {
if (self->fds) {
if (self->pollfdIsUpdated == false)
{
if (self->fds)
{
GLOBAL_FREEMEM(self->fds);
self->fds = NULL;
}
@ -124,13 +135,16 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
int i;
for (i = 0; i < self->nfds; i++) {
for (i = 0; i < self->nfds; i++)
{
LinkedList sockElem = LinkedList_get(self->sockets, i);
if (sockElem) {
Socket sock = (Socket) LinkedList_getData(sockElem);
if (sockElem)
{
Socket sock = (Socket)LinkedList_getData(sockElem);
if (sock) {
if (sock)
{
self->fds[i].fd = sock->fd;
self->fds[i].events = POLL_IN;
}
@ -140,17 +154,20 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
self->pollfdIsUpdated = true;
}
if (self->fds && self->nfds > 0) {
if (self->fds && self->nfds > 0)
{
int result = poll(self->fds, self->nfds, timeoutMs);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: poll error (errno: %i)\n", errno);
}
return result;
}
else {
else
{
/* there is no socket to wait for */
return 0;
}
@ -159,7 +176,8 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
void
Handleset_destroy(HandleSet self)
{
if (self) {
if (self)
{
if (self->sockets)
LinkedList_destroyStatic(self->sockets);
@ -197,18 +215,20 @@ static bool
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 (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);
}
else
sockaddr->sin_addr.s_addr = htonl(INADDR_ANY);
memcpy((char*)&sockaddr->sin_addr.s_addr, (char*)server->h_addr, server->h_length);
}
else
sockaddr->sin_addr.s_addr = htonl(INADDR_ANY);
sockaddr->sin_family = AF_INET;
sockaddr->sin_port = htons(port);
@ -228,7 +248,7 @@ activateTcpNoDelay(Socket self)
{
/* activate TCP_NODELAY option - packets will be sent immediately */
int flag = 1;
setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
}
ServerSocket
@ -238,27 +258,31 @@ TcpServerSocket_create(const char* address, int port)
int fd;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
{
struct sockaddr_in serverAddress;
if (!prepareAddress(address, port, &serverAddress)) {
if (!prepareAddress(address, port, &serverAddress))
{
close(fd);
return NULL;
}
int optionReuseAddr = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optionReuseAddr, sizeof(int));
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket));
if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) >= 0)
{
serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd;
serverSocket->backLog = 2;
setSocketNonBlocking((Socket) serverSocket);
setSocketNonBlocking((Socket)serverSocket);
}
else {
else
{
close(fd);
return NULL ;
return NULL;
}
}
@ -271,7 +295,6 @@ ServerSocket_listen(ServerSocket self)
listen(self->fd, self->backLog);
}
/* CHANGED TO MAKE NON-BLOCKING --> RETURNS NULL IF NO CONNECTION IS PENDING */
Socket
ServerSocket_accept(ServerSocket self)
@ -280,19 +303,22 @@ ServerSocket_accept(ServerSocket self)
Socket conSocket = NULL;
fd = accept(self->fd, NULL, NULL );
fd = accept(self->fd, NULL, NULL);
if (fd >= 0) {
conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (fd >= 0)
{
conSocket = (Socket)GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (conSocket) {
if (conSocket)
{
conSocket->fd = fd;
setSocketNonBlocking(conSocket);
activateTcpNoDelay(conSocket);
}
else {
else
{
/* out of memory */
close(fd);
@ -313,7 +339,8 @@ ServerSocket_setBacklog(ServerSocket self, int backlog)
static void
closeAndShutdownSocket(int socketFd)
{
if (socketFd != -1) {
if (socketFd != -1)
{
if (DEBUG_SOCKET)
printf("socket_linux.c: call shutdown for %i!\n", socketFd);
@ -346,10 +373,12 @@ TcpSocket_create()
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (Socket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->connectTimeout = 5000;
@ -358,7 +387,8 @@ TcpSocket_create()
int result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
#endif
}
else {
else
{
/* out of memory */
close(sock);
@ -366,7 +396,8 @@ TcpSocket_create()
printf("SOCKET: out of memory\n");
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create socket (errno=%i)\n", errno);
}
@ -390,7 +421,8 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind TCP socket (errno=%i)\n", errno);
@ -398,7 +430,7 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
self->fd = -1;
return false;
}
}
return true;
}
@ -422,9 +454,11 @@ Socket_connectAsync(Socket self, const char* address, int port)
fcntl(self->fd, F_SETFL, O_NONBLOCK);
if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
if (connect(self->fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0)
{
if (errno != EINPROGRESS) {
if (errno != EINPROGRESS)
{
self->fd = -1;
return false;
}
@ -444,16 +478,18 @@ Socket_checkAsyncConnectState(Socket self)
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
int selectVal = select(self->fd + 1, NULL, &fdSet , NULL, &timeout);
int selectVal = select(self->fd + 1, NULL, &fdSet, NULL, &timeout);
if (selectVal == 1) {
if (selectVal == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return SOCKET_STATE_CONNECTED;
@ -461,10 +497,12 @@ Socket_checkAsyncConnectState(Socket self)
return SOCKET_STATE_FAILED;
}
else if (selectVal == 0) {
else if (selectVal == 0)
{
return SOCKET_STATE_CONNECTING;
}
else {
else
{
return SOCKET_STATE_FAILED;
}
}
@ -483,21 +521,23 @@ Socket_connect(Socket self, const char* address, int port)
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
if (select(self->fd + 1, NULL, &fdSet , NULL, &timeout) == 1) {
if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return true;
}
}
close (self->fd);
close(self->fd);
self->fd = -1;
return false;
@ -511,22 +551,24 @@ convertAddressToStr(struct sockaddr_storage* addr)
bool isIPv6;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) addr;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) addr;
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9);
char* clientConnection = (char*)GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
sprintf(clientConnection, "[%s]:%i", addrString, port);
@ -542,7 +584,8 @@ Socket_getPeerAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getpeername(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -555,7 +598,8 @@ Socket_getLocalAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getsockname(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getsockname(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -568,27 +612,29 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
getpeername(self->fd, (struct sockaddr*) &addr, &addrLen);
getpeername(self->fd, (struct sockaddr*)&addr, &addrLen);
char addrString[INET6_ADDRSTRLEN + 7];
int port;
bool isIPv6;
if (addr.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr;
if (addr.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr;
else if (addr.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
if (isIPv6)
sprintf(peerAddressString, "[%s]:%i", addrString, port);
@ -609,18 +655,20 @@ Socket_read(Socket self, uint8_t* buf, int size)
if (read_bytes == 0)
return -1;
if (read_bytes == -1) {
if (read_bytes == -1)
{
int error = errno;
switch (error) {
switch (error)
{
case EAGAIN:
return 0;
case EBADF:
return -1;
case EAGAIN:
return 0;
case EBADF:
return -1;
default:
return -1;
default:
return -1;
}
}
@ -663,21 +711,25 @@ UdpSocket_createUsingNamespace(int namespace)
int sock = socket(namespace, SOCK_DGRAM, IPPROTO_UDP);
if (sock != -1) {
self = (UdpSocket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (UdpSocket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->namespace = namespace;
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to allocate memory\n");
close(sock);
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create UDP socket (errno=%i)\n", errno);
}
@ -700,36 +752,42 @@ UdpSocket_createIpV6()
bool
UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
{
if (self->namespace == AF_INET) {
if (self->namespace == AF_INET)
{
struct ip_mreq mreq;
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr))) {
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr)))
{
printf("SOCKET: Invalid IPv4 multicast address\n");
return false;
}
else {
else
{
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", errno);
return false;
}
}
return true;
}
else if (self->namespace == AF_INET6) {
else if (self->namespace == AF_INET6)
{
struct ipv6_mreq mreq;
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1) {
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
mreq.ipv6mr_interface = 0;
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
@ -743,16 +801,20 @@ UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
bool
UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
{
if (self->namespace == AF_INET) {
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
if (self->namespace == AF_INET)
{
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", errno);
return false;
}
return true;
}
else if (self->namespace == AF_INET6) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
else if (self->namespace == AF_INET6)
{
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", errno);
return false;
}
@ -766,10 +828,11 @@ UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
bool
UdpSocket_bind(UdpSocket self, const char* address, int port)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in localAddress;
if (!prepareAddress(address, port, &localAddress)) {
if (!prepareAddress(address, port, &localAddress))
{
close(self->fd);
self->fd = 0;
return false;
@ -777,7 +840,8 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind UDP socket (errno=%i)\n", errno);
@ -793,10 +857,11 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
bool
UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in remoteAddress;
if (!prepareAddress(address, port, &remoteAddress)) {
if (!prepareAddress(address, port, &remoteAddress))
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address);
@ -806,14 +871,17 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int result = sendto(self->fd, msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress));
if (result == msgSize) {
if (result == msgSize)
{
return true;
}
else if (result == -1) {
else if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (errno=%i)\n", errno);
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (insufficient data sent)\n");
}
@ -824,31 +892,35 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int
UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_storage remoteAddress;
socklen_t structSize = sizeof(struct sockaddr_storage);
int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno);
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
@ -862,19 +934,22 @@ UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* m
snprintf(address, maxAddrSize, "%s:%i", addrString, port);
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;

@ -8,49 +8,52 @@
*/
#include "hal_socket.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <netinet/tcp.h> /* required for TCP keepalive */
#include <linux/version.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h> /* required for TCP keepalive */
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <signal.h>
#include <poll.h>
#include <signal.h>
#include "linked_list.h"
#include "hal_thread.h"
#include "lib_memory.h"
#include "linked_list.h"
#ifndef DEBUG_SOCKET
#define DEBUG_SOCKET 0
#endif
struct sSocket {
struct sSocket
{
int fd;
uint32_t connectTimeout;
};
struct sServerSocket {
struct sServerSocket
{
int fd;
int backLog;
};
struct sUdpSocket {
struct sUdpSocket
{
int fd;
int namespace; /* IPv4: AF_INET; IPv6: AF_INET6 */
};
struct sHandleSet {
struct sHandleSet
{
LinkedList sockets;
bool pollfdIsUpdated;
struct pollfd* fds;
@ -60,23 +63,26 @@ struct sHandleSet {
HandleSet
Handleset_new(void)
{
HandleSet self = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
HandleSet self = (HandleSet)GLOBAL_MALLOC(sizeof(struct sHandleSet));
if (self) {
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
self->fds = NULL;
self->nfds = 0;
}
if (self)
{
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
self->fds = NULL;
self->nfds = 0;
}
return self;
return self;
}
void
Handleset_reset(HandleSet self)
{
if (self) {
if (self->sockets) {
if (self)
{
if (self->sockets)
{
LinkedList_destroyStatic(self->sockets);
self->sockets = LinkedList_create();
self->pollfdIsUpdated = false;
@ -87,17 +93,19 @@ Handleset_reset(HandleSet self)
void
Handleset_addSocket(HandleSet self, const Socket sock)
{
if (self != NULL && sock != NULL && sock->fd != -1) {
if (self != NULL && sock != NULL && sock->fd != -1)
{
LinkedList_add(self->sockets, sock);
self->pollfdIsUpdated = false;
}
LinkedList_add(self->sockets, sock);
self->pollfdIsUpdated = false;
}
}
void
Handleset_removeSocket(HandleSet self, const Socket sock)
{
if (self && self->sockets && sock) {
if (self && self->sockets && sock)
{
LinkedList_remove(self->sockets, sock);
self->pollfdIsUpdated = false;
}
@ -107,8 +115,10 @@ int
Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
{
/* check if pollfd array is updated */
if (self->pollfdIsUpdated == false) {
if (self->fds) {
if (self->pollfdIsUpdated == false)
{
if (self->fds)
{
GLOBAL_FREEMEM(self->fds);
self->fds = NULL;
}
@ -119,13 +129,16 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
int i;
for (i = 0; i < self->nfds; i++) {
for (i = 0; i < self->nfds; i++)
{
LinkedList sockElem = LinkedList_get(self->sockets, i);
if (sockElem) {
Socket sock = (Socket) LinkedList_getData(sockElem);
if (sockElem)
{
Socket sock = (Socket)LinkedList_getData(sockElem);
if (sock) {
if (sock)
{
self->fds[i].fd = sock->fd;
self->fds[i].events = POLL_IN;
}
@ -135,21 +148,25 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
self->pollfdIsUpdated = true;
}
if (self->fds && self->nfds > 0) {
if (self->fds && self->nfds > 0)
{
int result = poll(self->fds, self->nfds, timeoutMs);
if (result == -1 && errno == EINTR) {
if (result == -1 && errno == EINTR)
{
result = 0;
}
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: poll error (errno: %i)\n", errno);
}
return result;
}
else {
else
{
/* there is no socket to wait for */
return 0;
}
@ -158,7 +175,8 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
void
Handleset_destroy(HandleSet self)
{
if (self) {
if (self)
{
if (self->sockets)
LinkedList_destroyStatic(self->sockets);
@ -178,26 +196,30 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count)
optval = 1;
if (setsockopt(self->fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen)) {
if (setsockopt(self->fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to enable TCP keepalive\n");
}
#if defined TCP_KEEPCNT
optval = idleTime;
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen)) {
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to set TCP keepalive TCP_KEEPIDLE parameter\n");
}
optval = interval;
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen)) {
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to set TCP keepalive TCP_KEEPINTVL parameter\n");
}
optval = count;
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen)) {
if (setsockopt(self->fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen))
{
if (DEBUG_SOCKET)
printf("SOCKET: Failed to set TCP keepalive TCP_KEEPCNT parameter\n");
}
@ -211,18 +233,20 @@ prepareAddress(const char* address, int port, struct sockaddr_in* sockaddr)
{
bool retVal = true;
memset((char *) sockaddr, 0, sizeof(struct sockaddr_in));
memset((char*)sockaddr, 0, sizeof(struct sockaddr_in));
if (address != NULL) {
if (address != NULL)
{
struct addrinfo addressHints;
struct addrinfo *lookupResult;
struct addrinfo* lookupResult;
int result;
memset(&addressHints, 0, sizeof(struct addrinfo));
addressHints.ai_family = AF_INET;
result = getaddrinfo(address, NULL, &addressHints, &lookupResult);
if (result != 0) {
if (result != 0)
{
if (DEBUG_SOCKET)
printf("SOCKET: getaddrinfo failed (code=%i)\n", result);
@ -260,7 +284,7 @@ activateTcpNoDelay(Socket self)
{
/* activate TCP_NODELAY option - packets will be sent immediately */
int flag = 1;
setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
}
ServerSocket
@ -270,22 +294,25 @@ TcpServerSocket_create(const char* address, int port)
int fd;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
{
struct sockaddr_in serverAddress;
if (!prepareAddress(address, port, &serverAddress)) {
if (!prepareAddress(address, port, &serverAddress))
{
close(fd);
return NULL;
}
int optionReuseAddr = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optionReuseAddr, sizeof(int));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
int tcpUserTimeout = 10000;
int result = setsockopt(fd, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
int result = setsockopt(fd, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
if (result < 0) {
if (result < 0)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to set TCP_USER_TIMEOUT\n");
}
@ -293,16 +320,18 @@ TcpServerSocket_create(const char* address, int port)
#warning "TCP_USER_TIMEOUT not supported by linux kernel"
#endif
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket));
if (bind(fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) >= 0)
{
serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd;
serverSocket->backLog = 2;
setSocketNonBlocking((Socket) serverSocket);
setSocketNonBlocking((Socket)serverSocket);
}
else {
else
{
close(fd);
return NULL ;
return NULL;
}
}
@ -312,7 +341,8 @@ TcpServerSocket_create(const char* address, int port)
void
ServerSocket_listen(ServerSocket self)
{
if (listen(self->fd, self->backLog) == -1) {
if (listen(self->fd, self->backLog) == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: listen failed (errno: %i)\n", errno);
}
@ -326,19 +356,22 @@ ServerSocket_accept(ServerSocket self)
Socket conSocket = NULL;
fd = accept(self->fd, NULL, NULL );
fd = accept(self->fd, NULL, NULL);
if (fd >= 0) {
conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (fd >= 0)
{
conSocket = (Socket)GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (conSocket) {
if (conSocket)
{
conSocket->fd = fd;
setSocketNonBlocking(conSocket);
activateTcpNoDelay(conSocket);
}
else {
else
{
/* out of memory */
close(fd);
@ -346,7 +379,8 @@ ServerSocket_accept(ServerSocket self)
printf("SOCKET: out of memory\n");
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: accept failed (errno=%i)\n", errno);
}
@ -363,7 +397,8 @@ ServerSocket_setBacklog(ServerSocket self, int backlog)
static void
closeAndShutdownSocket(int socketFd)
{
if (socketFd != -1) {
if (socketFd != -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: call shutdown for %i!\n", socketFd);
@ -371,14 +406,16 @@ closeAndShutdownSocket(int socketFd)
/* shutdown is required to unblock read or accept in another thread! */
int result = shutdown(socketFd, SHUT_RDWR);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: shutdown error: %i\n", errno);
}
result = close(socketFd);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: close error: %i\n", errno);
}
@ -406,24 +443,28 @@ TcpSocket_create()
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != -1) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (Socket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
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 result = setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &tcpUserTimeout, sizeof(tcpUserTimeout));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to set TCP_USER_TIMEOUT (errno=%i)\n", errno);
}
#endif
}
else {
else
{
/* out of memory */
close(sock);
@ -431,7 +472,8 @@ TcpSocket_create()
printf("SOCKET: out of memory\n");
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create socket (errno=%i)\n", errno);
}
@ -455,7 +497,8 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind TCP socket (errno=%i)\n", errno);
@ -463,7 +506,7 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
self->fd = -1;
return false;
}
}
return true;
}
@ -483,10 +526,13 @@ Socket_connectAsync(Socket self, const char* address, int port)
fcntl(self->fd, F_SETFL, O_NONBLOCK);
if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
if (connect(self->fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0)
{
if (errno != EINPROGRESS) {
if (close(self->fd) == -1) {
if (errno != EINPROGRESS)
{
if (close(self->fd) == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to close socket (errno: %i)\n", errno);
}
@ -509,14 +555,16 @@ Socket_checkAsyncConnectState(Socket self)
int result = poll(fds, 1, 0);
if (result == 1) {
if (result == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return SOCKET_STATE_CONNECTED;
@ -524,10 +572,12 @@ Socket_checkAsyncConnectState(Socket self)
return SOCKET_STATE_FAILED;
}
else if (result == 0) {
else if (result == 0)
{
return SOCKET_STATE_CONNECTING;
}
else {
else
{
return SOCKET_STATE_FAILED;
}
}
@ -545,21 +595,23 @@ Socket_connect(Socket self, const char* address, int port)
int result = poll(fds, 1, self->connectTimeout);
if (result == 1) {
if (result == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &so_error, &len) >= 0)
{
if (so_error == 0)
return true;
}
}
close (self->fd);
close(self->fd);
self->fd = -1;
return false;
@ -573,22 +625,24 @@ convertAddressToStr(struct sockaddr_storage* addr)
bool isIPv6;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) addr;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) addr;
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9);
char* clientConnection = (char*)GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
sprintf(clientConnection, "[%s]:%i", addrString, port);
@ -604,7 +658,8 @@ Socket_getPeerAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getpeername(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -617,7 +672,8 @@ Socket_getLocalAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getsockname(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getsockname(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -629,28 +685,37 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
{
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
getpeername(self->fd, (struct sockaddr*) &addr, &addrLen);
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == -1)
{
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: getpeername -> errno: %i\n", errno);
return NULL;
}
char addrString[INET6_ADDRSTRLEN + 7];
int port;
bool isIPv6;
if (addr.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr;
if (addr.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&addr;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (addr.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr;
else if (addr.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&addr;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return NULL ;
return NULL;
if (isIPv6)
sprintf(peerAddressString, "[%s]:%i", addrString, port);
@ -671,22 +736,24 @@ Socket_read(Socket self, uint8_t* buf, int size)
if (read_bytes == 0)
return -1;
if (read_bytes == -1) {
if (read_bytes == -1)
{
int error = errno;
switch (error) {
switch (error)
{
case EAGAIN:
return 0;
case EBADF:
return -1;
case EAGAIN:
return 0;
case EBADF:
return -1;
default:
default:
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: recv returned error (errno=%i)\n", error);
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: recv returned error (errno=%i)\n", error);
return -1;
return -1;
}
}
@ -702,11 +769,14 @@ Socket_write(Socket self, uint8_t* buf, int size)
/* MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket */
int retVal = send(self->fd, buf, size, MSG_NOSIGNAL | MSG_DONTWAIT);
if (retVal == -1) {
if (errno == EAGAIN) {
if (retVal == -1)
{
if (errno == EAGAIN)
{
return 0;
}
else {
else
{
if (DEBUG_SOCKET)
printf("DEBUG_SOCKET: send returned error (errno=%i)\n", errno);
}
@ -736,21 +806,25 @@ UdpSocket_createUsingNamespace(int namespace)
int sock = socket(namespace, SOCK_DGRAM, IPPROTO_UDP);
if (sock != -1) {
self = (UdpSocket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != -1)
{
self = (UdpSocket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->namespace = namespace;
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to allocate memory\n");
close(sock);
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create UDP socket (errno=%i)\n", errno);
}
@ -773,36 +847,42 @@ UdpSocket_createIpV6()
bool
UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
{
if (self->namespace == AF_INET) {
if (self->namespace == AF_INET)
{
struct ip_mreq mreq;
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr))) {
if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr)))
{
printf("SOCKET: Invalid IPv4 multicast address\n");
return false;
}
else {
else
{
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", errno);
return false;
}
}
return true;
}
else if (self->namespace == AF_INET6) {
else if (self->namespace == AF_INET6)
{
struct ipv6_mreq mreq;
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1) {
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
mreq.ipv6mr_interface = 0;
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno);
return false;
}
@ -816,16 +896,20 @@ UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
bool
UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
{
if (self->namespace == AF_INET) {
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
if (self->namespace == AF_INET)
{
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", errno);
return false;
}
return true;
}
else if (self->namespace == AF_INET6) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) {
else if (self->namespace == AF_INET6)
{
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", errno);
return false;
}
@ -839,10 +923,11 @@ UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
bool
UdpSocket_bind(UdpSocket self, const char* address, int port)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in localAddress;
if (!prepareAddress(address, port, &localAddress)) {
if (!prepareAddress(address, port, &localAddress))
{
close(self->fd);
self->fd = 0;
return false;
@ -850,7 +935,8 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind UDP socket (errno=%i)\n", errno);
@ -866,10 +952,11 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
bool
UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in remoteAddress;
if (!prepareAddress(address, port, &remoteAddress)) {
if (!prepareAddress(address, port, &remoteAddress))
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address);
@ -879,14 +966,17 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int result = sendto(self->fd, msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress));
if (result == msgSize) {
if (result == msgSize)
{
return true;
}
else if (result == -1) {
else if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (errno=%i)\n", errno);
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (insufficient data sent)\n");
}
@ -897,31 +987,35 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int
UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_storage remoteAddress;
memset(&remoteAddress, 0, sizeof(struct sockaddr_storage));
socklen_t structSize = sizeof(struct sockaddr_storage);
int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize);
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno);
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;

@ -1,7 +1,7 @@
/*
* socket_win32.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
@ -9,56 +9,64 @@
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdbool.h>
#include <stdio.h>
#pragma comment (lib, "Ws2_32.lib")
#pragma comment(lib, "Ws2_32.lib")
#include "lib_memory.h"
#include "hal_socket.h"
#include "stack_config.h"
#include "lib_memory.h"
#define DEBUG_SOCKET 1
#ifndef DEBUG_SOCKET
#define DEBUG_SOCKET 0
#endif
#ifndef __MINGW64_VERSION_MAJOR
struct tcp_keepalive {
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
struct tcp_keepalive
{
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
};
#endif
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR, 4)
struct sSocket {
struct sSocket
{
SOCKET fd;
uint32_t connectTimeout;
};
struct sServerSocket {
struct sServerSocket
{
SOCKET fd;
int backLog;
};
struct sHandleSet {
struct sHandleSet
{
fd_set handles;
SOCKET maxHandle;
};
struct sUdpSocket {
struct sUdpSocket
{
SOCKET fd;
int ns; /* IPv4: AF_INET; IPv6: AF_INET6 */
int ns; /* IPv4: AF_INET; IPv6: AF_INET6 */
};
HandleSet
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);
result->maxHandle = INVALID_SOCKET;
}
@ -76,19 +84,21 @@ Handleset_reset(HandleSet self)
void
Handleset_addSocket(HandleSet self, const Socket sock)
{
if (self != NULL && sock != NULL && sock->fd != INVALID_SOCKET) {
if (self != NULL && sock != NULL && sock->fd != INVALID_SOCKET)
{
FD_SET(sock->fd, &self->handles);
FD_SET(sock->fd, &self->handles);
if ((sock->fd > self->maxHandle) || (self->maxHandle == INVALID_SOCKET))
self->maxHandle = sock->fd;
}
if ((sock->fd > self->maxHandle) || (self->maxHandle == INVALID_SOCKET))
self->maxHandle = sock->fd;
}
}
void
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);
}
}
@ -98,7 +108,8 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
{
int result;
if ((self != NULL) && (self->maxHandle != INVALID_SOCKET)) {
if ((self != NULL) && (self->maxHandle != INVALID_SOCKET))
{
struct timeval timeout;
timeout.tv_sec = timeoutMs / 1000;
@ -109,7 +120,9 @@ Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
memcpy((void*)&handles, &(self->handles), sizeof(fd_set));
result = select(self->maxHandle + 1, &handles, NULL, NULL, &timeout);
} else {
}
else
{
result = -1;
}
@ -131,27 +144,26 @@ Socket_activateTcpKeepAlive(Socket self, int idleTime, int interval, int count)
(void)count; /* not supported in windows socket API */
struct tcp_keepalive keepalive;
DWORD retVal=0;
DWORD retVal = 0;
keepalive.onoff = 1;
keepalive.keepalivetime = idleTime * 1000;
keepalive.keepaliveinterval = interval * 1000;
if (WSAIoctl(self->fd, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive),
NULL, 0, &retVal, NULL, NULL) == SOCKET_ERROR)
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: WSAIotcl(SIO_KEEPALIVE_VALS) failed: %d\n",
WSAGetLastError());
}
if (WSAIoctl(self->fd, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &retVal, NULL, NULL) ==
SOCKET_ERROR)
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: WSAIotcl(SIO_KEEPALIVE_VALS) failed: %d\n", WSAGetLastError());
}
}
static void
setSocketNonBlocking(Socket self)
{
unsigned long mode = 1;
if (ioctlsocket(self->fd, FIONBIO, &mode) != 0) {
if (ioctlsocket(self->fd, FIONBIO, &mode) != 0)
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: failed to set socket non-blocking!\n");
}
@ -164,18 +176,19 @@ setSocketNonBlocking(Socket self)
}
static bool
prepareAddress(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;
if (address != NULL)
{
struct hostent* server;
server = gethostbyname(address);
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);
@ -189,20 +202,22 @@ prepareAddress(const char *address, int port, struct sockaddr_in *sockaddr)
static bool
wsaStartUp(void)
{
if (wsaStartupCalled == false) {
if (wsaStartupCalled == false)
{
int ec;
WSADATA wsa;
if ((ec = WSAStartup(MAKEWORD(2, 0), &wsa)) != 0) {
if ((ec = WSAStartup(MAKEWORD(2, 0), &wsa)) != 0)
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: winsock error: code %i\n", ec);
return false;
}
else {
else
{
wsaStartupCalled = true;
return true;
}
}
else
return true;
@ -211,12 +226,13 @@ wsaStartUp(void)
static void
wsaShutdown(void)
{
if (wsaStartupCalled) {
if (socketCount == 0) {
if (wsaStartupCalled)
{
if (socketCount == 0)
{
WSACleanup();
wsaStartupCalled = false;
}
}
}
@ -237,7 +253,8 @@ TcpServerSocket_create(const char* address, int port)
listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_socket == INVALID_SOCKET) {
if (listen_socket == INVALID_SOCKET)
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: socket failed with error: %i\n", WSAGetLastError());
@ -247,11 +264,12 @@ TcpServerSocket_create(const char* address, int port)
}
int optionReuseAddr = 1;
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&optionReuseAddr, sizeof(int));
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&optionReuseAddr, sizeof(int));
ec = bind(listen_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ec == SOCKET_ERROR) {
if (ec == SOCKET_ERROR)
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: bind failed with error:%i\n", WSAGetLastError());
closesocket(listen_socket);
@ -263,7 +281,8 @@ TcpServerSocket_create(const char* address, int port)
serverSocket = (ServerSocket)GLOBAL_MALLOC(sizeof(struct sServerSocket));
if (serverSocket) {
if (serverSocket)
{
serverSocket->fd = listen_socket;
serverSocket->backLog = 10;
@ -271,7 +290,8 @@ TcpServerSocket_create(const char* address, int port)
socketCount++;
}
else {
else
{
closesocket(listen_socket);
wsaShutdown();
}
@ -292,8 +312,9 @@ ServerSocket_accept(ServerSocket self)
SOCKET fd = accept(self->fd, NULL, NULL);
if (fd != INVALID_SOCKET) {
conSocket = (Socket) GLOBAL_CALLOC(1, sizeof(struct sSocket));
if (fd != INVALID_SOCKET)
{
conSocket = (Socket)GLOBAL_CALLOC(1, sizeof(struct sSocket));
conSocket->fd = fd;
socketCount++;
@ -303,7 +324,8 @@ ServerSocket_accept(ServerSocket self)
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: connection accepted\n");
}
else {
else
{
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: accept failed\n");
}
@ -320,7 +342,8 @@ ServerSocket_setBacklog(ServerSocket self, int backlog)
void
ServerSocket_destroy(ServerSocket self)
{
if (self->fd != INVALID_SOCKET) {
if (self->fd != INVALID_SOCKET)
{
shutdown(self->fd, 2);
closesocket(self->fd);
socketCount--;
@ -341,25 +364,28 @@ TcpSocket_create()
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock != INVALID_SOCKET) {
self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != INVALID_SOCKET)
{
self = (Socket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->connectTimeout = 5000;
socketCount++;
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create socket - cannot allocate memory\n");
closesocket(sock);
wsaShutdown();
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create socket (error code=%i)\n", WSAGetLastError());
}
@ -383,7 +409,8 @@ Socket_bind(Socket self, const char* srcAddress, int srcPort)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == SOCKET_ERROR) {
if (result == SOCKET_ERROR)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind TCP socket (errno=%i)\n", WSAGetLastError());
@ -403,22 +430,19 @@ Socket_connectAsync(Socket self, const char* address, int port)
printf("WIN32_SOCKET: Socket_connect: %s:%i\n", address, port);
struct sockaddr_in serverAddress;
WSADATA wsa;
int ec;
if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) {
if (DEBUG_SOCKET)
printf("WIN32_SOCKET: winsock error: code %i\n", ec);
if (wsaStartUp() == false)
return false;
}
if (!prepareAddress(address, port, &serverAddress))
return false;
setSocketNonBlocking(self);
if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
if (connect(self->fd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
closesocket(self->fd);
self->fd = INVALID_SOCKET;
return false;
@ -439,21 +463,25 @@ Socket_checkAsyncConnectState(Socket self)
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
int selectVal = select(self->fd + 1, NULL, &fdSet , NULL, &timeout);
int selectVal = select(self->fd + 1, NULL, &fdSet, NULL, &timeout);
if (selectVal == 1) {
if (selectVal == 1)
{
/* Check if connection is established */
int so_error;
int len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, (char*) (&so_error), &len) != SOCKET_ERROR) {
if (so_error == 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, (char*)(&so_error), &len) != SOCKET_ERROR)
{
if (so_error == 0)
{
int recvRes = recv(self->fd, NULL, 0, 0);
if (recvRes == SOCKET_ERROR) {
if (recvRes == SOCKET_ERROR)
{
int wsaError = WSAGetLastError();
if (wsaError == WSAECONNRESET)
@ -463,17 +491,18 @@ Socket_checkAsyncConnectState(Socket self)
return SOCKET_STATE_FAILED;
}
return SOCKET_STATE_CONNECTED;
}
}
return SOCKET_STATE_FAILED;
}
else if (selectVal == 0) {
else if (selectVal == 0)
{
return SOCKET_STATE_CONNECTING;
}
else {
else
{
return SOCKET_STATE_FAILED;
}
}
@ -492,21 +521,23 @@ Socket_connect(Socket self, const char* address, int port)
FD_ZERO(&fdSet);
FD_SET(self->fd, &fdSet);
if (select(self->fd + 1, NULL, &fdSet , NULL, &timeout) == 1) {
if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) == 1)
{
/* Check if connection is established */
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, (char*)&so_error, &len) >= 0) {
if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, (char*)&so_error, &len) >= 0)
{
if (so_error == 0)
return true;
}
}
closesocket (self->fd);
closesocket(self->fd);
self->fd = INVALID_SOCKET;
return false;
@ -521,26 +552,28 @@ convertAddressToStr(struct sockaddr_storage* addr)
bool isIPv6;
if (addr->ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) addr;
if (addr->ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)addr;
port = ntohs(ipv4Addr->sin_port);
ipv4Addr->sin_port = 0;
WSAAddressToString((LPSOCKADDR) ipv4Addr, sizeof(struct sockaddr_storage), NULL,
(LPSTR) addrString, (LPDWORD) &addrStringLen);
WSAAddressToString((LPSOCKADDR)ipv4Addr, sizeof(struct sockaddr_storage), NULL, (LPSTR)addrString,
(LPDWORD)&addrStringLen);
isIPv6 = false;
}
else if (addr->ss_family == AF_INET6){
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) addr;
else if (addr->ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)addr;
port = ntohs(ipv6Addr->sin6_port);
ipv6Addr->sin6_port = 0;
WSAAddressToString((LPSOCKADDR) ipv6Addr, sizeof(struct sockaddr_storage), NULL,
(LPSTR) addrString, (LPDWORD) &addrStringLen);
WSAAddressToString((LPSOCKADDR)ipv6Addr, sizeof(struct sockaddr_storage), NULL, (LPSTR)addrString,
(LPDWORD)&addrStringLen);
isIPv6 = true;
}
else
return NULL;
char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9);
char* clientConnection = (char*)GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
sprintf(clientConnection, "[%s]:%i", addrString, port);
@ -550,14 +583,14 @@ convertAddressToStr(struct sockaddr_storage* addr)
return clientConnection;
}
char*
Socket_getPeerAddress(Socket self)
{
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getpeername(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getpeername(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -570,7 +603,8 @@ Socket_getLocalAddress(Socket self)
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
if (getsockname(self->fd, (struct sockaddr*) &addr, &addrLen) == 0) {
if (getsockname(self->fd, (struct sockaddr*)&addr, &addrLen) == 0)
{
return convertAddressToStr(&addr);
}
else
@ -583,7 +617,7 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
struct sockaddr_storage addr;
int addrLen = sizeof(addr);
getpeername(self->fd, (struct sockaddr*) &addr, &addrLen);
getpeername(self->fd, (struct sockaddr*)&addr, &addrLen);
char addrString[INET6_ADDRSTRLEN + 7];
int addrStringLen = INET6_ADDRSTRLEN + 7;
@ -591,20 +625,22 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
bool isIPv6;
if (addr.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &addr;
if (addr.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&addr;
port = ntohs(ipv4Addr->sin_port);
ipv4Addr->sin_port = 0;
WSAAddressToString((LPSOCKADDR) ipv4Addr, sizeof(struct sockaddr_storage), NULL,
(LPSTR) addrString, (LPDWORD) & addrStringLen);
WSAAddressToString((LPSOCKADDR)ipv4Addr, sizeof(struct sockaddr_storage), NULL, (LPSTR)addrString,
(LPDWORD)&addrStringLen);
isIPv6 = false;
}
else if (addr.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &addr;
else if (addr.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&addr;
port = ntohs(ipv6Addr->sin6_port);
ipv6Addr->sin6_port = 0;
WSAAddressToString((LPSOCKADDR) ipv6Addr, sizeof(struct sockaddr_storage), NULL,
(LPSTR) addrString, (LPDWORD) & addrStringLen);
WSAAddressToString((LPSOCKADDR)ipv6Addr, sizeof(struct sockaddr_storage), NULL, (LPSTR)addrString,
(LPDWORD)&addrStringLen);
isIPv6 = true;
}
else
@ -621,12 +657,13 @@ Socket_getPeerAddressStatic(Socket self, char* peerAddressString)
int
Socket_read(Socket self, uint8_t* buf, int size)
{
int bytes_read = recv(self->fd, (char*) buf, size, 0);
int bytes_read = recv(self->fd, (char*)buf, size, 0);
if (bytes_read == 0) /* peer has closed socket */
return -1;
if (bytes_read == SOCKET_ERROR) {
if (bytes_read == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
return 0;
else
@ -639,9 +676,10 @@ Socket_read(Socket self, uint8_t* buf, int size)
int
Socket_write(Socket self, uint8_t* buf, int size)
{
int bytes_sent = send(self->fd, (char*) buf, size, 0);
int bytes_sent = send(self->fd, (char*)buf, size, 0);
if (bytes_sent == SOCKET_ERROR) {
if (bytes_sent == SOCKET_ERROR)
{
int errorCode = WSAGetLastError();
if (errorCode == WSAEWOULDBLOCK)
@ -656,7 +694,8 @@ Socket_write(Socket self, uint8_t* buf, int size)
void
Socket_destroy(Socket self)
{
if (self->fd != INVALID_SOCKET) {
if (self->fd != INVALID_SOCKET)
{
shutdown(self->fd, 2);
closesocket(self->fd);
@ -680,23 +719,27 @@ UdpSocket_createUsingNamespace(int ns)
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock != INVALID_SOCKET) {
self = (UdpSocket) GLOBAL_MALLOC(sizeof(struct sSocket));
if (sock != INVALID_SOCKET)
{
self = (UdpSocket)GLOBAL_MALLOC(sizeof(struct sSocket));
if (self) {
if (self)
{
self->fd = sock;
self->ns = ns;
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to allocate memory\n");
closesocket(sock);
}
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to create UDP socket (errno=%i)\n", WSAGetLastError());
printf("SOCKET: failed to create UDP socket (errno=%i)\n", WSAGetLastError());
}
return self;
@ -717,37 +760,43 @@ UdpSocket_createIpV6()
bool
UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
{
if (self->ns == AF_INET) {
if (self->ns == AF_INET)
{
struct ip_mreq mreq;
if (inet_pton(AF_INET, multicastAddress, &(mreq.imr_multiaddr)) < 1) {
if (inet_pton(AF_INET, multicastAddress, &(mreq.imr_multiaddr)) < 1)
{
printf("SOCKET: Invalid IPv4 multicast address\n");
return false;
}
else {
else
{
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == -1) {
printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", WSAGetLastError());
if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", WSAGetLastError());
return false;
}
}
return true;
}
else if (self->ns == AF_INET6) {
else if (self->ns == AF_INET6)
{
struct ipv6_mreq mreq;
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1) {
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", WSAGetLastError());
if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", WSAGetLastError());
return false;
}
mreq.ipv6mr_interface = 0;
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == -1) {
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", WSAGetLastError());
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", WSAGetLastError());
return false;
}
@ -760,17 +809,21 @@ UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress)
bool
UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
{
if (self->ns == AF_INET) {
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)) == -1) {
printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", WSAGetLastError());
if (self->ns == AF_INET)
{
if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", WSAGetLastError());
return false;
}
return true;
}
else if (self->ns == AF_INET6) {
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&ttl, sizeof(ttl)) == -1) {
printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", WSAGetLastError());
else if (self->ns == AF_INET6)
{
if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&ttl, sizeof(ttl)) == -1)
{
printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", WSAGetLastError());
return false;
}
@ -783,10 +836,11 @@ UdpSocket_setMulticastTtl(UdpSocket self, int ttl)
bool
UdpSocket_bind(UdpSocket self, const char* address, int port)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in localAddress;
if (!prepareAddress(address, port, &localAddress)) {
if (!prepareAddress(address, port, &localAddress))
{
closesocket(self->fd);
self->fd = 0;
return false;
@ -794,7 +848,8 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress));
if (result == -1) {
if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to bind UDP socket (errno=%i)\n", errno);
@ -810,10 +865,11 @@ UdpSocket_bind(UdpSocket self, const char* address, int port)
bool
UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_in remoteAddress;
if (!prepareAddress(address, port, &remoteAddress)) {
if (!prepareAddress(address, port, &remoteAddress))
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to lookup remote address %s\n", address);
@ -821,16 +877,20 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
return false;
}
int result = sendto(self->fd, (const char*) msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress));
int result =
sendto(self->fd, (const char*)msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress));
if (result == msgSize) {
if (result == msgSize)
{
return true;
}
else if (result == -1) {
else if (result == -1)
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (errno=%i)\n", errno);
}
else {
else
{
if (DEBUG_SOCKET)
printf("SOCKET: failed to send UDP message (insufficient data sent)\n");
}
@ -841,7 +901,7 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
int
UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize)
{
//TODO add support for IPv6
// TODO add support for IPv6
struct sockaddr_storage remoteAddress;
memset(&remoteAddress, 0, sizeof(struct sockaddr_storage));
socklen_t structSize = sizeof(struct sockaddr_storage);
@ -849,31 +909,35 @@ UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* m
if (address)
address[0] = 0;
int result = recvfrom(self->fd, (char*) msg, msgSize, 0, (struct sockaddr*)&remoteAddress, &structSize);
int result = recvfrom(self->fd, (char*)msg, msgSize, 0, (struct sockaddr*)&remoteAddress, &structSize);
if (result == 0) /* peer has closed socket */
return -1;
if (result == SOCKET_ERROR) {
if (result == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
return 0;
else
return -1;
}
if (address) {
if (address)
{
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
if (remoteAddress.ss_family == AF_INET)
{
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*)&remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
else if (remoteAddress.ss_family == AF_INET6)
{
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*)&remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;

@ -1,7 +1,7 @@
/*
* time.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
@ -62,4 +62,36 @@ Hal_setTimeInNs(nsSinceEpoch nsTime)
return true;
}
msSinceEpoch
Hal_getMonotonicTimeInMs()
{
uint64_t timeVal = 0;
struct timespec ts;
if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
{
timeVal = ((uint64_t)ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000);
}
return timeVal;
}
nsSinceEpoch
Hal_getMonotonicTimeInNs()
{
uint64_t nsTime = 0;
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
{
nsTime = ts.tv_sec * 1000000000UL;
nsTime += ts.tv_nsec;
}
return nsTime;
}
#endif

@ -1,7 +1,7 @@
/*
* time.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2024 Michael Zillgith
*
* This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870.
@ -59,3 +59,14 @@ Hal_setTimeInNs(nsSinceEpoch nsTime)
return SetSystemTime(&st);
}
msSinceEpoch
Hal_getMonotonicTimeInMs()
{
return (msSinceEpoch)GetTickCount64;
}
nsSinceEpoch
Hal_getMonotonicTimeInNs()
{
return (nsSinceEpoch)(GetTickCount64() * 1000000ULL);
}

@ -11,23 +11,21 @@
#include <string.h>
#include "tls_socket.h"
#include "hal_thread.h"
#include "lib_memory.h"
#include "hal_time.h"
#include "lib_memory.h"
#include "linked_list.h"
#include "tls_socket.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#remove-the-certs-module-from-the-library
// #include "mbedtls/certs.h" (MIGRATE 2.28->3.x.x)
#include "mbedtls/x509.h"
#include "mbedtls/ssl.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/entropy.h"
#include "mbedtls/platform.h"
#include "mbedtls/debug.h"
#include "mbedtls/error.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_cache.h"
#include "mbedtls/x509.h"
#define SEC_EVENT_ALARM 2
#define SEC_EVENT_WARNING 1
@ -38,14 +36,18 @@
#endif
#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)
#define DEBUG_PRINT(fmt, ...) \
do \
{ \
} while (0)
#endif
static int psaInitCounter = 0;
struct sTLSConfiguration {
struct sTLSConfiguration
{
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
@ -73,11 +75,9 @@ struct sTLSConfiguration {
/* TLS session renegotiation interval in milliseconds */
int renegotiationTimeInMs;
// MIGRATE 2.28->3.x.x: Changed min version to 1.2 to reflect the removal of 1.1 and 1.0
/* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */
TLSConfigVersion minVersion;
// MIGRATE 2.28->3.x.x: Kept the max version but changed documentation
/* TLS maximum version allowed (default: TLS_VERSION_NOT_SELECTED) */
TLSConfigVersion maxVersion;
@ -96,7 +96,8 @@ struct sTLSConfiguration {
int maxCiphersuites;
};
struct sTLSSocket {
struct sTLSSocket
{
mbedtls_ssl_context ssl;
Socket socket;
mbedtls_ssl_config conf;
@ -113,20 +114,21 @@ struct sTLSSocket {
};
static void
raiseSecurityEvent(TLSConfiguration config, TLSEventLevel eventCategory, int eventCode, const char* message, TLSSocket socket)
raiseSecurityEvent(TLSConfiguration config, TLSEventLevel eventCategory, int eventCode, const char* message,
TLSSocket socket)
{
if (config->eventHandler) {
if (config->eventHandler)
{
config->eventHandler(config->eventHandlerParameter, eventCategory, eventCode, message, (TLSConnection)socket);
}
}
static bool
compareCertificates(mbedtls_x509_crt *crt1, mbedtls_x509_crt *crt2)
compareCertificates(mbedtls_x509_crt* crt1, mbedtls_x509_crt* crt2)
{
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private
if (crt1 != NULL && crt2 != NULL &&
crt1->raw.len == crt2->raw.len &&
memcmp(crt1->raw.p, crt2->raw.p, crt1->raw.len) == 0) {
if (crt1 != NULL && crt2 != NULL && crt1->raw.len == crt2->raw.len &&
memcmp(crt1->raw.p, crt2->raw.p, crt1->raw.len) == 0)
{
return true;
}
@ -134,9 +136,9 @@ compareCertificates(mbedtls_x509_crt *crt1, mbedtls_x509_crt *crt2)
}
static int
verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags)
verifyCertificate(void* parameter, mbedtls_x509_crt* crt, int certificate_depth, uint32_t* flags)
{
TLSSocket self = (TLSSocket) parameter;
TLSSocket self = (TLSSocket)parameter;
DEBUG_PRINT("TLS", "Verify cert: depth %i\n", certificate_depth);
@ -166,7 +168,7 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
while (certList)
{
mbedtls_x509_crt* allowedCert = (mbedtls_x509_crt*) LinkedList_getData(certList);
mbedtls_x509_crt* allowedCert = (mbedtls_x509_crt*)LinkedList_getData(certList);
DEBUG_PRINT("TLS", "Compare With:\n");
mbedtls_x509_crt_info(buffer, 1023, " ", allowedCert);
@ -188,7 +190,8 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
}
else
{
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: certificate validation: trusted individual certificate not available", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED,
"Alarm: certificate validation: trusted individual certificate not available", self);
*flags |= MBEDTLS_X509_BADCERT_OTHER;
return 1;
@ -201,28 +204,32 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
{
*flags = *flags - MBEDTLS_X509_BADCERT_EXPIRED;
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CERT_EXPIRED, "Warning: certificate validation: using expired certificate", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CERT_EXPIRED,
"Warning: certificate validation: using expired certificate", self);
}
if (*flags & MBEDTLS_X509_BADCRL_EXPIRED)
{
*flags = *flags - MBEDTLS_X509_BADCRL_EXPIRED;
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CRL_EXPIRED, "Warning: certificate validation: using expired CRL", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CRL_EXPIRED,
"Warning: certificate validation: using expired CRL", self);
}
if (*flags & MBEDTLS_X509_BADCERT_FUTURE)
{
*flags = *flags - MBEDTLS_X509_BADCERT_FUTURE;
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CERT_NOT_YET_VALID, "Warning: certificate validation: using certificate with validity in future", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CERT_NOT_YET_VALID,
"Warning: certificate validation: using certificate with validity in future", self);
}
if (*flags & MBEDTLS_X509_BADCRL_FUTURE)
{
*flags = *flags - MBEDTLS_X509_BADCRL_FUTURE;
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CRL_NOT_YET_VALID, "Warning: certificate validation: using CRL with validity in future", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_CRL_NOT_YET_VALID,
"Warning: certificate validation: using CRL with validity in future", self);
}
}
@ -231,7 +238,7 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
if (*flags == 0)
{
self->peerCertLength = 0;
self->peerCert = (uint8_t*) GLOBAL_MALLOC(crt->raw.len);
self->peerCert = (uint8_t*)GLOBAL_MALLOC(crt->raw.len);
if (self->peerCert)
{
@ -253,13 +260,14 @@ TLSConfiguration_setupComplete(TLSConfiguration self)
{
if (self->setupComplete == false)
{
mbedtls_ssl_conf_ca_chain( &(self->conf), &(self->cacerts), &(self->crl) );
mbedtls_ssl_conf_ca_chain(&(self->conf), &(self->cacerts), &(self->crl));
if (self->ownCertificate.version > 0)
{
int ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(self->ownCertificate), &(self->ownKey));
int ret = mbedtls_ssl_conf_own_cert(&(self->conf), &(self->ownCertificate), &(self->ownKey));
if (ret != 0) {
if (ret != 0)
{
DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned -0x%x\n", -ret);
return false;
}
@ -267,19 +275,17 @@ TLSConfiguration_setupComplete(TLSConfiguration self)
if (self->useSessionResumption)
{
if (mbedtls_ssl_conf_get_endpoint(&(self->conf)) == MBEDTLS_SSL_IS_CLIENT) {
if (mbedtls_ssl_conf_get_endpoint(&(self->conf)) == MBEDTLS_SSL_IS_CLIENT)
{
}
else
{
mbedtls_ssl_cache_init( &(self->cache) );
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private
mbedtls_ssl_cache_init(&(self->cache));
mbedtls_ssl_cache_set_timeout(&(self->cache), self->sessionResumptionInterval);
mbedtls_ssl_conf_session_cache( &(self->conf), &(self->cache),
mbedtls_ssl_cache_get,
mbedtls_ssl_cache_set );
mbedtls_ssl_conf_session_cache(&(self->conf), &(self->cache), mbedtls_ssl_cache_get,
mbedtls_ssl_cache_set);
}
}
@ -344,31 +350,36 @@ TLSConfiguration_clearCipherSuiteList(TLSConfiguration self)
TLSConfiguration
TLSConfiguration_create()
{
TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration));
TLSConfiguration self = (TLSConfiguration)GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration));
if (self)
{
/* call to psa_crypto_init required -> see https://github.com/Mbed-TLS/mbedtls/issues/9223 */
psa_status_t psaStatus = psa_crypto_init();
psa_status_t psaStatus = psa_crypto_init();
if (psaStatus != PSA_SUCCESS)
{
DEBUG_PRINT("TLS", "psa_crypto_init failed with %i\n", psaStatus);
GLOBAL_FREEMEM(self);
return NULL;
}
psaInitCounter++;
mbedtls_ssl_config_init( &(self->conf) );
mbedtls_x509_crt_init( &(self->ownCertificate) );
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) );
mbedtls_ssl_config_init(&(self->conf));
mbedtls_x509_crt_init(&(self->ownCertificate));
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));
/* WARINING is fixed to server! */
mbedtls_ssl_config_defaults( &(self->conf),
MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT );
mbedtls_ssl_config_defaults(&(self->conf), MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
mbedtls_ctr_drbg_seed( &(self->ctr_drbg), mbedtls_entropy_func, &(self->entropy), NULL, 0);
mbedtls_ssl_conf_rng( &(self->conf), mbedtls_ctr_drbg_random, &(self->ctr_drbg) );
mbedtls_ctr_drbg_seed(&(self->ctr_drbg), mbedtls_entropy_func, &(self->entropy), NULL, 0);
mbedtls_ssl_conf_rng(&(self->conf), mbedtls_ctr_drbg_random, &(self->ctr_drbg));
mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
@ -408,13 +419,15 @@ TLSConfiguration_create()
/* mandatory cipher suites by IEC 62351-4:2018 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256;
/* self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_GCM_SHA256; */ /* weak - not supported? */
/* self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_GCM_SHA256; */ /* weak - not
supported? */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
/* recommended cipher suites by IEC 62351-4:2018 */
/* self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_CBC_SHA256; */ /* weak - not supported?*/
/* self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_DH_RSA_WITH_AES_128_CBC_SHA256; */ /* weak - not
supported?*/
/* self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_DH_RSA_WITH_AES_256_GCM_SHA384; */ /* not supported?*/
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
@ -425,11 +438,16 @@ TLSConfiguration_create()
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
/* TLS 1.3 cipher suites */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_128_GCM_SHA256; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_256_GCM_SHA384; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256; /* optional according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_128_CCM_SHA256; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256 ; /* optional according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] =
MBEDTLS_TLS1_3_AES_128_GCM_SHA256; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] =
MBEDTLS_TLS1_3_AES_256_GCM_SHA384; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] =
MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256; /* optional according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] =
MBEDTLS_TLS1_3_AES_128_CCM_SHA256; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] =
MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256; /* optional according IEC 62351-3:2023 */
}
}
@ -505,7 +523,7 @@ TLSConfiguration_setOwnCertificate(TLSConfiguration self, uint8_t* certificate,
bool
TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* filename)
{
int ret = mbedtls_x509_crt_parse_file(&(self->ownCertificate), filename);
int ret = mbedtls_x509_crt_parse_file(&(self->ownCertificate), filename);
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse_file returned -0x%x\n", -ret);
@ -516,9 +534,9 @@ TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* fi
bool
TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword)
{
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#some-functions-gained-an-rng-parameter
// MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create
int ret = mbedtls_pk_parse_key(&(self->ownKey), key, keyLen, (const uint8_t*) keyPassword, (keyPassword == NULL) ? 0 : strlen(keyPassword), mbedtls_ctr_drbg_random, &(self->ctr_drbg));
int ret = mbedtls_pk_parse_key(&(self->ownKey), key, keyLen, (const uint8_t*)keyPassword,
(keyPassword == NULL) ? 0 : strlen(keyPassword), mbedtls_ctr_drbg_random,
&(self->ctr_drbg));
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_pk_parse_key returned -0x%x\n", -ret);
@ -529,9 +547,8 @@ TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, cons
bool
TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword)
{
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#some-functions-gained-an-rng-parameter
// MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create
int ret = mbedtls_pk_parse_keyfile(&(self->ownKey), filename, keyPassword, mbedtls_ctr_drbg_random, &(self->ctr_drbg));
int ret =
mbedtls_pk_parse_keyfile(&(self->ownKey), filename, keyPassword, mbedtls_ctr_drbg_random, &(self->ctr_drbg));
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_pk_parse_keyfile returned -0x%x\n", -ret);
@ -542,7 +559,7 @@ TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename,
bool
TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certificate, int certLen)
{
mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt));
mbedtls_x509_crt* cert = (mbedtls_x509_crt*)GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt));
int ret = mbedtls_x509_crt_parse(cert, certificate, certLen);
@ -561,7 +578,7 @@ TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certifica
bool
TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename)
{
mbedtls_x509_crt* cert = (mbedtls_x509_crt*) GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt));
mbedtls_x509_crt* cert = (mbedtls_x509_crt*)GLOBAL_CALLOC(1, sizeof(mbedtls_x509_crt));
int ret = mbedtls_x509_crt_parse_file(cert, filename);
@ -580,7 +597,7 @@ TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char
bool
TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, int certLen)
{
int ret = mbedtls_x509_crt_parse(&(self->cacerts), certificate, certLen);
int ret = mbedtls_x509_crt_parse(&(self->cacerts), certificate, certLen);
if (ret != 0)
{
@ -594,7 +611,7 @@ TLSConfiguration_addCACertificate(TLSConfiguration self, uint8_t* certificate, i
bool
TLSConfiguration_addCACertificateFromFile(TLSConfiguration self, const char* filename)
{
int ret = mbedtls_x509_crt_parse_file(&(self->cacerts), filename);
int ret = mbedtls_x509_crt_parse_file(&(self->cacerts), filename);
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_x509_crt_parse returned -0x%x\n", -ret);
@ -622,10 +639,12 @@ TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen)
{
int ret = mbedtls_x509_crl_parse(&(self->crl), crl, crlLen);
if (ret != 0) {
if (ret != 0)
{
DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse returned -0x%x\n", -ret);
}
else {
else
{
udpatedCRL(self);
}
@ -635,12 +654,14 @@ TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen)
bool
TLSConfiguration_addCRLFromFile(TLSConfiguration self, const char* filename)
{
int ret = mbedtls_x509_crl_parse_file(&(self->crl), filename);
int ret = mbedtls_x509_crl_parse_file(&(self->crl), filename);
if (ret != 0) {
if (ret != 0)
{
DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse_file returned %d\n", ret);
}
else {
else
{
udpatedCRL(self);
}
@ -694,7 +715,7 @@ TLSConfiguration_destroy(TLSConfiguration self)
while (certElem)
{
mbedtls_x509_crt* cert = (mbedtls_x509_crt*) LinkedList_getData(certElem);
mbedtls_x509_crt* cert = (mbedtls_x509_crt*)LinkedList_getData(certElem);
mbedtls_x509_crt_free(cert);
@ -720,111 +741,136 @@ createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket
if (config->eventHandler == NULL)
return;
switch (ret) {
switch (ret)
{
case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG:
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: Algorithm not supported", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: Algorithm not supported",
socket);
break;
// MIGRATE 2.28->3.x.x:https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#changes-in-the-ssl-error-code-space
// case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: no matching TLS ciphers", socket);
// break;
// case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Algorithm not supported", socket);
// break;
// MIGRATE 2.28->3.x.x:https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#changes-in-the-ssl-error-code-space
// case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: no matching TLS
// ciphers", socket); break;
// case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Algorithm
// not supported", socket); break;
case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Handshake failure", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED,
"Alarm: Handshake failure", socket);
break;
// case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Alarm: Unsecure communication", socket);
// break;
// case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Alarm:
// Unsecure communication", socket); break;
case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_UNAVAILABLE, "Alarm: certificate unavailable", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_UNAVAILABLE,
"Alarm: certificate unavailable", socket);
break;
// case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Alarm: Bad certificate", socket);
// break;
// case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Alarm: Bad certificate",
// socket); break;
case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_SIZE_EXCEEDED, "Alarm: TLS certificate size exceeded", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_SIZE_EXCEEDED,
"Alarm: TLS certificate size exceeded", socket);
break;
// MIGRATE 2.28->3.x.x: the removal of this is undocumented TODO: Verify migration path
// case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm: certificate validation: certificate signature could not be validated", socket);
// break;
// MIGRATE 2.28->3.x.x: the removal of this is undocumented TODO: Verify migration path
// case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED: (MIGRATE 2.28->3.x.x)
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm:
// certificate validation: certificate signature could not be validated", socket); break;
// MIGRATE 2.28->3.x.x: the removal of this is undocumented. The docs say migrating users are affected but don't provide a migration path TODO: Verify migration path (MIGRATE 2.28->3.x.x)
// case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED:
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Alarm: Certificate required", socket);
// break;
// MIGRATE 2.28->3.x.x: the removal of this is undocumented. The docs say migrating users are affected but don't
// provide a migration path TODO: Verify migration path (MIGRATE 2.28->3.x.x) case
// MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED:
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Alarm: Certificate
// required", socket); break;
case MBEDTLS_ERR_SSL_DECODE_ERROR:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Decode error", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Decode error", socket);
break;
case MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Illegal parameter", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Illegal parameter", socket);
break;
case MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Bad protocol version", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Bad protocol version", socket);
break;
case MBEDTLS_ERR_SSL_BAD_CERTIFICATE:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Bad certificate", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Bad certificate", socket);
break;
case MBEDTLS_ERR_SSL_UNRECOGNIZED_NAME:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unrecognized name", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Unrecognized name", socket);
break;
case MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unsupported extension", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Unsupported extension", socket);
break;
case MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: No application protocol", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: No application protocol", socket);
break;
case MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Unexpected message", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Unexpected message", socket);
break;
case MBEDTLS_ERR_SSL_INTERNAL_ERROR:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: Internal error", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: Internal error", socket);
break;
case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: {
if (flags & MBEDTLS_X509_BADCERT_EXPIRED)
{
if (flags & MBEDTLS_X509_BADCERT_EXPIRED) {
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_EXPIRED, "Alarm: expired certificate", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_REVOKED) {
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED, "Alarm: revoked certificate", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED, "Alarm: Certificate validation: CA certificate not available", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_OTHER) {
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: Certificate not configured", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_BAD_KEY) {
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED, "Alarm: Insufficient key length", socket);
}
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm: Certificate verification failed", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_EXPIRED,
"Alarm: expired certificate", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_REVOKED)
{
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED,
"Alarm: revoked certificate", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
{
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_TRUSTED,
"Alarm: Certificate validation: CA certificate not available", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_OTHER)
{
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED,
"Alarm: Certificate not configured", socket);
}
else if (flags & MBEDTLS_X509_BADCERT_BAD_KEY)
{
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_NOT_CONFIGURED,
"Alarm: Insufficient key length", socket);
}
break;
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED,
"Alarm: Certificate verification failed", socket);
}
break;
default:
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON, "Alarm: handshake failed for unknown reason", socket);
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_HANDSHAKE_FAILED_UNKNOWN_REASON,
"Alarm: handshake failed for unknown reason", socket);
break;
}
}
@ -832,7 +878,7 @@ createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket
static int
readFunction(void* ctx, unsigned char* buf, size_t len)
{
int ret = Socket_read((Socket) ctx, buf, (int)len);
int ret = Socket_read((Socket)ctx, buf, (int)len);
if ((ret == 0) && (len > 0))
{
@ -855,37 +901,11 @@ writeFunction(void* ctx, unsigned char* buf, size_t len)
return ret;
}
static TLSConfigVersion
getTLSVersion(int majorVersion, int minorVersion)
{
if (majorVersion != 3) {
return TLS_VERSION_NOT_SELECTED;
}
else
{
switch (minorVersion) {
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
case 0:
return TLS_VERSION_SSL_3_0;
case 1:
return TLS_VERSION_TLS_1_0;
case 2:
return TLS_VERSION_TLS_1_1;
/* Up until here (MIGRATE 2.28->3.x.x) */
case 3:
return TLS_VERSION_TLS_1_2;
case 4:
return TLS_VERSION_TLS_1_3;
default:
return TLS_VERSION_NOT_SELECTED;
}
}
}
static int
getMajorVersion(TLSConfigVersion version)
{
switch(version) {
switch (version)
{
case TLS_VERSION_NOT_SELECTED:
return 0;
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
@ -904,7 +924,8 @@ getMajorVersion(TLSConfigVersion version)
static int
getMinorVersion(TLSConfigVersion version)
{
switch(version) {
switch (version)
{
case TLS_VERSION_NOT_SELECTED:
return 0;
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
@ -927,7 +948,7 @@ getMinorVersion(TLSConfigVersion version)
TLSSocket
TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClientCert)
{
TLSSocket self = (TLSSocket) GLOBAL_CALLOC(1, sizeof(struct sTLSSocket));
TLSSocket self = (TLSSocket)GLOBAL_CALLOC(1, sizeof(struct sTLSSocket));
if (self)
{
@ -941,11 +962,11 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
memcpy(&(self->conf), &(configuration->conf), sizeof(mbedtls_ssl_config));
mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*) self);
mbedtls_ssl_conf_verify(&(self->conf), verifyCertificate, (void*)self);
int ret;
mbedtls_ssl_conf_ca_chain( &(self->conf), &(configuration->cacerts), &(configuration->crl) );
mbedtls_ssl_conf_ca_chain(&(self->conf), &(configuration->cacerts), &(configuration->crl));
self->crlUpdated = configuration->crlUpdated;
@ -956,7 +977,7 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
int majorVer = getMajorVersion(configuration->minVersion);
int minorVer = getMinorVersion(configuration->minVersion);
mbedtls_ssl_conf_min_version( &(self->conf), majorVer, minorVer);
mbedtls_ssl_conf_min_version(&(self->conf), majorVer, minorVer);
}
if (configuration->maxVersion != TLS_VERSION_NOT_SELECTED)
@ -966,24 +987,24 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
int majorVer = getMajorVersion(configuration->maxVersion);
int minorVer = getMinorVersion(configuration->maxVersion);
mbedtls_ssl_conf_max_version( &(self->conf), majorVer, minorVer);
mbedtls_ssl_conf_max_version(&(self->conf), majorVer, minorVer);
}
if (configuration->ownCertificate.version > 0)
{
ret = mbedtls_ssl_conf_own_cert( &(self->conf), &(configuration->ownCertificate), &(configuration->ownKey));
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) );
ret = mbedtls_ssl_setup(&(self->ssl), &(self->conf));
if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret);
mbedtls_ssl_set_bio(&(self->ssl), socket, (mbedtls_ssl_send_t*) writeFunction,
(mbedtls_ssl_recv_t*) readFunction, NULL);
mbedtls_ssl_set_bio(&(self->ssl), socket, (mbedtls_ssl_send_t*)writeFunction, (mbedtls_ssl_recv_t*)readFunction,
NULL);
if (configuration->useSessionResumption)
{
@ -991,7 +1012,8 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
{
if (configuration->savedSession && configuration->savedSessionTime > 0)
{
if (Hal_getTimeInMs() < (configuration->savedSessionTime + configuration->sessionResumptionInterval * 1000))
if (Hal_getTimeInMs() <
(configuration->savedSessionTime + configuration->sessionResumptionInterval * 1000))
{
ret = mbedtls_ssl_set_session(&(self->ssl), configuration->savedSession);
@ -1014,11 +1036,11 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
}
}
while( (ret = mbedtls_ssl_handshake(&(self->ssl)) ) != 0 )
while ((ret = mbedtls_ssl_handshake(&(self->ssl))) != 0)
{
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", "handshake failed - mbedtls_ssl_handshake returned -0x%x\n", -ret );
DEBUG_PRINT("TLS", "handshake failed - mbedtls_ssl_handshake returned -0x%x\n", -ret);
uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl));
@ -1026,7 +1048,8 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
mbedtls_ssl_free(&(self->ssl));
if (self->peerCert) {
if (self->peerCert)
{
GLOBAL_FREEMEM(self->peerCert);
}
@ -1066,11 +1089,6 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
self->lastRenegotiationTime = Hal_getTimeInMs();
// MIGRATE 2.28->3.x.x: impossible since mbedtls 3.x.x doesn't support insecure TLS versions
// if (getTLSVersion(self->ssl.major_ver, self->ssl.minor_ver) < TLS_VERSION_TLS_1_2) {
// raiseSecurityEvent(configuration, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self);
// }
/* create event that TLS session is established */
{
char msg[256];
@ -1103,21 +1121,19 @@ TLSSocket_performHandshake(TLSSocket self)
if (ret == 0 || ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS || ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
{
// MIGRATE 2.28->3.x.x: impossible since mbedtls 3.x.x doesn't support insecure TLS versions
// if (getTLSVersion(self->ssl.major_ver, self->ssl.minor_ver) < TLS_VERSION_TLS_1_2) {
// raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self);
// }
return true;
}
else {
else
{
DEBUG_PRINT("TLS", "TLSSocket_performHandshake failed -> ret=%i\n", ret);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Alarm: Renegotiation failed", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION,
"Alarm: Renegotiation failed", self);
/* mbedtls_ssl_renegotiate mandates to reset the ssl session in case of errors */
ret = mbedtls_ssl_session_reset(&(self->ssl));
if (ret != 0) {
if (ret != 0)
{
DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -> ret: -0x%X\n", -ret);
}
@ -1133,7 +1149,7 @@ checkForCRLUpdate(TLSSocket self)
DEBUG_PRINT("TLS", "CRL updated -> refresh CA chain\n");
mbedtls_ssl_conf_ca_chain( &(self->conf), &( self->tlsConfig->cacerts), &( self->tlsConfig->crl) );
mbedtls_ssl_conf_ca_chain(&(self->conf), &(self->tlsConfig->cacerts), &(self->tlsConfig->crl));
self->crlUpdated = self->tlsConfig->crlUpdated;
@ -1148,18 +1164,29 @@ startRenegotiationIfRequired(TLSSocket self)
if (self->tlsConfig->renegotiationTimeInMs <= 0)
return true;
if (self->lastRenegotiationTime == UINT64_MAX)
return true;
if (TLSConnection_getTLSVersion((TLSConnection)(self)) == TLS_VERSION_TLS_1_3)
{
self->lastRenegotiationTime = UINT64_MAX;
DEBUG_PRINT("TLS", "renegotiation not allowed for TLS 1.3\n");
return true;
}
if (Hal_getTimeInMs() <= self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs)
return true;
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Info: session renegotiation started", self);
raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION,
"Info: session renegotiation started", self);
if (TLSSocket_performHandshake(self) == false)
{
DEBUG_PRINT("TLS", " renegotiation failed\n");
DEBUG_PRINT("TLS", "renegotiation failed\n");
return false;
}
DEBUG_PRINT("TLS", " started renegotiation\n");
DEBUG_PRINT("TLS", "started renegotiation\n");
self->lastRenegotiationTime = Hal_getTimeInMs();
return true;
@ -1170,7 +1197,8 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size)
{
checkForCRLUpdate(self);
if (startRenegotiationIfRequired(self) == false) {
if (startRenegotiationIfRequired(self) == false)
{
return -1;
}
@ -1179,8 +1207,8 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size)
if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE))
return 0;
if (ret < 0) {
if (ret < 0)
{
switch (ret)
{
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
@ -1214,22 +1242,26 @@ TLSSocket_write(TLSSocket self, uint8_t* buf, int size)
checkForCRLUpdate(self);
if (startRenegotiationIfRequired(self) == false) {
if (startRenegotiationIfRequired(self) == false)
{
return -1;
}
while (len < size)
{
int ret = mbedtls_ssl_write(&(self->ssl), (buf + len), (size -len));
int ret = mbedtls_ssl_write(&(self->ssl), (buf + len), (size - len));
if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ||
(ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) || (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)) {
(ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) || (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS))
{
continue;
}
if (ret < 0) {
if (ret < 0)
{
DEBUG_PRINT("TLS", "mbedtls_ssl_write returned -0x%X\n", -ret);
if (0 != (ret = mbedtls_ssl_session_reset(&(self->ssl)))) {
if (0 != (ret = mbedtls_ssl_session_reset(&(self->ssl))))
{
DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -0x%X\n", -ret);
}
@ -1273,14 +1305,15 @@ TLSConnection_getPeerAddress(TLSConnection self, char* peerAddrBuf)
{
TLSSocket socket = (TLSSocket)self;
if (peerAddrBuf == NULL) {
if (peerAddrBuf == NULL)
{
peerAddrBuf = (char*)GLOBAL_MALLOC(61);
}
if (peerAddrBuf)
return Socket_getPeerAddressStatic(socket->socket, peerAddrBuf);
else
return NULL;
return NULL;
}
uint8_t*
@ -1295,17 +1328,18 @@ TLSConfigVersion
TLSConnection_getTLSVersion(TLSConnection self)
{
TLSSocket socket = (TLSSocket)self;
// MIGRATE 2.28->3.x.x: https://github.com/Mbed-TLS/mbedtls/blob/development/docs/3.0-migration-guide.md#most-structure-fields-are-now-private
mbedtls_ssl_protocol_version version = mbedtls_ssl_get_version_number(&(socket->ssl));
switch(version) {
case MBEDTLS_SSL_VERSION_TLS1_2:
return TLS_VERSION_TLS_1_2;
case MBEDTLS_SSL_VERSION_TLS1_3:
return TLS_VERSION_TLS_1_3;
case MBEDTLS_SSL_VERSION_UNKNOWN:
default:
return TLS_VERSION_NOT_SELECTED;
switch (version)
{
case MBEDTLS_SSL_VERSION_TLS1_2:
return TLS_VERSION_TLS_1_2;
case MBEDTLS_SSL_VERSION_TLS1_3:
return TLS_VERSION_TLS_1_3;
case MBEDTLS_SSL_VERSION_UNKNOWN:
default:
return TLS_VERSION_NOT_SELECTED;
}
}
@ -1314,19 +1348,19 @@ TLSConfigVersion_toString(TLSConfigVersion version)
{
switch (version)
{
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
case TLS_VERSION_SSL_3_0:
return "SSL 3.0";
case TLS_VERSION_TLS_1_0:
return "TLS 1.0";
case TLS_VERSION_TLS_1_1:
return "TLS 1.1";
/* Up until here (MIGRATE 2.28->3.x.x) */
case TLS_VERSION_TLS_1_2:
return "TLS 1.2";
case TLS_VERSION_TLS_1_3:
return "TLS 1.3";
default:
return "unknown TLS version";
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
case TLS_VERSION_SSL_3_0:
return "SSL 3.0";
case TLS_VERSION_TLS_1_0:
return "TLS 1.0";
case TLS_VERSION_TLS_1_1:
return "TLS 1.1";
/* Up until here (MIGRATE 2.28->3.x.x) */
case TLS_VERSION_TLS_1_2:
return "TLS 1.2";
case TLS_VERSION_TLS_1_3:
return "TLS 1.3";
default:
return "unknown TLS version";
}
}

Loading…
Cancel
Save