diff options
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/addr.c | 233 | ||||
-rw-r--r-- | src/server/addr.h | 69 | ||||
-rw-r--r-- | src/server/binding.c | 245 | ||||
-rw-r--r-- | src/server/binding.h | 42 | ||||
-rw-r--r-- | src/server/resolver.c | 166 | ||||
-rw-r--r-- | src/server/resolver.h | 6 | ||||
-rw-r--r-- | src/server/server.c | 100 | ||||
-rw-r--r-- | src/server/server.h | 12 |
8 files changed, 873 insertions, 0 deletions
diff --git a/src/server/addr.c b/src/server/addr.c new file mode 100644 index 0000000..982da13 --- /dev/null +++ b/src/server/addr.c @@ -0,0 +1,233 @@ +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "addr.h" +#include "../io/log.h" + +void create_ip_addr(char* domain, IpAddr* addr) { + addr->type = V4; + memcpy(&addr->data.v4.s_addr, domain, 4); +} + +void create_ip_addr6(char* domain, IpAddr* addr) { + addr->type = V6; + memcpy(&addr->data.v6.__in6_u.__u6_addr8, domain, 16); +} + +void ip_addr_any(IpAddr* addr) { + addr->type = V4; + addr->data.v4.s_addr = htonl(INADDR_ANY); +} + +void ip_addr_any6(IpAddr* addr) { + addr->type = V6; + addr->data.v6 = in6addr_any; +} + +static struct sockaddr_in create_socket_addr_v4(IpAddr addr, uint16_t port) { + struct sockaddr_in socketaddr; + memset(&socketaddr, 0, sizeof(socketaddr)); + socketaddr.sin_family = AF_INET; + socketaddr.sin_port = htons(port); + socketaddr.sin_addr = addr.data.v4; + return socketaddr; +} + +static struct sockaddr_in6 create_socket_addr_v6(IpAddr addr, uint16_t port) { + struct sockaddr_in6 socketaddr; + memset(&socketaddr, 0, sizeof(socketaddr)); + socketaddr.sin6_family = AF_INET6; + socketaddr.sin6_port = htons(port); + socketaddr.sin6_addr = addr.data.v6; + return socketaddr; +} + +static size_t get_addr_len(AddrType type) { + if (type == V4) { + return sizeof(struct sockaddr_in); + } else if (type == V6) { + return sizeof(struct sockaddr_in6); + } else { + return 0; + } +} + +void create_socket_addr(uint16_t port, IpAddr addr, SocketAddr* socket) { + socket->type = addr.type; + if (addr.type == V4) { + socket->data.v4 = create_socket_addr_v4(addr, port); + } else if(addr.type == V6) { + socket->data.v6 = create_socket_addr_v6(addr, port); + } else { + ERROR("Tried to create socketaddr with invalid protocol type"); + exit(EXIT_FAILURE); + } + socket->len = get_addr_len(addr.type); +} + +void print_socket_addr(SocketAddr* addr, char* buffer) { + INIT_LOG_BOUNDS + if(addr->type == V4) { + APPEND(buffer, "%hhu.%hhu.%hhu.%hhu:%hu", + (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr >> 24), + (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr >> 16), + (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr >> 8), + (uint8_t) ((uint32_t)addr->data.v4.sin_addr.s_addr), + addr->data.v4.sin_port + ); + } else { + for(int i = 0; i < 8; i++) { + APPEND(buffer, "%02hhx%02hhx:", + addr->data.v6.sin6_addr.__in6_u.__u6_addr8[i*2 + 0], + addr->data.v6.sin6_addr.__in6_u.__u6_addr8[i*2 + 1] + ); + } + APPEND(buffer, ":[%hu]", addr->data.v6.sin6_port); + } +} + +#define ADDR_DOMAIN(addr, var) \ + struct sockaddr* var; \ + if (addr->type == V4) { \ + var = (struct sockaddr*) &addr->data.v4; \ + } else if (addr->type == V6) { \ + var = (struct sockaddr*) &addr->data.v6; \ + } else { \ + return -1; \ + } + +#define ADDR_AFNET(type, var) \ + int var; \ + if (type == V4) { \ + var = AF_INET; \ + } else if (type == V6) { \ + var = AF_INET6; \ + } else { \ + return -1; \ + } + +int32_t create_udp_socket(AddrType type, UdpSocket* sock) { + ADDR_AFNET(type, __domain) + sock->type = type; + sock->sockfd = socket(__domain, SOCK_DGRAM, 0); + return sock->sockfd; +} + +int32_t bind_udp_socket(SocketAddr* addr, UdpSocket* sock) { + if (addr->type == V6) { + int v6OnlyEnabled = 0; + int32_t res = setsockopt( + sock->sockfd, + IPPROTO_IPV6, + IPV6_V6ONLY, + &v6OnlyEnabled, + sizeof(v6OnlyEnabled) + ); + if (res < 0) return res; + } + ADDR_DOMAIN(addr, __addr) + return bind(sock->sockfd, __addr, addr->len); +} + +int32_t read_udp_socket(UdpSocket* socket, void* buffer, uint16_t len, SocketAddr* clientaddr) { + clientaddr->type = socket->type; + clientaddr->len = get_addr_len(socket->type); + ADDR_DOMAIN(clientaddr, __addr) + return recvfrom( + socket->sockfd, + buffer, + (size_t) len, + MSG_WAITALL, + __addr, + (uint32_t*) &clientaddr->len + ); +} + +int32_t write_udp_socket(UdpSocket* socket, void* buffer, uint16_t len, SocketAddr* clientaddr) { + ADDR_DOMAIN(clientaddr, __addr) + return sendto( + socket->sockfd, + buffer, + (size_t) len, + MSG_CONFIRM, + __addr, + (uint32_t) clientaddr->len + ); +} + +int32_t close_udp_socket(UdpSocket* socket) { + return close(socket->sockfd); +} + +int32_t create_tcp_socket(AddrType type, TcpSocket* sock) { + ADDR_AFNET(type, __domain) + sock->type = type; + sock->sockfd = socket(__domain, SOCK_STREAM, 0); + return sock->sockfd; +} + +int32_t bind_tcp_socket(SocketAddr* addr, TcpSocket* sock) { + if (addr->type == V6) { + int v6OnlyEnabled = 0; + int32_t res = setsockopt( + sock->sockfd, + IPPROTO_IPV6, + IPV6_V6ONLY, + &v6OnlyEnabled, + sizeof(v6OnlyEnabled) + ); + if (res < 0) return res; + } + ADDR_DOMAIN(addr, __addr) + return bind(sock->sockfd, __addr, addr->len); +} + +int32_t listen_tcp_socket(TcpSocket* socket, uint32_t max) { + return listen(socket->sockfd, max); +} + +int32_t accept_tcp_socket(TcpSocket* socket, TcpStream* stream) { + stream->clientaddr.type = socket->type; + memset(&stream->clientaddr, 0, sizeof(SocketAddr)); + SocketAddr* addr = &stream->clientaddr; + ADDR_DOMAIN(addr, __addr) + stream->streamfd = accept( + socket->sockfd, + __addr, + (uint32_t*) &stream->clientaddr.len + ); + return stream->streamfd; +} + +int32_t close_tcp_socket(TcpSocket* socket) { + return close(socket->sockfd); +} + +int32_t connect_tcp_stream(SocketAddr* servaddr, TcpStream* stream) { + TcpSocket socket; + int32_t res = create_tcp_socket(servaddr->type, &socket); + if (res < 0) return res; + stream->clientaddr = *servaddr; + stream->streamfd = socket.sockfd; + ADDR_DOMAIN(servaddr, __addr) + return connect( + socket.sockfd, + __addr, + servaddr->len + ); +} + +int32_t read_tcp_stream(TcpStream* stream, void* buffer, uint16_t len) { + return recv(stream->streamfd, buffer, len, 0); +} + +int32_t write_tcp_stream(TcpStream* stream, void* buffer, uint16_t len) { + return send(stream->streamfd, buffer, len, MSG_NOSIGNAL); +} + +int32_t close_tcp_stream(TcpStream* stream) { + return close(stream->streamfd); +} diff --git a/src/server/addr.h b/src/server/addr.h new file mode 100644 index 0000000..173c7fd --- /dev/null +++ b/src/server/addr.h @@ -0,0 +1,69 @@ +#pragma once + +#include "../packet/record.h" + +#include <string.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> + +typedef enum { + V4, + V6 +} AddrType; + +typedef struct { + AddrType type; + union { + struct in_addr v4; + struct in6_addr v6; + } data; +} IpAddr; + +void create_ip_addr(char* domain, IpAddr* addr); +void create_ip_addr6(char* domain, IpAddr* addr); +void ip_addr_any(IpAddr* addr); +void ip_addr_any6(IpAddr* addr); + +typedef struct { + AddrType type; + union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } data; + size_t len; +} SocketAddr; + +void create_socket_addr(uint16_t port, IpAddr addr, SocketAddr* socket); +void print_socket_addr(SocketAddr* addr, char* buffer); + +typedef struct { + AddrType type; + uint32_t sockfd; +} UdpSocket; + +int32_t create_udp_socket(AddrType type, UdpSocket* socket); +int32_t bind_udp_socket(SocketAddr* addr, UdpSocket* socket); +int32_t read_udp_socket(UdpSocket* socket, void* buffer, uint16_t len, SocketAddr* clientaddr); +int32_t write_udp_socket(UdpSocket* socket, void* buffer, uint16_t len, SocketAddr* clientaddr); +int32_t close_udp_socket(UdpSocket* socket); + +typedef struct { + AddrType type; + uint32_t sockfd; +} TcpSocket; + +typedef struct { + SocketAddr clientaddr; + uint32_t streamfd; +} TcpStream; + +int32_t create_tcp_socket(AddrType type, TcpSocket* socket); +int32_t bind_tcp_socket(SocketAddr* addr, TcpSocket* socket); +int32_t listen_tcp_socket(TcpSocket* socket, uint32_t max); +int32_t accept_tcp_socket(TcpSocket* socket, TcpStream* stream); +int32_t close_tcp_socket(TcpSocket* socket); +int32_t connect_tcp_stream(SocketAddr* servaddr, TcpStream* stream); +int32_t read_tcp_stream(TcpStream* stream, void* buffer, uint16_t len); +int32_t write_tcp_stream(TcpStream* stream, void* buffer, uint16_t len); +int32_t close_tcp_stream(TcpStream* stream); diff --git a/src/server/binding.c b/src/server/binding.c new file mode 100644 index 0000000..47c62c6 --- /dev/null +++ b/src/server/binding.c @@ -0,0 +1,245 @@ +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "addr.h" +#include "binding.h" +#include "../io/log.h" + +static void create_udp_binding(UdpSocket* socket, uint16_t port) { + if (create_udp_socket(V6, socket) < 0) { + ERROR("Failed to create UDP socket: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + IpAddr addr; + ip_addr_any6(&addr); + + SocketAddr socketaddr; + create_socket_addr(port, addr, &socketaddr); + + if (bind_udp_socket(&socketaddr, socket) < 0) { + ERROR("Failed to bind UDP socket on port %hu: %s", port, strerror(errno)); + exit(EXIT_FAILURE); + } +} + +static void create_tcp_binding(TcpSocket* socket, uint16_t port) { + if (create_tcp_socket(V6, socket) < 0) { + ERROR("Failed to create TCP socket: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + IpAddr addr; + ip_addr_any6(&addr); + + SocketAddr socketaddr; + create_socket_addr(port, addr, &socketaddr); + + if (bind_tcp_socket(&socketaddr, socket) < 0) { + ERROR("Failed to bind TCP socket on port %hu: %s", port, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (listen_tcp_socket(socket, 5) < 0) { + ERROR("Failed to listen on TCP socket: %s", strerror(errno)); + exit(EXIT_FAILURE); + } +} + +void create_binding(BindingType type, uint16_t port, Binding* binding) { + binding->type = type; + if (type == UDP) { + create_udp_binding(&binding->sock.udp, port); + } else if(type == TCP) { + create_tcp_binding(&binding->sock.tcp, port); + } else { + exit(EXIT_FAILURE); + } +} + +void free_binding(Binding* binding) { + if (binding->type == UDP) { + close_udp_socket(&binding->sock.udp); + } else if(binding->type == TCP) { + close_tcp_socket(&binding->sock.tcp); + } +} + +bool accept_connection(Binding* binding, Connection* connection) { + connection->type = binding->type; + + if(binding->type == UDP) { + connection->sock.udp.udp = binding->sock.udp; + memset(&connection->sock.udp.clientaddr, 0, sizeof(SocketAddr)); + return true; + } + + if (accept_tcp_socket(&binding->sock.tcp, &connection->sock.tcp) < 0) { + ERROR("Failed to accept TCP connection: %s", strerror(errno)); + return false; + } + + return true; +} + +static void read_to_packet(uint8_t* buf, uint16_t len, Packet* packet) { + PacketBuffer* pkbuffer = buffer_create(len); + for (int i = 0; i < len; i++) { + buffer_write(pkbuffer, buf[i]); + } + buffer_seek(pkbuffer, 0); + read_packet(pkbuffer, packet); + buffer_free(pkbuffer); +} + +static bool read_udp(Connection* connection, Packet* packet) { + uint8_t buffer[512]; + int32_t n = read_udp_socket( + &connection->sock.udp.udp, + buffer, + 512, + &connection->sock.udp.clientaddr + ); + if (n < 0) { + return false; + } + read_to_packet(buffer, n, packet); + return true; +} + +static bool read_tcp(Connection* connection, Packet* packet) { + uint16_t len; + if ( read_tcp_stream( + &connection->sock.tcp, + &len, + sizeof(uint16_t) + ) < 0) { + return false; + } + + uint8_t buffer[len]; + if ( read_tcp_stream( + &connection->sock.tcp, + buffer, + len + ) < 0) { + return false; + } + + read_to_packet(buffer, len, packet); + return true; +} + +bool read_connection(Connection* connection, Packet* packet) { + if (connection->type == UDP) { + return read_udp(connection, packet); + } else if (connection->type == TCP) { + return read_tcp(connection, packet); + } + return false; +} + +static bool write_udp(Connection* connection, uint8_t* buf, uint16_t len) { + //if (len > 512) { + buf[2] = buf[2] | 0x03; + // len = 512; + // } + return write_udp_socket( + &connection->sock.udp.udp, + buf, + len, + &connection->sock.udp.clientaddr + ) == len; +} + +static bool write_tcp(Connection* connection, uint8_t* buf, uint16_t len) { + len = htons(len); + if (write_tcp_stream( + &connection->sock.tcp, + &len, + sizeof(uint16_t) + ) < 0) { + return false; + } + + if (write_tcp_stream( + &connection->sock.tcp, + buf, + len + ) < 0) { + return false; + } + + return true; +} + +bool write_connection(Connection* connection, Packet* packet) { + PacketBuffer* pkbuffer = buffer_create(64); + write_packet(pkbuffer, packet); + uint16_t len = buffer_get_size(pkbuffer); + uint8_t* buffer = buffer_get_ptr(pkbuffer); + bool success = false; + if(connection->type == UDP) { + success = write_udp(connection, buffer, len); + } else if(connection->type == TCP) { + success = write_tcp(connection, buffer, len); + }; + buffer_free(pkbuffer); + return success; +} + +void free_connection(Connection* connection) { + if (connection->type == TCP) { + close_tcp_stream(&connection->sock.tcp); + } +} + +static bool create_udp_request(SocketAddr* addr, Connection* request) { + if ( create_udp_socket(addr->type, &request->sock.udp.udp) < 0) { + ERROR("Failed to connect to UDP socket: %s", strerror(errno)); + return false; + } + request->sock.udp.clientaddr = *addr; + return true; +} + +static bool create_tcp_request(SocketAddr* addr, Connection* request) { + if( connect_tcp_stream(addr, &request->sock.tcp) < 0) { + ERROR("Failed to connect to TCP socket: %s", strerror(errno)); + return false; + } + return true; +} + +bool create_request(BindingType type, SocketAddr* addr, Connection* request) { + request->type = type; + if (type == UDP) { + return create_udp_request(addr, request); + } else if (type == TCP) { + return create_tcp_request(addr, request); + } else { + return true; + } +} + +bool request_packet(Connection* request, Packet* in, Packet* out) { + if (!write_connection(request, in)) { + return false; + } + if (!read_connection(request, out)) { + return false; + } + return true; +} + +void free_request(Connection* connection) { + if (connection->type == UDP) { + close_udp_socket(&connection->sock.udp.udp); + } else if (connection->type == TCP) { + close_tcp_stream(&connection->sock.tcp); + } +} diff --git a/src/server/binding.h b/src/server/binding.h new file mode 100644 index 0000000..e2e6160 --- /dev/null +++ b/src/server/binding.h @@ -0,0 +1,42 @@ +#pragma once + +#include "../packet/packet.h" +#include "addr.h" + +#include <netinet/in.h> + +typedef enum { + UDP, + TCP +} BindingType; + +typedef struct { + BindingType type; + union { + UdpSocket udp; + TcpSocket tcp; + } sock; +} Binding; + +void create_binding(BindingType type, uint16_t port, Binding* binding); +void free_binding(Binding* binding); + +typedef struct { + BindingType type; + union { + struct { + UdpSocket udp; + SocketAddr clientaddr; + } udp; + TcpStream tcp; + } sock; +} Connection; + +bool accept_connection(Binding* binding, Connection* connection); +bool read_connection(Connection* connection, Packet* packet); +bool write_connection(Connection* connection, Packet* packet); +void free_connection(Connection* connection); + +bool create_request(BindingType type, SocketAddr* addr, Connection* request); +bool request_packet(Connection* request, Packet* in, Packet* out); +void free_request(Connection* connection); diff --git a/src/server/resolver.c b/src/server/resolver.c new file mode 100644 index 0000000..e05f365 --- /dev/null +++ b/src/server/resolver.c @@ -0,0 +1,166 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "resolver.h" +#include "addr.h" +#include "binding.h" +#include "../io/log.h" + +static bool lookup( + Question* question, + Packet* response, + BindingType type, + SocketAddr addr +) { + INIT_LOG_BUFFER(log) + LOGONLY(print_socket_addr(&addr, log);) + TRACE("Attempting lookup on fallback dns %s", log); + + Connection request; + if (!create_request(type, &addr, &request)) { + return false; + } + + Packet req; + memset(&req, 0, sizeof(Packet)); + req.header.id = response->header.id; + req.header.opcode = response->header.opcode; + req.header.questions = 1; + req.header.recursion_desired = true; + req.questions = malloc(sizeof(Question)); + req.questions[0] = *question; + + if (!request_packet(&request, &req, response)) { + free_request(&request); + free(req.questions); + ERROR("Failed to request fallback dns: %s", strerror(errno)); + return false; + } + + free_request(&request); + free(req.questions); + return true; +} + +static bool search(Question* question, Packet* result, BindingType type) { + IpAddr addr; + char ip[4] = {1, 1, 1, 1}; + create_ip_addr(ip, &addr); + + uint16_t port = 53; + SocketAddr saddr; + create_socket_addr(port, addr, &saddr); + + while(1) { + if (!lookup(question, result, type, saddr)) { + return false; + } + + if (result->header.answers > 0 && result->header.rescode == NOERROR) { + return true; + } + + if (result->header.rescode == NXDOMAIN) { + return true; + } + + if (get_resolved_ns(result, question->domain, &addr)) { + continue; + } + + Question new_question; + if (!get_unresoled_ns(result, question->domain, &new_question)) { + return true; + } + + Packet recurse; + if (!search(&new_question, &recurse, type)) { + return false; + } + + free_question(&new_question); + + IpAddr random; + if (!get_random_a(&recurse, &random)) { + free_packet(&recurse); + return true; + } else { + free_packet(&recurse); + addr = random; + } + } +} + +static void push_records(Record* from, uint8_t from_len, Record** to, uint8_t to_len) { + if(from_len < 1) return; + *to = realloc(*to, sizeof(Record) * (from_len + to_len)); + memcpy(*to + to_len, from, from_len * sizeof(Record)); +} + +static void push_questions(Question* from, uint8_t from_len, Question** to, uint8_t to_len) { + if(from_len < 1) return; + *to = realloc(*to, sizeof(Question) * (from_len + to_len)); + memcpy(*to + to_len, from, from_len * sizeof(Question)); +} + +void handle_query(Packet* request, Packet* response, BindingType type) { + memset(response, 0, sizeof(Packet)); + response->header.id = request->header.id; + response->header.opcode = request->header.opcode; + response->header.recursion_desired = true; + response->header.recursion_available = true; + response->header.response = true; + + if (request->header.questions < 1) { + response->header.response = FORMERR; + return; + } + + for (uint16_t i = 0; i < request->header.questions; i++) { + Packet result; + memset(&result, 0, sizeof(Packet)); + result.header.id = response->header.id; + if (!search(&request->questions[i], &result, type)) { + response->header.response = SERVFAIL; + break; + } + + push_questions( + result.questions, + result.header.questions, + &response->questions, + response->header.questions + ); + response->header.questions += result.header.questions; + + push_records( + result.answers, + result.header.answers, + &response->answers, + response->header.answers + ); + response->header.answers += result.header.answers; + + push_records( + result.authorities, + result.header.authoritative_entries, + &response->authorities, + response->header.authoritative_entries + ); + response->header.authoritative_entries += result.header.authoritative_entries; + + push_records( + result.resources, + result.header.resource_entries, + &response->resources, + response->header.resource_entries + ); + response->header.resource_entries += result.header.resource_entries; + + free(result.questions); + free(result.answers); + free(result.authorities); + free(result.resources); + } +}
\ No newline at end of file diff --git a/src/server/resolver.h b/src/server/resolver.h new file mode 100644 index 0000000..79b4825 --- /dev/null +++ b/src/server/resolver.h @@ -0,0 +1,6 @@ +#pragma once + +#include "../packet/packet.h" +#include "binding.h" + +void handle_query(Packet* request, Packet* response, BindingType type);
\ No newline at end of file diff --git a/src/server/server.c b/src/server/server.c new file mode 100644 index 0000000..c8975ee --- /dev/null +++ b/src/server/server.c @@ -0,0 +1,100 @@ +#define _POSIX_SOURCE +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> +#include <signal.h> + +#include "addr.h" +#include "server.h" +#include "resolver.h" +#include "../io/log.h" + +static pid_t udp, tcp; + +void server_init(uint16_t port, Server* server) { + INFO("Server port set to %hu", port); + create_binding(UDP, port, &server->udp); + create_binding(TCP, port, &server->tcp); +} + +static void server_listen(Binding* binding) { + while(1) { + + Connection connection; + if (!accept_connection(binding, &connection)) { + ERROR("Failed to accept connection"); + continue; + } + + Packet request; + if (!read_connection(&connection, &request)) { + ERROR("Failed to read connection"); + free_connection(&connection); + continue; + } + + if(fork() != 0) { + free_packet(&request); + free_connection(&connection); + continue; + } + + INFO("Recieved packet request ID %hu", request.header.id); + + Packet response; + handle_query(&request, &response, connection.type); + + if (!write_connection(&connection, &response)) { + ERROR("Failed to respond to connection ID %hu: %s", request.header.id, strerror(errno)); + } + + free_packet(&request); + free_packet(&response); + free_connection(&connection); + exit(EXIT_SUCCESS); + } +} + +static void signal_handler() { + printf("\n"); + kill(udp, SIGTERM); + kill(tcp, SIGTERM); +} + +void server_run(Server* server) { + if ((udp = fork()) == 0) { + INFO("Listening for connections on UDP"); + server_listen(&server->udp); + exit(EXIT_SUCCESS); + } + + if ((tcp = fork()) == 0) { + INFO("Listening for connections on TCP"); + server_listen(&server->tcp); + exit(EXIT_SUCCESS); + } + + signal(SIGINT, signal_handler); + + int status; + waitpid(udp, &status, 0); + if (status == 0) { + INFO("UDP process closed successfully"); + } else { + ERROR("UDP process failed with error code %d", status); + } + + waitpid(tcp, &status, 0); + if (status == 0) { + INFO("TCP process closed successfully"); + } else { + ERROR("TCP process failed with error code %d", status); + } +} + +void server_free(Server* server) { + free_binding(&server->udp); + free_binding(&server->tcp); +} diff --git a/src/server/server.h b/src/server/server.h new file mode 100644 index 0000000..c9509f2 --- /dev/null +++ b/src/server/server.h @@ -0,0 +1,12 @@ +#pragma once + +#include "binding.h" + +typedef struct { + Binding udp; + Binding tcp; +} Server; + +void server_init(uint16_t port, Server* server); +void server_run(Server* server); +void server_free(Server* server);
\ No newline at end of file |