diff --git a/code/logic/fossil/io/network.h b/code/logic/fossil/io/network.h index 2c4ecf9..935750f 100644 --- a/code/logic/fossil/io/network.h +++ b/code/logic/fossil/io/network.h @@ -26,76 +26,158 @@ #include #include #include + #include #include #define closesocket close typedef int fossil_io_socket_t; #define FOSSIL_IO_INVALID_SOCKET (-1) #endif +#define FOSSIL_IO_SOCKET_TYPE_TCP SOCK_STREAM +#define FOSSIL_IO_SOCKET_TYPE_UDP SOCK_DGRAM + #ifdef __cplusplus extern "C" { #endif /** - * Initialize the network stack (needed for Windows). - * Returns 0 on success, non-zero on failure. + * Initialize the network stack. This function is necessary for Windows + * platforms to set up the Winsock library. On other platforms, it may + * perform other necessary initializations. + * + * @return 0 on success, non-zero on failure. */ int fossil_io_network_create(void); /** - * Clean up network stack (needed for Windows). + * Clean up the network stack. This function is necessary for Windows + * platforms to clean up the Winsock library. On other platforms, it may + * perform other necessary clean-up operations. */ void fossil_io_network_destroy(void); /** - * Create a new TCP socket. - * Returns a valid socket on success or FOSSIL_IO_INVALID_SOCKET on failure. + * Create a new socket of the specified type (TCP or UDP). + * + * @param type The type of socket to create (e.g., SOCK_STREAM for TCP, SOCK_DGRAM for UDP). + * @return A valid socket on success, or FOSSIL_IO_INVALID_SOCKET on failure. */ -fossil_io_socket_t fossil_io_network_create_socket(void); +fossil_io_socket_t fossil_io_network_create_socket(int type); /** - * Bind a socket to a specific port (IPv4/IPv6). - * Returns 0 on success, -1 on failure. + * Bind a socket to a specific IP address and port. This function associates + * the socket with a local address so that it can listen for incoming connections + * or send data. + * + * @param sock The socket to bind. + * @param ip The IP address to bind to (e.g., "127.0.0.1" for localhost). + * @param port The port number to bind to. + * @return 0 on success, -1 on failure. */ int fossil_io_network_bind(fossil_io_socket_t sock, const char *ip, uint16_t port); /** - * Listen for incoming connections. - * Returns 0 on success, -1 on failure. + * Listen for incoming connections on a bound socket. This function puts the + * socket into a state where it can accept incoming connection requests. + * + * @param sock The socket to listen on. + * @param backlog The maximum length of the queue of pending connections. + * @return 0 on success, -1 on failure. */ int fossil_io_network_listen(fossil_io_socket_t sock, int backlog); /** - * Accept a new connection. - * Returns a valid socket on success, or FOSSIL_IO_INVALID_SOCKET on failure. + * Accept a new incoming connection on a listening socket. This function + * extracts the first connection request on the queue of pending connections + * and creates a new socket for the connection. + * + * @param sock The listening socket. + * @param client_ip A buffer to store the IP address of the connecting client. + * @param client_port A pointer to store the port number of the connecting client. + * @return A valid socket for the new connection on success, or FOSSIL_IO_INVALID_SOCKET on failure. */ fossil_io_socket_t fossil_io_network_accept(fossil_io_socket_t sock, char *client_ip, uint16_t *client_port); /** - * Connect to a remote server. - * Returns 0 on success, -1 on failure. + * Connect to a remote server. This function establishes a connection to a + * specified IP address and port. + * + * @param sock The socket to use for the connection. + * @param ip The IP address of the remote server. + * @param port The port number of the remote server. + * @return 0 on success, -1 on failure. */ int fossil_io_network_connect(fossil_io_socket_t sock, const char *ip, uint16_t port); /** - * Send data over a socket. - * Returns the number of bytes sent, or -1 on failure. + * Send data over a connected socket. This function transmits data to the + * remote peer connected to the socket. + * + * @param sock The socket to use for sending data. + * @param data A pointer to the data to be sent. + * @param len The length of the data to be sent. + * @return The number of bytes sent, or -1 on failure. */ int fossil_io_network_send(fossil_io_socket_t sock, const void *data, size_t len); /** - * Receive data from a socket. - * Returns the number of bytes received, or -1 on failure. + * Receive data from a connected socket. This function reads data from the + * remote peer connected to the socket. + * + * @param sock The socket to use for receiving data. + * @param buffer A buffer to store the received data. + * @param len The maximum length of data to be received. + * @return The number of bytes received, or -1 on failure. */ int fossil_io_network_receive(fossil_io_socket_t sock, void *buffer, size_t len); /** - * Close a socket. + * Close a socket. This function releases the resources associated with the + * socket and closes the connection. + * + * @param sock The socket to be closed. */ void fossil_io_network_close(fossil_io_socket_t sock); +/** + * Send data to a specific IP address and port using a UDP socket. This function + * transmits data to the specified address and port without establishing a connection. + * + * @param sock The socket to use for sending data. + * @param data A pointer to the data to be sent. + * @param len The length of the data to be sent. + * @param ip The IP address of the destination. + * @param port The port number of the destination. + * @return The number of bytes sent, or -1 on failure. + */ +int fossil_io_network_sendto(fossil_io_socket_t sock, const void *data, size_t len, const char *ip, uint16_t port); + +/** + * Receive data from a specific IP address and port using a UDP socket. This function + * reads data from the specified address and port without establishing a connection. + * + * @param sock The socket to use for receiving data. + * @param buffer A buffer to store the received data. + * @param len The maximum length of data to be received. + * @param ip A buffer to store the IP address of the sender. + * @param port A pointer to store the port number of the sender. + * @return The number of bytes received, or -1 on failure. + */ +int fossil_io_network_recvfrom(fossil_io_socket_t sock, void *buffer, size_t len, char *ip, uint16_t *port); + +/** + * Bridge function for network operations. This function can be used to + * transfer data between two sockets, effectively bridging them. + * + * @param sock1 The first socket. + * @param sock2 The second socket. + * @return 0 on success, -1 on failure. + */ +int fossil_io_network_bridge(fossil_io_socket_t sock1, fossil_io_socket_t sock2); + #ifdef __cplusplus } + /** * C++ wrapper for the output functions. */ @@ -110,83 +192,166 @@ namespace fossil { class Network { public: /** - * Initialize the network stack (needed for Windows). - * Returns 0 on success, non-zero on failure. + * Initialize the network stack. This function is necessary for Windows + * platforms to set up the Winsock library. On other platforms, it may + * perform other necessary initializations. + * + * @return 0 on success, non-zero on failure. */ static int init(void) { return fossil_io_network_create(); } /** - * Clean up network stack (needed for Windows). + * Clean up the network stack. This function is necessary for Windows + * platforms to clean up the Winsock library. On other platforms, it may + * perform other necessary clean-up operations. */ static void cleanup(void) { fossil_io_network_destroy(); } /** - * Create a new TCP socket. - * Returns a valid socket on success or FOSSIL_IO_INVALID_SOCKET on failure. + * Create a new socket of the specified type (TCP or UDP). + * + * @param type The type of socket to create (e.g., SOCK_STREAM for TCP, SOCK_DGRAM for UDP). + * @return A valid socket on success, or FOSSIL_IO_INVALID_SOCKET on failure. */ - static fossil_io_socket_t create_socket(void) { - return fossil_io_network_create_socket(); + static fossil_io_socket_t create_socket(int type) { + return fossil_io_network_create_socket(type); } /** - * Bind a socket to a specific port (IPv4/IPv6). - * Returns 0 on success, -1 on failure. + * Bind a socket to a specific IP address and port. This function associates + * the socket with a local address so that it can listen for incoming connections + * or send data. + * + * @param sock The socket to bind. + * @param ip The IP address to bind to (e.g., "127.0.0.1" for localhost). + * @param port The port number to bind to. + * @return 0 on success, -1 on failure. */ static int bind(fossil_io_socket_t sock, const char *ip, uint16_t port) { return fossil_io_network_bind(sock, ip, port); } /** - * Listen for incoming connections. - * Returns 0 on success, -1 on failure. + * Listen for incoming connections on a bound socket. This function puts the + * socket into a state where it can accept incoming connection requests. + * + * @param sock The socket to listen on. + * @param backlog The maximum length of the queue of pending connections. + * @return 0 on success, -1 on failure. */ static int listen(fossil_io_socket_t sock, int backlog) { return fossil_io_network_listen(sock, backlog); } /** - * Accept a new connection. - * Returns a valid socket on success, or FOSSIL_IO_INVALID_SOCKET on failure. + * Accept a new incoming connection on a listening socket. This function + * extracts the first connection request on the queue of pending connections + * and creates a new socket for the connection. + * + * @param sock The listening socket. + * @param client_ip A buffer to store the IP address of the connecting client. + * @param client_port A pointer to store the port number of the connecting client. + * @return A valid socket for the new connection on success, or FOSSIL_IO_INVALID_SOCKET on failure. */ static fossil_io_socket_t accept(fossil_io_socket_t sock, char *client_ip, uint16_t *client_port) { return fossil_io_network_accept(sock, client_ip, client_port); } /** - * Connect to a remote server. - * Returns 0 on success, -1 on failure. + * Connect to a remote server. This function establishes a connection to a + * specified IP address and port. + * + * @param sock The socket to use for the connection. + * @param ip The IP address of the remote server. + * @param port The port number of the remote server. + * @return 0 on success, -1 on failure. */ static int connect(fossil_io_socket_t sock, const char *ip, uint16_t port) { return fossil_io_network_connect(sock, ip, port); } /** - * Send data over a socket. - * Returns the number of bytes sent, or -1 on failure. + * Send data over a connected socket. This function transmits data to the + * remote peer connected to the socket. + * + * @param sock The socket to use for sending data. + * @param data A pointer to the data to be sent. + * @param len The length of the data to be sent. + * @return The number of bytes sent, or -1 on failure. */ static int send(fossil_io_socket_t sock, const void *data, size_t len) { return fossil_io_network_send(sock, data, len); } /** - * Receive data from a socket. - * Returns the number of bytes received, or -1 on failure. + * Receive data from a connected socket. This function reads data from the + * remote peer connected to the socket. + * + * @param sock The socket to use for receiving data. + * @param buffer A buffer to store the received data. + * @param len The maximum length of data to be received. + * @return The number of bytes received, or -1 on failure. */ static int receive(fossil_io_socket_t sock, void *buffer, size_t len) { return fossil_io_network_receive(sock, buffer, len); } /** - * Close a socket. + * Close a socket. This function releases the resources associated with the + * socket and closes the connection. + * + * @param sock The socket to be closed. */ static void close(fossil_io_socket_t sock) { fossil_io_network_close(sock); } + /** + * Send data to a specific IP address and port using a UDP socket. This function + * transmits data to the specified address and port without establishing a connection. + * + * @param sock The socket to use for sending data. + * @param data A pointer to the data to be sent. + * @param len The length of the data to be sent. + * @param ip The IP address of the destination. + * @param port The port number of the destination. + * @return The number of bytes sent, or -1 on failure. + */ + static int sendto(fossil_io_socket_t sock, const void *data, size_t len, const char *ip, uint16_t port) { + return fossil_io_network_sendto(sock, data, len, ip, port); + } + + /** + * Receive data from a specific IP address and port using a UDP socket. This function + * reads data from the specified address and port without establishing a connection. + * + * @param sock The socket to use for receiving data. + * @param buffer A buffer to store the received data. + * @param len The maximum length of data to be received. + * @param ip A buffer to store the IP address of the sender. + * @param port A pointer to store the port number of the sender. + * @return The number of bytes received, or -1 on failure. + */ + static int recvfrom(fossil_io_socket_t sock, void *buffer, size_t len, char *ip, uint16_t *port) { + return fossil_io_network_recvfrom(sock, buffer, len, ip, port); + } + + /** + * Bridge function for network operations. This function can be used to + * transfer data between two sockets, effectively bridging them. + * + * @param sock1 The first socket. + * @param sock2 The second socket. + * @return 0 on success, -1 on failure. + */ + static int bridge(fossil_io_socket_t sock1, fossil_io_socket_t sock2) { + return fossil_io_network_bridge(sock1, sock2); + } + }; } } diff --git a/code/logic/network.c b/code/logic/network.c index a8b058d..2265d90 100644 --- a/code/logic/network.c +++ b/code/logic/network.c @@ -35,8 +35,8 @@ void fossil_io_network_destroy(void) { #endif } -fossil_io_socket_t fossil_io_network_create_socket(void) { - fossil_io_socket_t sock = socket(AF_INET, SOCK_STREAM, 0); +fossil_io_socket_t fossil_io_network_create_socket(int type) { + fossil_io_socket_t sock = socket(AF_INET, type, 0); if (sock == FOSSIL_IO_INVALID_SOCKET) { #ifdef _WIN32 fprintf(stderr, "Socket creation failed with error: %d\n", WSAGetLastError()); @@ -138,6 +138,43 @@ int fossil_io_network_receive(fossil_io_socket_t sock, void *buffer, size_t len) return bytes_received; } +int fossil_io_network_sendto(fossil_io_socket_t sock, const void *data, size_t len, const char *ip, uint16_t port) { + struct sockaddr_in dest_addr; + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(port); + dest_addr.sin_addr.s_addr = inet_addr(ip); + + int bytes_sent = sendto(sock, data, (int)len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); + if (bytes_sent == -1) { +#ifdef _WIN32 + fprintf(stderr, "Sendto failed with error: %d\n", WSAGetLastError()); +#else + perror("Sendto failed"); +#endif + } + return bytes_sent; +} + +int fossil_io_network_recvfrom(fossil_io_socket_t sock, void *buffer, size_t len, char *ip, uint16_t *port) { + struct sockaddr_in src_addr; + socklen_t addr_len = sizeof(src_addr); + + int bytes_received = recvfrom(sock, buffer, (int)len, 0, (struct sockaddr*)&src_addr, &addr_len); + if (bytes_received == -1) { +#ifdef _WIN32 + fprintf(stderr, "Recvfrom failed with error: %d\n", WSAGetLastError()); +#else + perror("Recvfrom failed"); +#endif + } else if (ip) { + strcpy(ip, inet_ntoa(src_addr.sin_addr)); + if (port) { + *port = ntohs(src_addr.sin_port); + } + } + return bytes_received; +} + void fossil_io_network_close(fossil_io_socket_t sock) { #ifdef _WIN32 if (closesocket(sock) == SOCKET_ERROR) { @@ -149,3 +186,16 @@ void fossil_io_network_close(fossil_io_socket_t sock) { } #endif } + +int fossil_io_network_bridge(fossil_io_socket_t sock1, fossil_io_socket_t sock2) { + char buffer[1024]; + int bytes_received; + + while ((bytes_received = fossil_io_network_receive(sock1, buffer, sizeof(buffer))) > 0) { + if (fossil_io_network_send(sock2, buffer, bytes_received) == -1) { + return -1; + } + } + + return bytes_received; +} diff --git a/code/tests/cases/test_network.c b/code/tests/cases/test_network.c index ea4405d..387ffe6 100644 --- a/code/tests/cases/test_network.c +++ b/code/tests/cases/test_network.c @@ -51,7 +51,7 @@ FOSSIL_TEST_CASE(c_test_network_init) { FOSSIL_TEST_CASE(c_test_network_create_socket) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil_io_network_close(sock); fossil_io_network_destroy(); @@ -59,7 +59,7 @@ FOSSIL_TEST_CASE(c_test_network_create_socket) { FOSSIL_TEST_CASE(c_test_network_bind) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); int result = fossil_io_network_bind(sock, "127.0.0.1", 8080); ASSUME_ITS_EQUAL_I32(0, result); @@ -69,7 +69,7 @@ FOSSIL_TEST_CASE(c_test_network_bind) { FOSSIL_TEST_CASE(c_test_network_listen) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil_io_network_bind(sock, "127.0.0.1", 8080); int result = fossil_io_network_listen(sock, 5); @@ -80,13 +80,41 @@ FOSSIL_TEST_CASE(c_test_network_listen) { FOSSIL_TEST_CASE(c_test_network_close) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil_io_network_close(sock); // No direct way to test close, but we assume no errors if it reaches here fossil_io_network_destroy(); } +FOSSIL_TEST_CASE(c_test_network_create_udp_socket) { + fossil_io_network_create(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + fossil_io_network_close(sock); + fossil_io_network_destroy(); +} + +FOSSIL_TEST_CASE(c_test_network_bind_udp) { + fossil_io_network_create(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + int result = fossil_io_network_bind(sock, "127.0.0.1", 8081); + ASSUME_ITS_EQUAL_I32(0, result); + fossil_io_network_close(sock); + fossil_io_network_destroy(); +} + +FOSSIL_TEST_CASE(c_test_network_sendto_udp) { + fossil_io_network_create(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + const char *message = "Hello, UDP!"; + int bytes_sent = fossil_io_network_sendto(sock, message, strlen(message), "127.0.0.1", 8081); + ASSUME_ITS_EQUAL_I32((int)strlen(message), bytes_sent); + fossil_io_network_close(sock); + fossil_io_network_destroy(); +} // * * * * * * * * * * * * * * * * * * * * * * * * // * Fossil Logic Test Pool @@ -98,6 +126,9 @@ FOSSIL_TEST_GROUP(c_network_tests) { FOSSIL_TEST_ADD(c_network_suite, c_test_network_bind); FOSSIL_TEST_ADD(c_network_suite, c_test_network_listen); FOSSIL_TEST_ADD(c_network_suite, c_test_network_close); + FOSSIL_TEST_ADD(c_network_suite, c_test_network_create_udp_socket); + FOSSIL_TEST_ADD(c_network_suite, c_test_network_bind_udp); + FOSSIL_TEST_ADD(c_network_suite, c_test_network_sendto_udp); FOSSIL_TEST_REGISTER(c_network_suite); } diff --git a/code/tests/cases/test_network.cpp b/code/tests/cases/test_network.cpp index 90fb930..75388a0 100644 --- a/code/tests/cases/test_network.cpp +++ b/code/tests/cases/test_network.cpp @@ -51,7 +51,7 @@ FOSSIL_TEST_CASE(cpp_test_network_init) { FOSSIL_TEST_CASE(cpp_test_network_create_socket) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil_io_network_close(sock); fossil_io_network_destroy(); @@ -59,7 +59,7 @@ FOSSIL_TEST_CASE(cpp_test_network_create_socket) { FOSSIL_TEST_CASE(cpp_test_network_bind) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); int result = fossil_io_network_bind(sock, "127.0.0.1", 8080); ASSUME_ITS_EQUAL_I32(0, result); @@ -69,7 +69,7 @@ FOSSIL_TEST_CASE(cpp_test_network_bind) { FOSSIL_TEST_CASE(cpp_test_network_listen) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil_io_network_bind(sock, "127.0.0.1", 8080); int result = fossil_io_network_listen(sock, 5); @@ -80,13 +80,42 @@ FOSSIL_TEST_CASE(cpp_test_network_listen) { FOSSIL_TEST_CASE(cpp_test_network_close) { fossil_io_network_create(); - fossil_io_socket_t sock = fossil_io_network_create_socket(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil_io_network_close(sock); // No direct way to test close, but we assume no errors if it reaches here fossil_io_network_destroy(); } +FOSSIL_TEST_CASE(cpp_test_network_create_udp_socket) { + fossil_io_network_create(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + fossil_io_network_close(sock); + fossil_io_network_destroy(); +} + +FOSSIL_TEST_CASE(cpp_test_network_bind_udp) { + fossil_io_network_create(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + int result = fossil_io_network_bind(sock, "127.0.0.1", 8081); + ASSUME_ITS_EQUAL_I32(0, result); + fossil_io_network_close(sock); + fossil_io_network_destroy(); +} + +FOSSIL_TEST_CASE(cpp_test_network_sendto_udp) { + fossil_io_network_create(); + fossil_io_socket_t sock = fossil_io_network_create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + const char *message = "Hello, UDP!"; + int bytes_sent = fossil_io_network_sendto(sock, message, strlen(message), "127.0.0.1", 8081); + ASSUME_ITS_EQUAL_I32((int)strlen(message), bytes_sent); + fossil_io_network_close(sock); + fossil_io_network_destroy(); +} + FOSSIL_TEST_CASE(cpp_test_network_class_init) { int result = fossil::io::Network::init(); ASSUME_ITS_EQUAL_I32(0, result); @@ -95,7 +124,7 @@ FOSSIL_TEST_CASE(cpp_test_network_class_init) { FOSSIL_TEST_CASE(cpp_test_network_class_create_socket) { fossil::io::Network::init(); - fossil_io_socket_t sock = fossil::io::Network::create_socket(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil::io::Network::close(sock); fossil::io::Network::cleanup(); @@ -103,7 +132,7 @@ FOSSIL_TEST_CASE(cpp_test_network_class_create_socket) { FOSSIL_TEST_CASE(cpp_test_network_class_bind) { fossil::io::Network::init(); - fossil_io_socket_t sock = fossil::io::Network::create_socket(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); int result = fossil::io::Network::bind(sock, "127.0.0.1", 8080); ASSUME_ITS_EQUAL_I32(0, result); @@ -113,7 +142,7 @@ FOSSIL_TEST_CASE(cpp_test_network_class_bind) { FOSSIL_TEST_CASE(cpp_test_network_class_listen) { fossil::io::Network::init(); - fossil_io_socket_t sock = fossil::io::Network::create_socket(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil::io::Network::bind(sock, "127.0.0.1", 8080); int result = fossil::io::Network::listen(sock, 5); @@ -124,10 +153,38 @@ FOSSIL_TEST_CASE(cpp_test_network_class_listen) { FOSSIL_TEST_CASE(cpp_test_network_class_close) { fossil::io::Network::init(); - fossil_io_socket_t sock = fossil::io::Network::create_socket(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_TCP); ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); fossil::io::Network::close(sock); - // No direct way to test close, but we assume no errors if it reaches here + fossil::io::Network::cleanup(); +} + +FOSSIL_TEST_CASE(cpp_test_network_class_create_udp_socket) { + fossil::io::Network::init(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + fossil::io::Network::close(sock); + fossil::io::Network::cleanup(); +} + +FOSSIL_TEST_CASE(cpp_test_network_class_bind_udp) { + fossil::io::Network::init(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + int result = fossil::io::Network::bind(sock, "127.0.0.1", 8081); + ASSUME_ITS_EQUAL_I32(0, result); + fossil::io::Network::close(sock); + fossil::io::Network::cleanup(); +} + +FOSSIL_TEST_CASE(cpp_test_network_class_sendto_udp) { + fossil::io::Network::init(); + fossil_io_socket_t sock = fossil::io::Network::create_socket(FOSSIL_IO_SOCKET_TYPE_UDP); + ASSUME_NOT_EQUAL_I32(FOSSIL_IO_INVALID_SOCKET, sock); + const char *message = "Hello, UDP!"; + int bytes_sent = fossil::io::Network::sendto(sock, message, strlen(message), "127.0.0.1", 8081); + ASSUME_ITS_EQUAL_I32((int)strlen(message), bytes_sent); + fossil::io::Network::close(sock); fossil::io::Network::cleanup(); } @@ -141,12 +198,18 @@ FOSSIL_TEST_GROUP(cpp_network_tests) { FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_bind); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_listen); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_close); + FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_create_udp_socket); + FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_bind_udp); + FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_sendto_udp); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_init); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_create_socket); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_bind); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_listen); FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_close); + FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_create_udp_socket); + FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_bind_udp); + FOSSIL_TEST_ADD(cpp_network_suite, cpp_test_network_class_sendto_udp); FOSSIL_TEST_REGISTER(cpp_network_suite); }