From f3eab207e85ba00d0dfe637631be0aa66f7dae7b Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sun, 30 Oct 2022 18:25:15 +0000 Subject: [PATCH] - added UDP socket functions to Macos socket interface implementatio (LIB61850-360) --- hal/socket/bsd/socket_bsd.c | 245 ++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/hal/socket/bsd/socket_bsd.c b/hal/socket/bsd/socket_bsd.c index 74fbc1e7..1d928559 100644 --- a/hal/socket/bsd/socket_bsd.c +++ b/hal/socket/bsd/socket_bsd.c @@ -10,6 +10,7 @@ #include "hal_socket.h" #include #include +#include #include #include #include @@ -32,6 +33,10 @@ #define DEBUG_SOCKET 0 #endif +#ifndef IPV6_ADD_MEMBERSHIP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif @@ -46,6 +51,11 @@ struct sServerSocket { int backLog; }; +struct sUdpSocket { + int fd; + int namespace; /* IPv4: AF_INET; IPv6: AF_INET6 */ +}; + struct sHandleSet { LinkedList sockets; bool pollfdIsUpdated; @@ -645,3 +655,238 @@ Socket_destroy(Socket self) GLOBAL_FREEMEM(self); } + +static UdpSocket +UdpSocket_createUsingNamespace(int namespace) +{ + UdpSocket self = NULL; + + int sock = socket(namespace, SOCK_DGRAM, IPPROTO_UDP); + + if (sock != -1) { + self = (UdpSocket) GLOBAL_MALLOC(sizeof(struct sSocket)); + + if (self) { + self->fd = sock; + self->namespace = namespace; + } + else { + if (DEBUG_SOCKET) + printf("SOCKET: failed to allocate memory\n"); + + close(sock); + } + } + else { + if (DEBUG_SOCKET) + printf("SOCKET: failed to create UDP socket (errno=%i)\n", errno); + } + + return self; +} + +UdpSocket +UdpSocket_create() +{ + return UdpSocket_createUsingNamespace(AF_INET); +} + +UdpSocket +UdpSocket_createIpV6() +{ + return UdpSocket_createUsingNamespace(AF_INET6); +} + +bool +UdpSocket_addGroupMembership(UdpSocket self, const char* multicastAddress) +{ + if (self->namespace == AF_INET) { + struct ip_mreq mreq; + + if (!inet_aton(multicastAddress, &(mreq.imr_multiaddr))) { + printf("SOCKET: Invalid IPv4 multicast address\n"); + return false; + } + else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(self->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { + printf("SOCKET: failed to set IPv4 multicast group (errno: %i)\n", errno); + return false; + } + + } + + return true; + } + else if (self->namespace == AF_INET6) { + struct ipv6_mreq mreq; + + if (inet_pton(AF_INET6, multicastAddress, &(mreq.ipv6mr_multiaddr)) < 1) { + printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno); + return false; + } + + mreq.ipv6mr_interface = 0; + + if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { + printf("SOCKET: failed to set IPv6 multicast group (errno: %i)\n", errno); + return false; + } + + return true; + } + + return false; +} + +bool +UdpSocket_setMulticastTtl(UdpSocket self, int ttl) +{ + if (self->namespace == AF_INET) { + if (setsockopt(self->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) { + printf("SOCKET: failed to set IPv4 multicast TTL (errno: %i)\n", errno); + return false; + } + + return true; + } + else if (self->namespace == AF_INET6) { + if (setsockopt(self->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) == -1) { + printf("SOCKET: failed to set IPv6 multicast TTL(hops) (errno: %i)\n", errno); + return false; + } + + return true; + } + + return false; +} + +bool +UdpSocket_bind(UdpSocket self, const char* address, int port) +{ + //TODO add support for IPv6 + struct sockaddr_in localAddress; + + if (!prepareAddress(address, port, &localAddress)) { + close(self->fd); + self->fd = 0; + return false; + } + + int result = bind(self->fd, (struct sockaddr*)&localAddress, sizeof(localAddress)); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to bind UDP socket (errno=%i)\n", errno); + + close(self->fd); + self->fd = 0; + + return false; + } + + return true; +} + +bool +UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize) +{ + //TODO add support for IPv6 + struct sockaddr_in remoteAddress; + + if (!prepareAddress(address, port, &remoteAddress)) { + + if (DEBUG_SOCKET) + printf("SOCKET: failed to lookup remote address %s\n", address); + + return false; + } + + int result = sendto(self->fd, msg, msgSize, 0, (struct sockaddr*)&remoteAddress, sizeof(remoteAddress)); + + if (result == msgSize) { + return true; + } + else if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to send UDP message (errno=%i)\n", errno); + } + else { + if (DEBUG_SOCKET) + printf("SOCKET: failed to send UDP message (insufficient data sent)\n"); + } + + return false; +} + +int +UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize) +{ + //TODO add support for IPv6 + struct sockaddr_storage remoteAddress; + + socklen_t structSize = sizeof(struct sockaddr_storage); + + int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize); + + if (result == -1) { + if (DEBUG_SOCKET) + printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno); + } + + if (address) { + bool isIPv6; + char addrString[INET6_ADDRSTRLEN + 7]; + int port; + + if (remoteAddress.ss_family == AF_INET) { + struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress; + port = ntohs(ipv4Addr->sin_port); + inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN); + isIPv6 = false; + } + else if (remoteAddress.ss_family == AF_INET6) { + struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress; + port = ntohs(ipv6Addr->sin6_port); + inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN); + isIPv6 = true; + } + else + return -1; + + if (isIPv6) + snprintf(address, maxAddrSize, "[%s]:%i", addrString, port); + else + snprintf(address, maxAddrSize, "%s:%i", addrString, port); + } + + if (address) { + bool isIPv6; + char addrString[INET6_ADDRSTRLEN + 7]; + int port; + + if (remoteAddress.ss_family == AF_INET) { + struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress; + port = ntohs(ipv4Addr->sin_port); + inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN); + isIPv6 = false; + } + else if (remoteAddress.ss_family == AF_INET6) { + struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress; + port = ntohs(ipv6Addr->sin6_port); + inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN); + isIPv6 = true; + } + else + return result; + + if (isIPv6) + snprintf(address, maxAddrSize, "[%s]:%i", addrString, port); + else + snprintf(address, maxAddrSize, "%s:%i", addrString, port); + } + + return result; +}