diff --git a/src/Network/network.c b/src/Network/network.c index fc949c5..7f077cf 100644 --- a/src/Network/network.c +++ b/src/Network/network.c @@ -1,5 +1,5 @@ #include "network.h" -#include "stdSocketHeaders.h" +#include "socket_impl_includes.h" Maybe kn_tryInit(){ #if _WIN32 @@ -10,8 +10,8 @@ Maybe kn_tryInit(){ char* errcode = toString_hex(&startupResult, sizeof(int), 0 , 1, 1); safethrow(cptr_concat("WSAStartup failed with error: ", errcode), ;); } - return SUCCESS(UniNull); #endif + return SUCCESS(UniNull); } Maybe kt_tryDispose(){ @@ -22,6 +22,24 @@ Maybe kt_tryDispose(){ char* errcode = toString_hex(&cleanupResult, sizeof(int), 0, 1, 1); safethrow(cptr_concat("WSAStartup failed with error: ", errcode), ;); } - return SUCCESS(UniNull); #endif + return SUCCESS(UniNull); +} + + +Maybe __kn_StdSocket_shutdown(i64 socketfd, knShutdownType direction){ + if(shutdown(socketfd, SD_SEND) == -1) + safethrow("can't shutdown socket", ;); + return MaybeNull; +} + +Maybe __kn_StdSocket_close(i64 socketfd){ +#if KN_USE_WINSOCK + if(closesocket(socketfd) == -1) +#else + if(close(socket->socketfd) == -1) +#endif + safethrow("can't close socket", ;); + + return MaybeNull; } diff --git a/src/Network/network.h b/src/Network/network.h index c2a8d46..836659d 100644 --- a/src/Network/network.h +++ b/src/Network/network.h @@ -6,7 +6,7 @@ extern "C" { #include "../base/base.h" -#include "knAddress.h" +#include "network_types.h" #include "sockets/knSocketTCP.h" #include "sockets/knSocketUDP.h" #include "sockets/knSocketChanneled.h" @@ -14,6 +14,15 @@ 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/knAddress.c b/src/Network/network_types.c similarity index 93% rename from src/Network/knAddress.c rename to src/Network/network_types.c index 5f02151..1f28169 100644 --- a/src/Network/knAddress.c +++ b/src/Network/network_types.c @@ -1,4 +1,4 @@ -#include "knAddress.h" +#include "network_types.h" ktid_define(knIPV4Address); ktid_define(knIPV4Endpoint); @@ -8,7 +8,7 @@ Maybe knIPV4Address_fromStr(char* addrStr){ char* errmsg_extra="wrong char"; u8 c; knIPV4Address addr; - addr.u32=0; + addr.UintBigEndian=0; u16 n=0; for(u8 i=0; i<4; ){ c=*addrStr++; @@ -45,5 +45,5 @@ Maybe knIPV4Address_fromStr(char* addrStr){ } } //TODO UniStack for generic structs - return SUCCESS(UniUInt64(addr.u32)); + return SUCCESS(UniUInt64(addr.UintBigEndian)); } diff --git a/src/Network/knAddress.h b/src/Network/network_types.h similarity index 61% rename from src/Network/knAddress.h rename to src/Network/network_types.h index 721ae88..756a46a 100644 --- a/src/Network/knAddress.h +++ b/src/Network/network_types.h @@ -10,12 +10,13 @@ extern "C" { typedef u16 knPort; typedef union knIPV4Address { - u32 u32; + u32 UintBigEndian; char bytes[4]; } knIPV4Address; ktid_declare(knIPV4Address); -#define knIPV4Address_fromBytes(A, B, C, D) (knIPV4Address){.bytes={A,B,C,D}} +#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); @@ -31,7 +32,13 @@ typedef struct knIPV4Endpoint { } knIPV4Endpoint; ktid_declare(knIPV4Endpoint); -#define knIPV4Endpoint_create(ADDR, PORT) (knIPV4Endpoint){ADDR, PORT} +#define knIPV4Endpoint_create(ADDR, PORT) ((knIPV4Endpoint){ADDR, PORT}) + +typedef enum knShutdownType { + knShutdownType_Receive = 0, + knShutdownType_Send = 1, + knShutdownType_Both = 2, +} knShutdownType; #if __cplusplus } diff --git a/src/Network/stdSocketHeaders.h b/src/Network/socket_impl_includes.h similarity index 100% rename from src/Network/stdSocketHeaders.h rename to src/Network/socket_impl_includes.h diff --git a/src/Network/sockets/knSocketChanneled.c b/src/Network/sockets/knSocketChanneled.c index 1f3cb24..4c0b5b9 100644 --- a/src/Network/sockets/knSocketChanneled.c +++ b/src/Network/sockets/knSocketChanneled.c @@ -1,5 +1,5 @@ #include "../network.h" -#include "../stdSocketHeaders.h" +#include "../socket_impl_includes.h" ktid_define(knPackage); ktid_define(knPackageQueueElem); diff --git a/src/Network/sockets/knSocketChanneled.h b/src/Network/sockets/knSocketChanneled.h index 2de7483..a0e00e7 100644 --- a/src/Network/sockets/knSocketChanneled.h +++ b/src/Network/sockets/knSocketChanneled.h @@ -4,8 +4,7 @@ extern "C" { #endif -#include "../../base/base.h" -#include "../knAddress.h" +#include "../network_types.h" #define KNPAC_MAX_DATA_SIZE (65535-sizeof(knPackage)+sizeof(u8*)) @@ -74,7 +73,7 @@ Maybe knSocketChanneled_accept(knSocketChanneled* socket); ///@return Maybe Maybe knSocketChanneled_send(knSocketChanneled* socket, u16 destinationIndex, u8* data, u32 dataLength); -///@param buffer buffer for recieving data +///@param buffer buffer for receiving data ///@param bufferLength 0-4294967295 ///@return Maybe received bytes amount Maybe knSocketChanneled_receive(knSocketChanneled* socket, u16 destinationIndex, u8* buffer, u32 bufferLength); diff --git a/src/Network/sockets/knSocketTCP.c b/src/Network/sockets/knSocketTCP.c index 6b41484..6d16e12 100644 --- a/src/Network/sockets/knSocketTCP.c +++ b/src/Network/sockets/knSocketTCP.c @@ -1,41 +1,35 @@ #include "../network.h" -#include "../stdSocketHeaders.h" +#include "../socket_impl_includes.h" ktid_define(knSocketTCP); Maybe knSocketTCP_open(){ knSocketTCP* newSocket=malloc(sizeof(knSocketTCP)); - newSocket->localEndpoint=knIPV4Endpoint_create({.u32=INADDR_NONE},0); + newSocket->localEndpoint=knIPV4Endpoint_create(IPV4_NONE,0); newSocket->remoteEndpoint=newSocket->localEndpoint; newSocket->socketfd=socket(AF_INET, SOCK_STREAM, 0); - if(newSocket->socketfd==-1) + if(newSocket->socketfd==-1 || newSocket->socketfd == ~0) safethrow("can't create TCP socket", free(newSocket)); return SUCCESS(UniHeapPtr(knSocketTCP, newSocket)); } -Maybe knSocketTCP_close(knSocketTCP* socket){ - int result= -#if KN_USE_WINSOCK - closesocket -#else - close -#endif - (socket->socketfd); - if(result==-1) - safethrow("can't close socket",;); +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(0, 0); - socket->remoteEndpoint = knIPV4Endpoint_create(0, 0); + socket->localEndpoint = knIPV4Endpoint_create(IPV4_NONE, -1); + socket->remoteEndpoint = knIPV4Endpoint_create(IPV4_NONE, -1); return MaybeNull; } Maybe knSocketTCP_listen(knSocketTCP* socket, knIPV4Endpoint localEndp){ - if(socket->localEndpoint.address.u32!=INADDR_NONE) - safethrow("socket is bound already",;); struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(localEndp.address.u32); + 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",;); @@ -46,11 +40,9 @@ Maybe knSocketTCP_listen(knSocketTCP* socket, knIPV4Endpoint localEndp){ } Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEndp){ - if(socket->remoteEndpoint.address.u32!=0) - safethrow("socket is connected already",;); struct sockaddr_in servaddr; servaddr.sin_family=AF_INET; - servaddr.sin_addr.s_addr = htonl(remoteEndp.address.u32); + 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",;); @@ -59,11 +51,47 @@ Maybe knSocketTCP_connect(knSocketTCP* socket, knIPV4Endpoint remoteEndp){ } Maybe knSocketTCP_accept(knSocketTCP* socket){ - accept(socket->socketfd, ) + 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); +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)); +} diff --git a/src/Network/sockets/knSocketTCP.h b/src/Network/sockets/knSocketTCP.h index 6b1ad4a..fe8ef44 100644 --- a/src/Network/sockets/knSocketTCP.h +++ b/src/Network/sockets/knSocketTCP.h @@ -4,19 +4,23 @@ extern "C" { #endif -#include "../../base/base.h" -#include "../knAddress.h" +#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); @@ -35,7 +39,7 @@ Maybe knSocketTCP_accept(knSocketTCP* socket); ///@return Maybe Maybe knSocketTCP_send(knSocketTCP* socket, char* data, u32 dataLength); -///@param buffer buffer for recieving data +///@param buffer buffer for receiving data ///@param bufferLength 0-4294967295 ///@return Maybe received bytes amount Maybe knSocketTCP_receive(knSocketTCP* socket, char* buffer, u32 bufferLength); diff --git a/src/Network/sockets/knSocketUDP.c b/src/Network/sockets/knSocketUDP.c index 419e0f1..e8a48e5 100644 --- a/src/Network/sockets/knSocketUDP.c +++ b/src/Network/sockets/knSocketUDP.c @@ -1,5 +1,5 @@ #include "../network.h" -#include "../stdSocketHeaders.h" +#include "../socket_impl_includes.h" ktid_define(knSocketUDP); Maybe knSocketUDP_open(){ @@ -12,19 +12,15 @@ Maybe knSocketUDP_open(){ return SUCCESS(UniHeapPtr(knSocketUDP, newSocket)); } -Maybe knSocketUDP_close(knSocketUDP* socket){ - int result= -#if KN_USE_WINSOCK - closesocket -#else - close -#endif - (socket->socketfd); - if(result==-1) - safethrow("can't close socket",;); +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(0,0); + socket->localEndpoint = knIPV4Endpoint_create(IPV4_NONE, -1); return MaybeNull; } diff --git a/src/Network/sockets/knSocketUDP.h b/src/Network/sockets/knSocketUDP.h index 4942c81..8ef4454 100644 --- a/src/Network/sockets/knSocketUDP.h +++ b/src/Network/sockets/knSocketUDP.h @@ -4,17 +4,22 @@ extern "C" { #endif -#include "knSocketUDP.h" +#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); @@ -29,7 +34,7 @@ Maybe knSocketUDP_accept(knSocketUDP* socket); ///@return Maybe Maybe knSocketUDP_sendto(knSocketUDP* socket, char* data, u32 dataLength, knIPV4Endpoint destination); -///@param buffer buffer for recieving data +///@param buffer buffer for receiving data ///@param bufferLength 0-4294967295 ///@return Maybe received bytes amount Maybe knSocketUDP_receive(knSocketUDP* socket, char* buffer, u32 bufferLength); diff --git a/tests/test_network.c b/tests/test_network.c index 97ec06c..2c6c784 100644 --- a/tests/test_network.c +++ b/tests/test_network.c @@ -4,9 +4,9 @@ void __test_knIPV4Address_fromStr(char* addrStr, u8 a, u8 b, u8 c, u8 d){ tryLast(knIPV4Address_fromStr(addrStr), maybeAddr, ;) knIPV4Address addr; - addr.u32=(u32)maybeAddr.value.UInt64; + 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).u32){ + 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"); @@ -42,15 +42,32 @@ void test_network(){ socket=m_socket.value.VoidPtr; kprintf("\e[92mTCP socket created\n"); - knIPV4Endpoint localEnd = knIPV4Endpoint_create(knIPV4Address_fromBytes(127,0,0,1), 4444); + 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_accept(socket), m_connection, ;); - knSocketTCP* connection = m_connection.value.VoidPtr; - knSocketTCP_receive() + 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");