diff --git a/default.config b/default.config index d6baae4..6c654b0 100644 --- a/default.config +++ b/default.config @@ -37,12 +37,12 @@ case "$OS" in WINDOWS) EXEC_FILE="$PROJECT.exe" SHARED_LIB_FILE="$PROJECT.dll" - LINKER_LIBS="-lws2_32" + LINKER_LIBS="-lpthread -lws2_32" ;; LINUX) EXEC_FILE="$PROJECT" SHARED_LIB_FILE="$PROJECT.so" - LINKER_LIBS="" + LINKER_LIBS="-lpthread" ;; *) error "operating system $OS has no configuration variants" diff --git a/src/Network/network.c b/src/Network/network.c index 7f077cf..62cd751 100644 --- a/src/Network/network.c +++ b/src/Network/network.c @@ -28,7 +28,7 @@ Maybe kt_tryDispose(){ Maybe __kn_StdSocket_shutdown(i64 socketfd, knShutdownType direction){ - if(shutdown(socketfd, SD_SEND) == -1) + if(shutdown(socketfd, (int)direction) == -1) safethrow("can't shutdown socket", ;); return MaybeNull; } @@ -37,7 +37,7 @@ Maybe __kn_StdSocket_close(i64 socketfd){ #if KN_USE_WINSOCK if(closesocket(socketfd) == -1) #else - if(close(socket->socketfd) == -1) + if(close(socketfd) == -1) #endif safethrow("can't close socket", ;); diff --git a/src/Network/network.h b/src/Network/network.h index 836659d..d55ae0c 100644 --- a/src/Network/network.h +++ b/src/Network/network.h @@ -1,28 +1,28 @@ -#pragma once - -#if __cplusplus -extern "C" { -#endif - -#include "../base/base.h" - -#include "network_types.h" -#include "sockets/knSocketTCP.h" -#include "sockets/knSocketUDP.h" -#include "sockets/knSocketChanneled.h" - -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 +#pragma once + +#if __cplusplus +extern "C" { +#endif + +#include "../base/base.h" + +#include "network_types.h" +#include "sockets/knSocketTCP.h" +#include "sockets/knSocketUDP.h" +#include "sockets/knSocketChanneled.h" + +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/sockets/knSocketChanneled.c b/src/Network/sockets/knSocketChanneled.c index 4c0b5b9..0d99969 100644 --- a/src/Network/sockets/knSocketChanneled.c +++ b/src/Network/sockets/knSocketChanneled.c @@ -1,59 +1,59 @@ -#include "../network.h" -#include "../socket_impl_includes.h" - -ktid_define(knPackage); -ktid_define(knPackageQueueElem); -ktid_define(knChannel); -ktid_define(knSocketChanneled); - -Maybe knSocketChanneled_open(){ - knSocketChanneled* newSocket=malloc(sizeof(knSocketChanneled)); - newSocket->localEndpoint=knIPV4Endpoint_create(knIPV4Address_fromBytes(0,0,0,0),0); - newSocket->remoteEndpoint=newSocket->localEndpoint; - newSocket->channels=NULL; - newSocket->channelsAmount=0; - return SUCCESS(UniHeapPtr(knSocketChanneled, newSocket)); -} - -Maybe knSocketChanneled_close(knSocketChanneled* socket){ - int result= -#if KN_USE_WINSOCK - closesocket -#else - close -#endif - (socket->socketfd); - if(result==-1) { - safethrow("can't close socket",;); - } - else return MaybeNull; -} - -knChannel* __createChannel(){ - knChannel* ch=malloc(sizeof(knChannel)); - ch->queueStart=NULL; - return ch; -} - -Maybe knSocketChanneled_createChannel(knSocketChanneled* socket){ - if(socket->channelsAmount == 65535) - safethrow("max amount of channels",;); - u16 channelsAmountPrev=socket->channelsAmount; - socket->channelsAmount++; - if(channelsAmountPrev==0) - socket->channels=malloc(sizeof(knChannel*)); - else - socket->channels=realloc(socket->channels, socket->channelsAmount*sizeof(knChannel*)); - socket->channels[channelsAmountPrev]=__createChannel(); - return SUCCESS(UniUInt64(channelsAmountPrev)); -} - -Maybe knSocketChanneled_listen(knSocketChanneled* socket, knIPV4Endpoint localEndp); - -Maybe knSocketChanneled_connect(knSocketChanneled* socket, knIPV4Endpoint remoteEndp); - -Maybe knSocketChanneled_accept(knSocketChanneled* socket); - -Maybe knSocketChanneled_send(knSocketChanneled* socket, u16 destinationIndex, u8* data, u32 dataLength); - +#include "../network.h" +#include "../socket_impl_includes.h" + +ktid_define(knPackage); +ktid_define(knPackageQueueElem); +ktid_define(knChannel); +ktid_define(knSocketChanneled); + +Maybe knSocketChanneled_open(){ + knSocketChanneled* newSocket=malloc(sizeof(knSocketChanneled)); + newSocket->localEndpoint=knIPV4Endpoint_create(knIPV4Address_fromBytes(0,0,0,0),0); + newSocket->remoteEndpoint=newSocket->localEndpoint; + newSocket->channels=NULL; + newSocket->channelsAmount=0; + return SUCCESS(UniHeapPtr(knSocketChanneled, newSocket)); +} + +Maybe knSocketChanneled_close(knSocketChanneled* socket){ + int result= +#if KN_USE_WINSOCK + closesocket +#else + close +#endif + (socket->socketfd); + if(result==-1) { + safethrow("can't close socket",;); + } + else return MaybeNull; +} + +knChannel* __createChannel(){ + knChannel* ch=malloc(sizeof(knChannel)); + ch->queueStart=NULL; + return ch; +} + +Maybe knSocketChanneled_createChannel(knSocketChanneled* socket){ + if(socket->channelsAmount == 65535) + safethrow("max amount of channels",;); + u16 channelsAmountPrev=socket->channelsAmount; + socket->channelsAmount++; + if(channelsAmountPrev==0) + socket->channels=malloc(sizeof(knChannel*)); + else + socket->channels=realloc(socket->channels, socket->channelsAmount*sizeof(knChannel*)); + socket->channels[channelsAmountPrev]=__createChannel(); + return SUCCESS(UniUInt64(channelsAmountPrev)); +} + +Maybe knSocketChanneled_listen(knSocketChanneled* socket, knIPV4Endpoint localEndp); + +Maybe knSocketChanneled_connect(knSocketChanneled* socket, knIPV4Endpoint remoteEndp); + +Maybe knSocketChanneled_accept(knSocketChanneled* socket); + +Maybe knSocketChanneled_send(knSocketChanneled* socket, u16 destinationIndex, u8* data, u32 dataLength); + Maybe knSocketChanneled_receive(knSocketChanneled* socket, u16 destinationIndex, u8* buffer, u32 bufferLength); \ No newline at end of file diff --git a/src/Network/sockets/knSocketTCP.c b/src/Network/sockets/knSocketTCP.c index 6d16e12..f6e4259 100644 --- a/src/Network/sockets/knSocketTCP.c +++ b/src/Network/sockets/knSocketTCP.c @@ -1,97 +1,102 @@ -#include "../network.h" -#include "../socket_impl_includes.h" -ktid_define(knSocketTCP); - -Maybe knSocketTCP_open(){ - knSocketTCP* newSocket=malloc(sizeof(knSocketTCP)); - newSocket->localEndpoint=knIPV4Endpoint_create(IPV4_NONE,0); - newSocket->remoteEndpoint=newSocket->localEndpoint; - newSocket->socketfd=socket(AF_INET, SOCK_STREAM, 0); - if(newSocket->socketfd==-1 || newSocket->socketfd == ~0) - safethrow("can't create TCP socket", free(newSocket)); - - return SUCCESS(UniHeapPtr(knSocketTCP, newSocket)); -} - -Maybe knSocketTCP_shutdown(knSocketTCP* socket, knShutdownType direction){ - try(__kn_StdSocket_shutdown(socket->socketfd, direction), _m875, ;); - return MaybeNull; -} - -Maybe knSocketTCP_close(knSocketTCP* socket){ - try(__kn_StdSocket_close(socket->socketfd), _m875, ;); - socket->socketfd = 0; - socket->localEndpoint = knIPV4Endpoint_create(IPV4_NONE, -1); - socket->remoteEndpoint = knIPV4Endpoint_create(IPV4_NONE, -1); - 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); - if(bind(socket->socketfd,(struct sockaddr*)&servaddr, sizeof(servaddr)) !=0) - safethrow("socket bind failed",;); - socket->localEndpoint=localEndp; - if(listen(socket->socketfd, 256) !=0) - safethrow("socket listen failed",;); - 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); - if(connect(socket->socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) !=0) - safethrow("socket connect failed",;); - socket->remoteEndpoint=remoteEndp; - return MaybeNull; -} - -Maybe knSocketTCP_accept(knSocketTCP* socket){ - struct sockaddr_in remoteAddr = {0}; - int remoteAddrSize = sizeof(remoteAddr); - i64 client_fd = accept(socket->socketfd, (struct sockaddr*)&remoteAddr, &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, &remoteAddrSize) != 0) - safethrow("can't get connected client address", ;); - } - - 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); - return SUCCESS(UniHeapPtr(knSocketTCP, clientSocket)); -} - -Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength){ - u32 sentTotal = 0; - while(sentTotal < dataLength){ - int sentCount = send(socket->socketfd, data+sentTotal, dataLength-sentTotal, 0); - if(sentCount == -1){ - safethrow( - cptr_concat("can't send ", toString_u64(dataLength-sentTotal,0,0), - " bytes out of ", toString_u64(dataLength,0,0), - " at index ", toString_u64(sentTotal,0,0), - " to TCP socket" - ), - ;); - } - sentTotal += sentCount; - } - return MaybeNull; -} - -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 TCP socket", ;) - return SUCCESS(UniUInt64(receivedCount)); -} +#include "../network.h" +#include "../socket_impl_includes.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->socketfd=socket(AF_INET, SOCK_STREAM, 0); + if(newSocket->socketfd==-1 || newSocket->socketfd == ~0) + safethrow("can't create socket", free(newSocket)); + + // set value of REUSEADDR socket option + int opt_val = allowReuse; + if(setsockopt(newSocket->socketfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt_val, sizeof(opt_val)) != 0) + safethrow("can't set socket options", free(newSocket)); + + return SUCCESS(UniHeapPtr(knSocketTCP, newSocket)); +} + +Maybe knSocketTCP_shutdown(knSocketTCP* socket, knShutdownType direction){ + try(__kn_StdSocket_shutdown(socket->socketfd, direction), _m875, ;); + return MaybeNull; +} + +Maybe knSocketTCP_close(knSocketTCP* socket){ + try(__kn_StdSocket_close(socket->socketfd), _m875, ;); + free(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; + + r = listen(socket->socketfd, 1024); + if(r != 0) + safethrow("socket listen failed",;); + 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); + if(connect(socket->socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) !=0) + safethrow("socket connect failed",;); + socket->remoteEndpoint=remoteEndp; + 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) + safethrow("can't get connected client address", ;); + } + + 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); + return SUCCESS(UniHeapPtr(knSocketTCP, clientSocket)); +} + +Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength){ + u32 sentTotal = 0; + while(sentTotal < dataLength){ + int sentCount = send(socket->socketfd, data+sentTotal, dataLength-sentTotal, 0); + if(sentCount == -1){ + safethrow( + cptr_concat("can't send ", toString_u64(dataLength-sentTotal,0,0), + " bytes out of ", toString_u64(dataLength,0,0), + " at index ", toString_u64(sentTotal,0,0) + ), + ;); + } + sentTotal += sentCount; + } + return MaybeNull; +} + +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 fe8ef44..86bc7ed 100644 --- a/src/Network/sockets/knSocketTCP.h +++ b/src/Network/sockets/knSocketTCP.h @@ -1,49 +1,53 @@ -#pragma once - -#if __cplusplus -extern "C" { -#endif - -#include "../network_types.h" - -typedef struct knSocketTCP { - i64 socketfd; - knIPV4Endpoint localEndpoint; - knIPV4Endpoint remoteEndpoint; - // TODO socket status enum -} knSocketTCP; -ktid_declare(knSocketTCP); - -///@return Maybe new socket -Maybe knSocketTCP_open(); - -///@param direction receive/send/both -///@return Maybe error or nothing -Maybe knSocketTCP_shutdown(knSocketTCP* socket, knShutdownType direction); - -///@return Maybe error or nothing -Maybe knSocketTCP_close(knSocketTCP* socket); - -///start listening at local endpoint -///@return Maybe error or nothing -Maybe knSocketTCP_listen(knSocketTCP* socket, knIPV4Endpoint localEndp); - -///sets socket remote endpoint -///@return Maybe error or nothing -Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEndp); - -///@return Maybe new socket connected to client -Maybe knSocketTCP_accept(knSocketTCP* socket); - -///@param dataLength 0-4294967295 -///@return Maybe -Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength); - -///@param buffer buffer for receiving data -///@param bufferLength 0-4294967295 -///@return Maybe received bytes amount -Maybe knSocketTCP_receive(knSocketTCP* socket, char* buffer, u32 bufferLength); - -#if __cplusplus -} +#pragma once + +#if __cplusplus +extern "C" { +#endif + +#include "../network_types.h" + +typedef struct knSocketTCP { + i64 socketfd; + knIPV4Endpoint localEndpoint; + knIPV4Endpoint remoteEndpoint; + // TODO socket status enum +} knSocketTCP; +ktid_declare(knSocketTCP); + +///@note EXAMPLE 1: socket = open(false); bind(socket, localhost:8080); close(socket); - the socket on port 8080 still unavaliable for several minutes +///@note EXAMPLE 2: socket = open(true); bind(socket, localhost:8080); close(socket); - the socket on port 8080 can be opened again +///@param allowReuse enables binding multiple sockets to single port. Set to TRUE on a listening socket if you want to bind it to the same port after close. +///@return Maybe new socket +Maybe knSocketTCP_open(bool allowReuse); + +///@param direction receive/send/both +///@return Maybe error or nothing +Maybe knSocketTCP_shutdown(knSocketTCP* socket, knShutdownType direction); + +/// closes file descriptor and frees socket pointer +///@return Maybe error or nothing +Maybe knSocketTCP_close(knSocketTCP* socket); + +///start listening at local endpoint +///@return Maybe error or nothing +Maybe knSocketTCP_listen(knSocketTCP* socket, knIPV4Endpoint localEndp); + +///sets socket remote endpoint +///@return Maybe error or nothing +Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEndp); + +///@return Maybe new socket connected to client +Maybe knSocketTCP_accept(knSocketTCP* socket); + +///@param dataLength 0-4294967295 +///@return Maybe +Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength); + +///@param buffer buffer for receiving data +///@param bufferLength 0-4294967295 +///@return Maybe received bytes amount +Maybe knSocketTCP_receive(knSocketTCP* socket, char* buffer, u32 bufferLength); + +#if __cplusplus +} #endif \ No newline at end of file diff --git a/src/Network/sockets/knSocketUDP.c b/src/Network/sockets/knSocketUDP.c index e8a48e5..a4cc712 100644 --- a/src/Network/sockets/knSocketUDP.c +++ b/src/Network/sockets/knSocketUDP.c @@ -1,33 +1,37 @@ -#include "../network.h" -#include "../socket_impl_includes.h" -ktid_define(knSocketUDP); - -Maybe knSocketUDP_open(){ - knSocketUDP* newSocket=malloc(sizeof(knSocketUDP)); - newSocket->localEndpoint=knIPV4Endpoint_create(knIPV4Address_fromBytes(0,0,0,0),0); - newSocket->socketfd=socket(AF_INET, SOCK_DGRAM, 0); - if(newSocket->socketfd==-1) - safethrow("can't create UDP socket", free(newSocket)); - - return SUCCESS(UniHeapPtr(knSocketUDP, newSocket)); -} - -Maybe knSocketUDP_shutdown(knSocketUDP* socket, knShutdownType direction){ - try(__kn_StdSocket_shutdown(socket->socketfd, direction), _m875, ;); - return MaybeNull; -} - -Maybe knSocketUDP_close(knSocketUDP* socket){ - try(__kn_StdSocket_close(socket->socketfd), _m875, ;); - socket->socketfd = 0; - socket->localEndpoint = knIPV4Endpoint_create(IPV4_NONE, -1); - return MaybeNull; -} - -Maybe knSocketUDP_listen(knSocketUDP* socket, knIPV4Endpoint localEndp); - -Maybe knSocketUDP_accept(knSocketUDP* socket); - -Maybe knSocketUDP_sendto(knSocketUDP* socket, char* data, u32 dataLength, knIPV4Endpoint destination); - -Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); +#include "../network.h" +#include "../socket_impl_includes.h" +ktid_define(knSocketUDP); + +Maybe knSocketUDP_open(bool allowReuse){ + knSocketUDP* newSocket=malloc(sizeof(knSocketUDP)); + newSocket->localEndpoint=knIPV4Endpoint_create(knIPV4Address_fromBytes(0,0,0,0),0); + newSocket->socketfd=socket(AF_INET, SOCK_DGRAM, 0); + if(newSocket->socketfd==-1) + safethrow("can't create socket", free(newSocket)); + + // set value of REUSEADDR socket option + int opt_val = allowReuse; + if(setsockopt(newSocket->socketfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt_val, sizeof(opt_val)) != 0) + safethrow("can't set socket options", free(newSocket)); + + return SUCCESS(UniHeapPtr(knSocketUDP, newSocket)); +} + +Maybe knSocketUDP_shutdown(knSocketUDP* socket, knShutdownType direction){ + try(__kn_StdSocket_shutdown(socket->socketfd, direction), _m875, ;); + return MaybeNull; +} + +Maybe knSocketUDP_close(knSocketUDP* socket){ + try(__kn_StdSocket_close(socket->socketfd), _m875, ;); + free(socket); + return MaybeNull; +} + +Maybe knSocketUDP_listen(knSocketUDP* socket, knIPV4Endpoint localEndp); + +Maybe knSocketUDP_accept(knSocketUDP* socket); + +Maybe knSocketUDP_sendto(knSocketUDP* socket, char* data, u32 dataLength, knIPV4Endpoint destination); + +Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); diff --git a/src/Network/sockets/knSocketUDP.h b/src/Network/sockets/knSocketUDP.h index 8ef4454..4f5ec56 100644 --- a/src/Network/sockets/knSocketUDP.h +++ b/src/Network/sockets/knSocketUDP.h @@ -1,45 +1,49 @@ -#pragma once - -#if __cplusplus -extern "C" { -#endif - -#include "../network_types.h" - -typedef struct knSocketUDP { - i64 socketfd; - knIPV4Endpoint localEndpoint; - // TODO socket status enum -} knSocketUDP; -ktid_declare(knSocketUDP); - -///@return Maybe new socket -Maybe knSocketUDP_open(); - -///@param direction receive/send/both -///@return Maybe error or nothing -Maybe knSocketUDP_shutdown(knSocketUDP* socket, knShutdownType direction); - -///@return Maybe error or nothing -Maybe knSocketUDP_close(knSocketUDP* socket); - -///start listening at 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); - -///@param buffer buffer for receiving data -///@param bufferLength 0-4294967295 -///@return Maybe received bytes amount -Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); - - -#if __cplusplus -} +#pragma once + +#if __cplusplus +extern "C" { +#endif + +#include "../network_types.h" + +typedef struct knSocketUDP { + i64 socketfd; + knIPV4Endpoint localEndpoint; + // TODO socket status enum +} knSocketUDP; +ktid_declare(knSocketUDP); + +///@note EXAMPLE 1: socket = open(false); bind(socket, localhost:8080); close(socket); - the socket on port 8080 still unavaliable for several minutes +///@note EXAMPLE 2: socket = open(true); bind(socket, localhost:8080); close(socket); - the socket on port 8080 can be opened again +///@param allowReuse enables binding multiple sockets to single port. Set to TRUE on a listening socket if you want to bind it to the same port after close. +///@return Maybe new socket +Maybe knSocketUDP_open(bool allowReuse); + +///@param direction receive/send/both +///@return Maybe error or nothing +Maybe knSocketUDP_shutdown(knSocketUDP* socket, knShutdownType direction); + +/// closes file descriptor and frees socket pointer +///@return Maybe error or nothing +Maybe knSocketUDP_close(knSocketUDP* socket); + +///start listening at 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); + +///@param buffer buffer for receiving data +///@param bufferLength 0-4294967295 +///@return Maybe received bytes amount +Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); + + +#if __cplusplus +} #endif \ No newline at end of file diff --git a/tests/test_network.c b/tests/test_network.c index 2c6c784..b99edc4 100644 --- a/tests/test_network.c +++ b/tests/test_network.c @@ -1,78 +1,169 @@ -#include "tests.h" -#include "../src/Network/network.h" - -void __test_knIPV4Address_fromStr(char* addrStr, u8 a, u8 b, u8 c, u8 d){ - tryLast(knIPV4Address_fromStr(addrStr), maybeAddr, ;) - knIPV4Address addr; - addr.UintBigEndian=(u32)maybeAddr.value.UInt64; - kprintf("\e[94mknIPV4Address_fromStr(\e[96m%s\e[94m) -> ", addrStr); - if(maybeAddr.value.UInt64!=knIPV4Address_fromBytes(a,b,c,d).UintBigEndian){ - kprintf("\e[91m%u.%u.%u.%u\n", - (u8)addr.bytes[0], (u8)addr.bytes[1], (u8)addr.bytes[2], (u8)addr.bytes[3]); - throw("knIPV4Address_fromStr returned wrong value"); - } - else { - kprintf("\e[92m%u.%u.%u.%u\n", - (u8)addr.bytes[0], (u8)addr.bytes[1], (u8)addr.bytes[2], (u8)addr.bytes[3]); - } - -} -#define test_knIPV4Address_fromStr(a,b,c,d) __test_knIPV4Address_fromStr(#a"."#b"."#c"."#d, a,b,c,d) - -void test_network(){ - optime(__func__,1,({ - kprintf("\e[96m------------[test_network]------------\n"); - tryLast(kn_tryInit(), _mjj64g, ;); - kprintf("\e[92m\nkerepNetwork initialized"); - - PRINT_SIZEOF(knIPV4Address); - PRINT_SIZEOF(knPort); - PRINT_SIZEOF(knIPV4Endpoint); - PRINT_SIZEOF(knSocketTCP); - PRINT_SIZEOF(knSocketUDP); - PRINT_SIZEOF(knPackage); - PRINT_SIZEOF(knChannel); - - test_knIPV4Address_fromStr(127,0,0,1); - test_knIPV4Address_fromStr(34,255,45,0); - test_knIPV4Address_fromStr(3,3,3,128); - - knSocketTCP* socket; - tryLast(knSocketTCP_open(), m_socket, ;); - socket=m_socket.value.VoidPtr; - kprintf("\e[92mTCP socket created\n"); - - knIPV4Endpoint localEnd = knIPV4Endpoint_create(IPV4_LOOPBACK, 4444); - tryLast(knSocketTCP_listen(socket, localEnd), _m81775, ;) - kprintf("\e[92msocket is listening\n"); - - tryLast(knSocketTCP_accept(socket), m_connection, ;); - knSocketTCP* clientConnection = m_connection.value.VoidPtr; - kprintf("\e[92mclient connection accepted\n"); - - char buf[4096]; - while(true){ - tryLast(knSocketTCP_receive(clientConnection, buf, sizeof(buf)), m_recCount, ;); - u64 recCount = m_recCount.value.UInt64; - fwrite(buf, sizeof(char), recCount, stdout); - // end of received data - if(recCount != sizeof(buf)) - break; - } - kprintf("\e[92mmessage received\n"); - - const char msg[] = "pong"; - tryLast(knSocketTCP_send(clientConnection, msg, sizeof(msg)), _mu75q2, ;); - kprintf("\e[92mmessage sent\n"); - - tryLast(knSocketTCP_shutdown(clientConnection, knShutdownType_Both), _m2351, ;); - tryLast(knSocketTCP_close(clientConnection), _m9776, ;); - kprintf("\e[92mclient connection closed\n"); - - tryLast(knSocketTCP_close(socket), _m676, ;); - kprintf("\e[92mTCP socket closed\n"); - - tryLast(kt_tryDispose(), _m88ag, ;); - kprintf("\e[92mkerepNetwork disposed\n"); - })); +#include "tests.h" +#include "../src/Network/network.h" +#include "pthread.h" +#include "../src/Network/socket_impl_includes.h" + +static void __test_knIPV4Address_fromStr(char* addrStr, u8 a, u8 b, u8 c, u8 d){ + tryLast(knIPV4Address_fromStr(addrStr), maybeAddr, ;) + knIPV4Address addr; + addr.UintBigEndian=(u32)maybeAddr.value.UInt64; + kprintf("\e[92mknIPV4Address_fromStr(\e[96m%s\e[92m) -> ", addrStr); + if(maybeAddr.value.UInt64!=knIPV4Address_fromBytes(a,b,c,d).UintBigEndian){ + kprintf("\e[91m%u.%u.%u.%u\n", + (u8)addr.bytes[0], (u8)addr.bytes[1], (u8)addr.bytes[2], (u8)addr.bytes[3]); + throw("knIPV4Address_fromStr returned wrong value"); + } + else { + kprintf("\e[94m%u.%u.%u.%u\n", + (u8)addr.bytes[0], (u8)addr.bytes[1], (u8)addr.bytes[2], (u8)addr.bytes[3]); + } + +} +#define test_knIPV4Address_fromStr(a,b,c,d) __test_knIPV4Address_fromStr(#a"."#b"."#c"."#d, a,b,c,d) + +static void test_network_types(){ + PRINT_SIZEOF(knIPV4Address); + PRINT_SIZEOF(knPort); + PRINT_SIZEOF(knIPV4Endpoint); + PRINT_SIZEOF(knSocketTCP); + PRINT_SIZEOF(knSocketUDP); + PRINT_SIZEOF(knPackage); + PRINT_SIZEOF(knChannel); + + test_knIPV4Address_fromStr(127,0,0,1); + test_knIPV4Address_fromStr(34,255,45,0); + test_knIPV4Address_fromStr(3,3,3,128); + fflush(stdout); +} + +static pthread_mutex_t stdout_mutex = {0}; + +// thread-safe print +#define kprintf_safe(ARGS...) pthread_mutex_lock(&stdout_mutex); kprintf(ARGS); fflush(stdout); pthread_mutex_unlock(&stdout_mutex); + +typedef struct { + knSocketTCP* socket_client; + knIPV4Endpoint serverEnd; +} tcp_client_connect_async_data; + +void* tcp_client_connect_async(void* _data){ + tcp_client_connect_async_data* data = _data; + tryLast(knSocketTCP_connect(data->socket_client, data->serverEnd), _m8531,;); + + kprintf_safe("\e[92mclient socket connected to server\n"); + free(data); + return NULL; +} + +static void test_tcp(){ + kprintf("\e[96m----------[test_network/tcp]----------\n"); + knIPV4Endpoint serverEnd = knIPV4Endpoint_create(IPV4_LOOPBACK, 4444); + knSocketTCP *socket_server, *clientConnection, *socket_client; + // server + { + tryLast(knSocketTCP_open(true), m_socketS, ;); + socket_server=m_socketS.value.VoidPtr; + kprintf("\e[92mTCP server socket created\n"); + + tryLast(knSocketTCP_listen(socket_server, serverEnd), _m81775, ;) + kprintf("\e[92mserver socket is listening\n"); + } + // client + { + tryLast(knSocketTCP_open(false), m_socketC, ;); + socket_client=m_socketC.value.VoidPtr; + kprintf("\e[92mTCP client socket created\n"); + + tcp_client_connect_async_data* client_connection_data = malloc(sizeof(tcp_client_connect_async_data)); + client_connection_data->serverEnd = serverEnd; + client_connection_data->socket_client = socket_client; + pthread_t client_connection_thread; + fflush(stdout); + if(pthread_create(&client_connection_thread, NULL, tcp_client_connect_async, client_connection_data) != 0) + throw("can't create client connection thread"); + if(pthread_detach(client_connection_thread) != 0) + throw("can't detatch client connection thread"); + } + // server + { + tryLast(knSocketTCP_accept(socket_server), m_connection, ;); + clientConnection = m_connection.value.VoidPtr; + kprintf_safe("\e[92mserver accepted client connection\n"); + } + // client + { + const char client_msg[] = "ping"; + tryLast(knSocketTCP_send(socket_client, client_msg, sizeof(client_msg)), _mu75q2, ;); + kprintf("\e[92mmessage sent to server\n\e[94m"); + } + // server + { + char received_client_msg[32]; + tryLast(knSocketTCP_receive(clientConnection, received_client_msg, sizeof(received_client_msg)), m_recCount, ;); + u64 recCount = m_recCount.value.UInt64; + fwrite(received_client_msg, sizeof(char), recCount, stdout); + fputc('\n', stdout); + if(!cptr_equals(received_client_msg, "ping")) + throw("received_client_msg != \"ping\""); + kprintf("\e[92mmessage received by server\n"); + + const char server_msg[] = "pong"; + tryLast(knSocketTCP_send(clientConnection, server_msg, sizeof(server_msg)), _mu75q2, ;); + kprintf("\e[92mmessage sent to client\n\e[94m"); + fflush(stdout); + } + // client + { + char received_server_msg[32]; + tryLast(knSocketTCP_receive(socket_client, received_server_msg, sizeof(received_server_msg)), m_recCount, ;); + u64 recCount = m_recCount.value.UInt64; + fwrite(received_server_msg, sizeof(char), recCount, stdout); + fputc('\n', stdout); + if(!cptr_equals(received_server_msg, "pong")) + throw("received_server_msg != \"pong\""); + kprintf("\e[92mmessage received by client\n"); + fflush(stdout); + } + // server + { + tryLast(knSocketTCP_shutdown(clientConnection, knShutdownType_Both), _m2351, ;); + tryLast(knSocketTCP_close(clientConnection), _m9776, ;); + kprintf("\e[92mclient connection closed\n"); + + tryLast(knSocketTCP_close(socket_server), _m676, ;); + kprintf("\e[92mTCP server socket closed\n"); + } + // client + { + tryLast(knSocketTCP_close(socket_client), _m964, ;); + kprintf("\e[92mTCP client socket closed\n"); + } + fflush(stdout); +} + +void test_udp(){ + kprintf("\e[96m----------[test_network/udp]----------\n"); + + fflush(stdout); +} + +void test_network(){ + optime(__func__,1,({ + kprintf("\e[96m------------[test_network]------------\n"); + tryLast(kn_tryInit(), _mjj64g, ;); + kprintf("\e[92mkerepNetwork initialized\n"); + + if(pthread_mutex_init(&stdout_mutex, NULL) != 0) + throw("can't init mutex"); + + test_network_types(); + test_tcp(); + test_udp(); + + if(pthread_mutex_destroy(&stdout_mutex) != 0) + throw("can't destroy mutex"); + + tryLast(kt_tryDispose(), _m88ag, ;); + kprintf("\e[92mkerepNetwork disposed\n"); + })); } \ No newline at end of file