- 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 * socket_hal.h
* *
* Copyright 2013-2022 Michael Zillgith * Copyright 2013-2024 Michael Zillgith
* *
* This file is part of Platform Abstraction Layer (libpal) * This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870. * for libiec61850, libmms, and lib60870.

@ -1,7 +1,7 @@
/* /*
* time.c * time.c
* *
* Copyright 2013-2022 Michael Zillgith * Copyright 2013-2024 Michael Zillgith
* *
* This file is part of Platform Abstraction Layer (libpal) * This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870. * for libiec61850, libmms, and lib60870.
@ -68,6 +68,22 @@ Hal_getTimeInNs(void);
PAL_API bool PAL_API bool
Hal_setTimeInNs(nsSinceEpoch nsTime); 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); free(memb);
} }

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

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

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

@ -1,7 +1,7 @@
/* /*
* time.c * time.c
* *
* Copyright 2013-2021 Michael Zillgith * Copyright 2013-2024 Michael Zillgith
* *
* This file is part of Platform Abstraction Layer (libpal) * This file is part of Platform Abstraction Layer (libpal)
* for libiec61850, libmms, and lib60870. * for libiec61850, libmms, and lib60870.
@ -62,4 +62,36 @@ Hal_setTimeInNs(nsSinceEpoch nsTime)
return true; 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 #endif

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

@ -11,23 +11,21 @@
#include <string.h> #include <string.h>
#include "tls_socket.h"
#include "hal_thread.h" #include "hal_thread.h"
#include "lib_memory.h"
#include "hal_time.h" #include "hal_time.h"
#include "lib_memory.h"
#include "linked_list.h" #include "linked_list.h"
#include "tls_socket.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.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/entropy.h"
// #include "mbedtls/certs.h" (MIGRATE 2.28->3.x.x) #include "mbedtls/platform.h"
#include "mbedtls/x509.h"
#include "mbedtls/ssl.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.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/ssl_cache.h"
#include "mbedtls/x509.h"
#define SEC_EVENT_ALARM 2 #define SEC_EVENT_ALARM 2
#define SEC_EVENT_WARNING 1 #define SEC_EVENT_WARNING 1
@ -38,14 +36,18 @@
#endif #endif
#if (CONFIG_DEBUG_TLS == 1) #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 #else
#define DEBUG_PRINT(fmt, ...) do {} while(0) #define DEBUG_PRINT(fmt, ...) \
do \
{ \
} while (0)
#endif #endif
static int psaInitCounter = 0; static int psaInitCounter = 0;
struct sTLSConfiguration { struct sTLSConfiguration
{
mbedtls_entropy_context entropy; mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ctr_drbg_context ctr_drbg;
@ -73,11 +75,9 @@ struct sTLSConfiguration {
/* TLS session renegotiation interval in milliseconds */ /* TLS session renegotiation interval in milliseconds */
int renegotiationTimeInMs; 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) */ /* TLS minimum version allowed (default: TLS_VERSION_TLS_1_2) */
TLSConfigVersion minVersion; TLSConfigVersion minVersion;
// MIGRATE 2.28->3.x.x: Kept the max version but changed documentation
/* TLS maximum version allowed (default: TLS_VERSION_NOT_SELECTED) */ /* TLS maximum version allowed (default: TLS_VERSION_NOT_SELECTED) */
TLSConfigVersion maxVersion; TLSConfigVersion maxVersion;
@ -96,7 +96,8 @@ struct sTLSConfiguration {
int maxCiphersuites; int maxCiphersuites;
}; };
struct sTLSSocket { struct sTLSSocket
{
mbedtls_ssl_context ssl; mbedtls_ssl_context ssl;
Socket socket; Socket socket;
mbedtls_ssl_config conf; mbedtls_ssl_config conf;
@ -113,20 +114,21 @@ struct sTLSSocket {
}; };
static void 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); config->eventHandler(config->eventHandlerParameter, eventCategory, eventCode, message, (TLSConnection)socket);
} }
} }
static bool 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 &&
if (crt1 != NULL && crt2 != NULL && memcmp(crt1->raw.p, crt2->raw.p, crt1->raw.len) == 0)
crt1->raw.len == crt2->raw.len && {
memcmp(crt1->raw.p, crt2->raw.p, crt1->raw.len) == 0) {
return true; return true;
} }
@ -134,9 +136,9 @@ compareCertificates(mbedtls_x509_crt *crt1, mbedtls_x509_crt *crt2)
} }
static int 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); 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) 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"); DEBUG_PRINT("TLS", "Compare With:\n");
mbedtls_x509_crt_info(buffer, 1023, " ", allowedCert); mbedtls_x509_crt_info(buffer, 1023, " ", allowedCert);
@ -188,7 +190,8 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
} }
else 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; *flags |= MBEDTLS_X509_BADCERT_OTHER;
return 1; return 1;
@ -201,28 +204,32 @@ verifyCertificate (void* parameter, mbedtls_x509_crt *crt, int certificate_depth
{ {
*flags = *flags - MBEDTLS_X509_BADCERT_EXPIRED; *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) if (*flags & MBEDTLS_X509_BADCRL_EXPIRED)
{ {
*flags = *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) if (*flags & MBEDTLS_X509_BADCERT_FUTURE)
{ {
*flags = *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) if (*flags & MBEDTLS_X509_BADCRL_FUTURE)
{ {
*flags = *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) if (*flags == 0)
{ {
self->peerCertLength = 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) if (self->peerCert)
{ {
@ -253,13 +260,14 @@ TLSConfiguration_setupComplete(TLSConfiguration self)
{ {
if (self->setupComplete == false) 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) 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); DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned -0x%x\n", -ret);
return false; return false;
} }
@ -267,19 +275,17 @@ TLSConfiguration_setupComplete(TLSConfiguration self)
if (self->useSessionResumption) 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 else
{ {
mbedtls_ssl_cache_init( &(self->cache) ); 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_set_timeout(&(self->cache), self->sessionResumptionInterval); mbedtls_ssl_cache_set_timeout(&(self->cache), self->sessionResumptionInterval);
mbedtls_ssl_conf_session_cache( &(self->conf), &(self->cache), mbedtls_ssl_conf_session_cache(&(self->conf), &(self->cache), mbedtls_ssl_cache_get,
mbedtls_ssl_cache_get, mbedtls_ssl_cache_set);
mbedtls_ssl_cache_set );
} }
} }
@ -344,31 +350,36 @@ TLSConfiguration_clearCipherSuiteList(TLSConfiguration self)
TLSConfiguration TLSConfiguration
TLSConfiguration_create() TLSConfiguration_create()
{ {
TLSConfiguration self = (TLSConfiguration) GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration)); TLSConfiguration self = (TLSConfiguration)GLOBAL_CALLOC(1, sizeof(struct sTLSConfiguration));
if (self) if (self)
{ {
/* call to psa_crypto_init required -> see https://github.com/Mbed-TLS/mbedtls/issues/9223 */ /* 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++; psaInitCounter++;
mbedtls_ssl_config_init( &(self->conf) ); mbedtls_ssl_config_init(&(self->conf));
mbedtls_x509_crt_init( &(self->ownCertificate) ); mbedtls_x509_crt_init(&(self->ownCertificate));
mbedtls_x509_crt_init( &(self->cacerts) ); mbedtls_x509_crt_init(&(self->cacerts));
mbedtls_x509_crl_init( &(self->crl) ); mbedtls_x509_crl_init(&(self->crl));
mbedtls_pk_init( &(self->ownKey) ); mbedtls_pk_init(&(self->ownKey));
mbedtls_entropy_init( &(self->entropy) ); mbedtls_entropy_init(&(self->entropy));
mbedtls_ctr_drbg_init( &(self->ctr_drbg) ); mbedtls_ctr_drbg_init(&(self->ctr_drbg));
/* WARINING is fixed to server! */ /* WARINING is fixed to server! */
mbedtls_ssl_config_defaults( &(self->conf), mbedtls_ssl_config_defaults(&(self->conf), MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_PRESET_DEFAULT);
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT );
mbedtls_ctr_drbg_seed( &(self->ctr_drbg), mbedtls_entropy_func, &(self->entropy), NULL, 0); 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_rng(&(self->conf), mbedtls_ctr_drbg_random, &(self->ctr_drbg));
mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
@ -408,13 +419,15 @@ TLSConfiguration_create()
/* mandatory cipher suites by IEC 62351-4:2018 */ /* mandatory cipher suites by IEC 62351-4:2018 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256; 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_DHE_RSA_WITH_AES_128_GCM_SHA256;
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_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 */ /* 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_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_128_GCM_SHA256;
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; 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; self->ciphersuites[cipherIndex++] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
/* TLS 1.3 cipher suites */ /* TLS 1.3 cipher suites */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_128_GCM_SHA256; /* mandatory according IEC 62351-3:2023 */ self->ciphersuites[cipherIndex++] =
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_256_GCM_SHA384; /* mandatory according IEC 62351-3:2023 */ MBEDTLS_TLS1_3_AES_128_GCM_SHA256; /* mandatory according IEC 62351-3:2023 */
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256; /* optional according IEC 62351-3:2023 */ self->ciphersuites[cipherIndex++] =
self->ciphersuites[cipherIndex++] = MBEDTLS_TLS1_3_AES_128_CCM_SHA256; /* mandatory according IEC 62351-3:2023 */ MBEDTLS_TLS1_3_AES_256_GCM_SHA384; /* 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_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 */
} }
} }
@ -516,9 +534,9 @@ TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self, const char* fi
bool bool
TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword) TLSConfiguration_setOwnKey(TLSConfiguration self, uint8_t* key, int keyLen, const char* keyPassword)
{ {
// 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 int ret = mbedtls_pk_parse_key(&(self->ownKey), key, keyLen, (const uint8_t*)keyPassword,
// MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create (keyPassword == NULL) ? 0 : strlen(keyPassword), mbedtls_ctr_drbg_random,
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)); &(self->ctr_drbg));
if (ret != 0) if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_pk_parse_key returned -0x%x\n", -ret); 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 bool
TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename, const char* keyPassword) 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 int ret =
// MIGRATE 2.28->3.x.x: drbg needs to be initialized, but it seems to be done in TLSConfiguration_create 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) if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_pk_parse_keyfile returned -0x%x\n", -ret); DEBUG_PRINT("TLS", "mbedtls_pk_parse_keyfile returned -0x%x\n", -ret);
@ -542,7 +559,7 @@ TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self, const char* filename,
bool bool
TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certificate, int certLen) 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); int ret = mbedtls_x509_crt_parse(cert, certificate, certLen);
@ -561,7 +578,7 @@ TLSConfiguration_addAllowedCertificate(TLSConfiguration self, uint8_t* certifica
bool bool
TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self, const char* filename) 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); int ret = mbedtls_x509_crt_parse_file(cert, filename);
@ -622,10 +639,12 @@ TLSConfiguration_addCRL(TLSConfiguration self, uint8_t* crl, int crlLen)
{ {
int ret = mbedtls_x509_crl_parse(&(self->crl), crl, 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); DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse returned -0x%x\n", -ret);
} }
else { else
{
udpatedCRL(self); udpatedCRL(self);
} }
@ -637,10 +656,12 @@ 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); DEBUG_PRINT("TLS", "mbedtls_x509_crl_parse_file returned %d\n", ret);
} }
else { else
{
udpatedCRL(self); udpatedCRL(self);
} }
@ -694,7 +715,7 @@ TLSConfiguration_destroy(TLSConfiguration self)
while (certElem) 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); mbedtls_x509_crt_free(cert);
@ -720,111 +741,136 @@ createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket
if (config->eventHandler == NULL) if (config->eventHandler == NULL)
return; return;
switch (ret) { switch (ret)
{
case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG: 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; 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 // 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) // 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); // raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_NO_CIPHER, "Alarm: no matching TLS
// break; // ciphers", socket); break;
// case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: (MIGRATE 2.28->3.x.x) // 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); // raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_ALGO_NOT_SUPPORTED, "Alarm: Algorithm
// break; // not supported", socket); break;
case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE: 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; break;
// case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: (MIGRATE 2.28->3.x.x) // 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); // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_UNSECURE_COMMUNICATION, "Alarm:
// break; // Unsecure communication", socket); break;
case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE: 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; break;
// case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: (MIGRATE 2.28->3.x.x) // 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); // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_BAD_CERT, "Alarm: Bad certificate",
// break; // socket); break;
case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL: 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; break;
// MIGRATE 2.28->3.x.x: the removal of this is undocumented TODO: Verify migration path // 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) // 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); // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_VALIDATION_FAILED, "Alarm:
// break; // 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) // MIGRATE 2.28->3.x.x: the removal of this is undocumented. The docs say migrating users are affected but don't
// case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED: // provide a migration path TODO: Verify migration path (MIGRATE 2.28->3.x.x) case
// raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Alarm: Certificate required", socket); // MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED:
// break; // raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REQUIRED, "Alarm: Certificate
// required", socket); break;
case MBEDTLS_ERR_SSL_DECODE_ERROR: 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; break;
case MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER: 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; break;
case MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION: 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; break;
case MBEDTLS_ERR_SSL_BAD_CERTIFICATE: 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; break;
case MBEDTLS_ERR_SSL_UNRECOGNIZED_NAME: 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; break;
case MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION: 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; break;
case MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL: 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; break;
case MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE: 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; break;
case MBEDTLS_ERR_SSL_INTERNAL_ERROR: 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; 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,
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_EXPIRED, "Alarm: expired certificate", socket); "Alarm: expired certificate", socket);
} }
else if (flags & MBEDTLS_X509_BADCERT_REVOKED) { else if (flags & MBEDTLS_X509_BADCERT_REVOKED)
raiseSecurityEvent(config,TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED, "Alarm: revoked certificate", socket); {
raiseSecurityEvent(config, TLS_SEC_EVT_INCIDENT, TLS_EVENT_CODE_ALM_CERT_REVOKED,
"Alarm: revoked certificate", socket);
} }
else if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) { 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); {
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) { 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); {
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) { 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_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_VALIDATION_FAILED,
"Alarm: Certificate verification failed", socket);
} }
break; break;
default: 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; break;
} }
} }
@ -832,7 +878,7 @@ createSecurityEvents(TLSConfiguration config, int ret, uint32_t flags, TLSSocket
static int static int
readFunction(void* ctx, unsigned char* buf, size_t len) 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)) if ((ret == 0) && (len > 0))
{ {
@ -855,37 +901,11 @@ writeFunction(void* ctx, unsigned char* buf, size_t len)
return ret; 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 static int
getMajorVersion(TLSConfigVersion version) getMajorVersion(TLSConfigVersion version)
{ {
switch(version) { switch (version)
{
case TLS_VERSION_NOT_SELECTED: case TLS_VERSION_NOT_SELECTED:
return 0; return 0;
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
@ -904,7 +924,8 @@ getMajorVersion(TLSConfigVersion version)
static int static int
getMinorVersion(TLSConfigVersion version) getMinorVersion(TLSConfigVersion version)
{ {
switch(version) { switch (version)
{
case TLS_VERSION_NOT_SELECTED: case TLS_VERSION_NOT_SELECTED:
return 0; return 0;
/* TODO: Remove from here (MIGRATE 2.28->3.x.x) */ /* TODO: Remove from here (MIGRATE 2.28->3.x.x) */
@ -927,7 +948,7 @@ getMinorVersion(TLSConfigVersion version)
TLSSocket TLSSocket
TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClientCert) 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) if (self)
{ {
@ -941,11 +962,11 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
memcpy(&(self->conf), &(configuration->conf), sizeof(mbedtls_ssl_config)); 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; 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; self->crlUpdated = configuration->crlUpdated;
@ -956,7 +977,7 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
int majorVer = getMajorVersion(configuration->minVersion); int majorVer = getMajorVersion(configuration->minVersion);
int minorVer = getMinorVersion(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) 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 majorVer = getMajorVersion(configuration->maxVersion);
int minorVer = getMinorVersion(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) 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) if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_ssl_conf_own_cert returned %d\n", ret); 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) if (ret != 0)
DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret); DEBUG_PRINT("TLS", "mbedtls_ssl_setup returned %d\n", ret);
mbedtls_ssl_set_bio(&(self->ssl), socket, (mbedtls_ssl_send_t*) writeFunction, mbedtls_ssl_set_bio(&(self->ssl), socket, (mbedtls_ssl_send_t*)writeFunction, (mbedtls_ssl_recv_t*)readFunction,
(mbedtls_ssl_recv_t*) readFunction, NULL); NULL);
if (configuration->useSessionResumption) if (configuration->useSessionResumption)
{ {
@ -991,7 +1012,8 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
{ {
if (configuration->savedSession && configuration->savedSessionTime > 0) 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); 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)); 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)); mbedtls_ssl_free(&(self->ssl));
if (self->peerCert) { if (self->peerCert)
{
GLOBAL_FREEMEM(self->peerCert); GLOBAL_FREEMEM(self->peerCert);
} }
@ -1066,11 +1089,6 @@ TLSSocket_create(Socket socket, TLSConfiguration configuration, bool storeClient
self->lastRenegotiationTime = Hal_getTimeInMs(); 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 */ /* create event that TLS session is established */
{ {
char msg[256]; 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 || 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) 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; return true;
} }
else { else
{
DEBUG_PRINT("TLS", "TLSSocket_performHandshake failed -> ret=%i\n", ret); 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 */ /* mbedtls_ssl_renegotiate mandates to reset the ssl session in case of errors */
ret = mbedtls_ssl_session_reset(&(self->ssl)); 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); 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"); 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; self->crlUpdated = self->tlsConfig->crlUpdated;
@ -1148,18 +1164,29 @@ startRenegotiationIfRequired(TLSSocket self)
if (self->tlsConfig->renegotiationTimeInMs <= 0) if (self->tlsConfig->renegotiationTimeInMs <= 0)
return true; 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) if (Hal_getTimeInMs() <= self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs)
return true; 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) if (TLSSocket_performHandshake(self) == false)
{ {
DEBUG_PRINT("TLS", " renegotiation failed\n"); DEBUG_PRINT("TLS", "renegotiation failed\n");
return false; return false;
} }
DEBUG_PRINT("TLS", " started renegotiation\n"); DEBUG_PRINT("TLS", "started renegotiation\n");
self->lastRenegotiationTime = Hal_getTimeInMs(); self->lastRenegotiationTime = Hal_getTimeInMs();
return true; return true;
@ -1170,7 +1197,8 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size)
{ {
checkForCRLUpdate(self); checkForCRLUpdate(self);
if (startRenegotiationIfRequired(self) == false) { if (startRenegotiationIfRequired(self) == false)
{
return -1; 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)) if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE))
return 0; return 0;
if (ret < 0) { if (ret < 0)
{
switch (ret) switch (ret)
{ {
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
@ -1214,22 +1242,26 @@ TLSSocket_write(TLSSocket self, uint8_t* buf, int size)
checkForCRLUpdate(self); checkForCRLUpdate(self);
if (startRenegotiationIfRequired(self) == false) { if (startRenegotiationIfRequired(self) == false)
{
return -1; return -1;
} }
while (len < size) 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) || 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; continue;
} }
if (ret < 0) { if (ret < 0)
{
DEBUG_PRINT("TLS", "mbedtls_ssl_write returned -0x%X\n", -ret); 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); DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -0x%X\n", -ret);
} }
@ -1273,7 +1305,8 @@ TLSConnection_getPeerAddress(TLSConnection self, char* peerAddrBuf)
{ {
TLSSocket socket = (TLSSocket)self; TLSSocket socket = (TLSSocket)self;
if (peerAddrBuf == NULL) { if (peerAddrBuf == NULL)
{
peerAddrBuf = (char*)GLOBAL_MALLOC(61); peerAddrBuf = (char*)GLOBAL_MALLOC(61);
} }
@ -1295,10 +1328,11 @@ TLSConfigVersion
TLSConnection_getTLSVersion(TLSConnection self) TLSConnection_getTLSVersion(TLSConnection self)
{ {
TLSSocket socket = (TLSSocket)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)); mbedtls_ssl_protocol_version version = mbedtls_ssl_get_version_number(&(socket->ssl));
switch(version) { switch (version)
{
case MBEDTLS_SSL_VERSION_TLS1_2: case MBEDTLS_SSL_VERSION_TLS1_2:
return TLS_VERSION_TLS_1_2; return TLS_VERSION_TLS_1_2;
case MBEDTLS_SSL_VERSION_TLS1_3: case MBEDTLS_SSL_VERSION_TLS1_3:

Loading…
Cancel
Save