From 59b3772d5ac714f6de85c964ca3f15ae2c6aaafa Mon Sep 17 00:00:00 2001 From: timerix Date: Tue, 2 Jan 2024 23:30:25 +0600 Subject: [PATCH] udp implementation --- src/Network/network.c | 3 +- src/Network/network.h | 9 --- src/Network/network_internal.h | 32 +++++++++ src/Network/network_types.h | 90 +++++++++++++------------ src/Network/sockets/knSocketChanneled.c | 3 +- src/Network/sockets/knSocketTCP.c | 52 +++++++------- src/Network/sockets/knSocketTCP.h | 14 ++-- src/Network/sockets/knSocketUDP.c | 59 ++++++++++++++-- src/Network/sockets/knSocketUDP.h | 25 +++---- tests/test_network.c | 4 +- 10 files changed, 182 insertions(+), 109 deletions(-) create mode 100644 src/Network/network_internal.h diff --git a/src/Network/network.c b/src/Network/network.c index 62cd751..8c28330 100644 --- a/src/Network/network.c +++ b/src/Network/network.c @@ -1,5 +1,4 @@ -#include "network.h" -#include "socket_impl_includes.h" +#include "network_internal.h" Maybe kn_tryInit(){ #if _WIN32 diff --git a/src/Network/network.h b/src/Network/network.h index d55ae0c..109d00d 100644 --- a/src/Network/network.h +++ b/src/Network/network.h @@ -14,15 +14,6 @@ extern "C" { Maybe kn_tryInit(); Maybe kt_tryDispose(); - - -/* INTERNAL */ - -/// shutdown TCP/UDP/other std socket -Maybe __kn_StdSocket_shutdown(i64 socketfd, knShutdownType direction); -/// close TCP/UDP/other std socket -Maybe __kn_StdSocket_close(i64 socketfd); - #if __cplusplus } #endif diff --git a/src/Network/network_internal.h b/src/Network/network_internal.h new file mode 100644 index 0000000..c7ea12e --- /dev/null +++ b/src/Network/network_internal.h @@ -0,0 +1,32 @@ +#pragma once + +#if __cplusplus +extern "C" { +#endif + +#include "network.h" +#include "socket_impl_includes.h" + +/// shutdown TCP/UDP/other std socket +Maybe __kn_StdSocket_shutdown(i64 socketfd, knShutdownType direction); + +/// close TCP/UDP/other std socket +Maybe __kn_StdSocket_close(i64 socketfd); + +static inline struct sockaddr_in knIPV4Endpoint_toSockaddr(knIPV4Endpoint end){ + struct sockaddr_in saddr = {0}; + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = end.address.UintBigEndian; + saddr.sin_port = htons(end.port); /* transforms port number to big endian (network order) */ + return saddr; +} + +static inline knIPV4Endpoint knIPV4Endpoint_fromSockaddr(struct sockaddr_in saddr_ptr){ + knIPV4Address ipv4 = knIPV4Address_fromU32(saddr_ptr.sin_addr.s_addr); + u16 port = ntohs(saddr_ptr.sin_port); /* transforms port number to little endian (normal order) */ + return knIPV4Endpoint_create(ipv4, port); +} + +#if __cplusplus +} +#endif diff --git a/src/Network/network_types.h b/src/Network/network_types.h index 756a46a..29fdb75 100644 --- a/src/Network/network_types.h +++ b/src/Network/network_types.h @@ -1,45 +1,47 @@ -#pragma once - -#if __cplusplus -extern "C" { -#endif - -#include "../base/base.h" - - -typedef u16 knPort; - -typedef union knIPV4Address { - u32 UintBigEndian; - char bytes[4]; -} knIPV4Address; -ktid_declare(knIPV4Address); - -#define knIPV4Address_fromBytes(A, B, C, D) ((knIPV4Address){.bytes={A,B,C,D}}) -#define knIPV4Address_fromU32(N) ((knIPV4Address){.UintBigEndian=N}) - -///@return Maybe as Maybe -Maybe knIPV4Address_fromStr(char* addrStr); - -#define IPV4_NONE knIPV4Address_fromBytes(255,255,255,255) -#define IPV4_ANY knIPV4Address_fromBytes(0,0,0,0) -#define IPV4_LOOPBACK knIPV4Address_fromBytes(127,0,0,1) - - -typedef struct knIPV4Endpoint { - knIPV4Address address; - knPort port; -} knIPV4Endpoint; -ktid_declare(knIPV4Endpoint); - -#define knIPV4Endpoint_create(ADDR, PORT) ((knIPV4Endpoint){ADDR, PORT}) - -typedef enum knShutdownType { - knShutdownType_Receive = 0, - knShutdownType_Send = 1, - knShutdownType_Both = 2, -} knShutdownType; - -#if __cplusplus -} +#pragma once + +#if __cplusplus +extern "C" { +#endif + +#include "../base/base.h" + + +typedef u16 knPort; + +typedef union knIPV4Address { + u32 UintBigEndian; + char bytes[4]; +} knIPV4Address; +ktid_declare(knIPV4Address); + +#define knIPV4Address_fromBytes(A, B, C, D) ((knIPV4Address){.bytes={A,B,C,D}}) +#define knIPV4Address_fromU32(N) ((knIPV4Address){.UintBigEndian=N}) + +///@return Maybe as Maybe +Maybe knIPV4Address_fromStr(char* addrStr); + +#define knIPV4Address_INVALID knIPV4Address_fromBytes(255,255,255,255) +#define knIPV4Address_ANY knIPV4Address_fromBytes(0,0,0,0) +#define knIPV4Address_LOOPBACK knIPV4Address_fromBytes(127,0,0,1) + + +typedef struct knIPV4Endpoint { + knIPV4Address address; + knPort port; +} knIPV4Endpoint; +ktid_declare(knIPV4Endpoint); + +#define knIPV4Endpoint_create(ADDR, PORT) ((knIPV4Endpoint){ADDR, PORT}) + +#define knIPV4Endpoint_INVALID knIPV4Endpoint_create(knIPV4Address_INVALID, ~0) + +typedef enum knShutdownType { + knShutdownType_Receive = 0, + knShutdownType_Send = 1, + knShutdownType_Both = 2, +} knShutdownType; + +#if __cplusplus +} #endif \ No newline at end of file diff --git a/src/Network/sockets/knSocketChanneled.c b/src/Network/sockets/knSocketChanneled.c index 0d99969..77e55da 100644 --- a/src/Network/sockets/knSocketChanneled.c +++ b/src/Network/sockets/knSocketChanneled.c @@ -1,5 +1,4 @@ -#include "../network.h" -#include "../socket_impl_includes.h" +#include "../network_internal.h" ktid_define(knPackage); ktid_define(knPackageQueueElem); diff --git a/src/Network/sockets/knSocketTCP.c b/src/Network/sockets/knSocketTCP.c index f6e4259..43c12fe 100644 --- a/src/Network/sockets/knSocketTCP.c +++ b/src/Network/sockets/knSocketTCP.c @@ -1,11 +1,11 @@ -#include "../network.h" -#include "../socket_impl_includes.h" +#include "../network_internal.h" + ktid_define(knSocketTCP); Maybe knSocketTCP_open(bool allowReuse){ knSocketTCP* newSocket=malloc(sizeof(knSocketTCP)); - newSocket->localEndpoint=knIPV4Endpoint_create(IPV4_NONE,0); - newSocket->remoteEndpoint=knIPV4Endpoint_create(IPV4_NONE,0); + newSocket->localEndpoint=knIPV4Endpoint_INVALID; + newSocket->remoteEndpoint=knIPV4Endpoint_INVALID; newSocket->socketfd=socket(AF_INET, SOCK_STREAM, 0); if(newSocket->socketfd==-1 || newSocket->socketfd == ~0) safethrow("can't create socket", free(newSocket)); @@ -29,39 +29,37 @@ Maybe knSocketTCP_close(knSocketTCP* socket){ return MaybeNull; } -Maybe knSocketTCP_listen(knSocketTCP* socket, knIPV4Endpoint localEndp){ - struct sockaddr_in servaddr; - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = localEndp.address.UintBigEndian; - servaddr.sin_port = htons(localEndp.port); - int r = bind(socket->socketfd,(struct sockaddr*)&servaddr, sizeof(servaddr)); - if(r != 0) - safethrow("socket bind failed",;); - socket->localEndpoint=localEndp; +Maybe knSocketTCP_bindAndListen(knSocketTCP* socket, knIPV4Endpoint localEndp){ + struct sockaddr_in servaddr = knIPV4Endpoint_toSockaddr(localEndp); + + if(bind(socket->socketfd, (void*)&servaddr, sizeof(servaddr)) != 0) + safethrow("socket bind failed", ;); - r = listen(socket->socketfd, 1024); - if(r != 0) - safethrow("socket listen failed",;); + if(listen(socket->socketfd, 1024) != 0) + safethrow("socket listen failed", ;); + + socket->localEndpoint = localEndp; return MaybeNull; } -Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEndp){ - struct sockaddr_in servaddr; - servaddr.sin_family=AF_INET; - servaddr.sin_addr.s_addr = remoteEndp.address.UintBigEndian; - servaddr.sin_port = htons(remoteEndp.port); +Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEnd){ + struct sockaddr_in servaddr = knIPV4Endpoint_toSockaddr(remoteEnd); + if(connect(socket->socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) !=0) safethrow("socket connect failed",;); - socket->remoteEndpoint=remoteEndp; + + socket->remoteEndpoint=remoteEnd; return MaybeNull; } Maybe knSocketTCP_accept(knSocketTCP* socket){ struct sockaddr_in remoteAddr = {0}; u64 remoteAddrSize = sizeof(remoteAddr); + i64 client_fd = accept(socket->socketfd, (struct sockaddr*)&remoteAddr, (void*)&remoteAddrSize); if(client_fd == -1 || client_fd == ~0) safethrow("can't accept client connection", ;); + // if accept() didn't set remoteAddr for some reason if(remoteAddr.sin_addr.s_addr == 0 && remoteAddr.sin_port == 0 && remoteAddr.sin_family == 0){ if(getpeername(client_fd, (struct sockaddr*)&remoteAddr, (void*)&remoteAddrSize) != 0) @@ -71,16 +69,14 @@ Maybe knSocketTCP_accept(knSocketTCP* socket){ knSocketTCP* clientSocket = malloc(sizeof(knSocketTCP)); clientSocket->socketfd = client_fd; clientSocket->localEndpoint = socket->localEndpoint; - clientSocket->remoteEndpoint = knIPV4Endpoint_create( - knIPV4Address_fromU32(remoteAddr.sin_addr.s_addr), - remoteAddr.sin_port); + clientSocket->remoteEndpoint = knIPV4Endpoint_fromSockaddr(remoteAddr); return SUCCESS(UniHeapPtr(knSocketTCP, clientSocket)); } -Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength){ +Maybe knSocketTCP_send(knSocketTCP* socket, char* buffer, u32 dataLength){ u32 sentTotal = 0; while(sentTotal < dataLength){ - int sentCount = send(socket->socketfd, data+sentTotal, dataLength-sentTotal, 0); + int sentCount = send(socket->socketfd, buffer+sentTotal, dataLength-sentTotal, 0); if(sentCount == -1){ safethrow( cptr_concat("can't send ", toString_u64(dataLength-sentTotal,0,0), @@ -91,6 +87,7 @@ Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength){ } sentTotal += sentCount; } + return MaybeNull; } @@ -98,5 +95,6 @@ Maybe knSocketTCP_receive(knSocketTCP* socket, char* buffer, u32 bufferLength){ int receivedCount = recv(socket->socketfd, buffer, bufferLength, 0); if(receivedCount == -1 || receivedCount == 0) safethrow("can't receive data from socket", ;) + return SUCCESS(UniUInt64(receivedCount)); } diff --git a/src/Network/sockets/knSocketTCP.h b/src/Network/sockets/knSocketTCP.h index 86bc7ed..3f28134 100644 --- a/src/Network/sockets/knSocketTCP.h +++ b/src/Network/sockets/knSocketTCP.h @@ -28,21 +28,25 @@ Maybe knSocketTCP_shutdown(knSocketTCP* socket, knShutdownType direction); ///@return Maybe error or nothing Maybe knSocketTCP_close(knSocketTCP* socket); -///start listening at local endpoint +/// binds socket to a local endpoint and starts listening for incoming TCP connections ///@return Maybe error or nothing -Maybe knSocketTCP_listen(knSocketTCP* socket, knIPV4Endpoint localEndp); +Maybe knSocketTCP_bindAndListen(knSocketTCP* socket, knIPV4Endpoint localEndp); -///sets socket remote endpoint +/// establishes TCP connection with a remote endpoint ///@return Maybe error or nothing -Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEndp); +Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEnd); ///@return Maybe new socket connected to client Maybe knSocketTCP_accept(knSocketTCP* socket); +/// sends bytes from buffer +///@param buffer buffer for receiving data ///@param dataLength 0-4294967295 ///@return Maybe -Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength); +Maybe knSocketTCP_send(knSocketTCP* socket, char* buffer, u32 dataLength); +/// receives a package of any size +/// (by TCP 32 bytes han be sent as 32x1byte, 4x8byte, 32x1byte or in any other combination) ///@param buffer buffer for receiving data ///@param bufferLength 0-4294967295 ///@return Maybe received bytes amount diff --git a/src/Network/sockets/knSocketUDP.c b/src/Network/sockets/knSocketUDP.c index a4cc712..7a50c47 100644 --- a/src/Network/sockets/knSocketUDP.c +++ b/src/Network/sockets/knSocketUDP.c @@ -1,5 +1,5 @@ -#include "../network.h" -#include "../socket_impl_includes.h" +#include "../network_internal.h" + ktid_define(knSocketUDP); Maybe knSocketUDP_open(bool allowReuse){ @@ -28,10 +28,57 @@ Maybe knSocketUDP_close(knSocketUDP* socket){ return MaybeNull; } -Maybe knSocketUDP_listen(knSocketUDP* socket, knIPV4Endpoint localEndp); +Maybe knSocketUDP_bind(knSocketUDP* socket, knIPV4Endpoint localEndp){ + struct sockaddr_in servaddr = { + .sin_family = AF_INET, + .sin_addr.s_addr = localEndp.address.UintBigEndian, + .sin_port = htons(localEndp.port) /* transforms port to big endian */ + }; + + if(bind(socket->socketfd, (void*)&servaddr, sizeof(servaddr)) != 0) + safethrow("socket bind failed", ;); -Maybe knSocketUDP_accept(knSocketUDP* socket); + socket->localEndpoint = localEndp; + return MaybeNull; +} -Maybe knSocketUDP_sendto(knSocketUDP* socket, char* data, u32 dataLength, knIPV4Endpoint destination); +Maybe knSocketUDP_sendTo(knSocketUDP* socket, char* buffer, u32 dataLength, knIPV4Endpoint destEnd){ + struct sockaddr_in dest_saddr = knIPV4Endpoint_toSockaddr(destEnd); + u32 sentCount = sendto( + socket->socketfd, + buffer, + dataLength, + 0, + (struct sockaddr*)&dest_saddr, + sizeof(struct sockaddr_in) + ); + + if(sentCount != dataLength) { + safethrow( + cptr_concat("can't send ", toString_u64(dataLength-sentCount,0,0), + " bytes out of ", toString_u64(dataLength,0,0) + ), + ;); + } -Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); + return MaybeNull; +} + +Maybe knSocketUDP_receiveAny(knSocketUDP* socket, char* buffer, u32 bufferLength, knIPV4Endpoint* senderEnd){ + struct sockaddr_in remote_saddr = {0}; + u64 remote_saddr_size = sizeof(remote_saddr); + int receivedCount = recvfrom( + socket->socketfd, + buffer, + bufferLength, + 0, + (struct sockaddr*)&remote_saddr, + (void*)&remote_saddr_size + ); + + if(receivedCount == -1 || receivedCount == 0) + safethrow("can't receive data from socket", ;) + + *senderEnd = knIPV4Endpoint_fromSockaddr(remote_saddr); + return SUCCESS(UniUInt64(receivedCount)); +} diff --git a/src/Network/sockets/knSocketUDP.h b/src/Network/sockets/knSocketUDP.h index 4f5ec56..658ee50 100644 --- a/src/Network/sockets/knSocketUDP.h +++ b/src/Network/sockets/knSocketUDP.h @@ -27,22 +27,23 @@ Maybe knSocketUDP_shutdown(knSocketUDP* socket, knShutdownType direction); ///@return Maybe error or nothing Maybe knSocketUDP_close(knSocketUDP* socket); -///start listening at local endpoint +/// binds socket to a local endpoint ///@return Maybe error or nothing -Maybe knSocketUDP_listen(knSocketUDP* socket, knIPV4Endpoint localEndp); - -///@return Maybe new socket connected to client -Maybe knSocketUDP_accept(knSocketUDP* socket); - -///@param dataLength 0-4294967295 -///@return Maybe -Maybe knSocketUDP_sendto(knSocketUDP* socket, char* data, u32 dataLength, knIPV4Endpoint destination); +Maybe knSocketUDP_bind(knSocketUDP* socket, knIPV4Endpoint localEndp); +/// sends one package to destination endpoint ///@param buffer buffer for receiving data -///@param bufferLength 0-4294967295 -///@return Maybe received bytes amount -Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); +///@param dataLength 0-64k +///@param destEnd destination endpoint +///@return Maybe +Maybe knSocketUDP_sendTo(knSocketUDP* socket, char* buffer, u32 dataLength, knIPV4Endpoint destEnd); +/// receives one package from anywhere +///@param buffer buffer for receiving data +///@param bufferLength 0-64k +///@param senderEnd [OUT] endpoint UPD package was sent from +///@return Maybe received bytes amount +Maybe knSocketUDP_receiveAny(knSocketUDP* socket, char* buffer, u32 bufferLength, knIPV4Endpoint* senderEnd); #if __cplusplus } diff --git a/tests/test_network.c b/tests/test_network.c index b99edc4..6daa564 100644 --- a/tests/test_network.c +++ b/tests/test_network.c @@ -57,7 +57,7 @@ void* tcp_client_connect_async(void* _data){ static void test_tcp(){ kprintf("\e[96m----------[test_network/tcp]----------\n"); - knIPV4Endpoint serverEnd = knIPV4Endpoint_create(IPV4_LOOPBACK, 4444); + knIPV4Endpoint serverEnd = knIPV4Endpoint_create(knIPV4Address_LOOPBACK, 4444); knSocketTCP *socket_server, *clientConnection, *socket_client; // server { @@ -65,7 +65,7 @@ static void test_tcp(){ socket_server=m_socketS.value.VoidPtr; kprintf("\e[92mTCP server socket created\n"); - tryLast(knSocketTCP_listen(socket_server, serverEnd), _m81775, ;) + tryLast(knSocketTCP_bindAndListen(socket_server, serverEnd), _m81775, ;) kprintf("\e[92mserver socket is listening\n"); } // client