#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include "addr.h" #include "server.h" #include "resolver.h" #include "../io/log.h" #include "../io/map.h" #include "../io/config.h" static pthread_t udp, tcp; static RecordMap map; 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); load_config("config", &map); } struct DnsRequest { Connection connection; Packet request; }; static void* server_respond(void* arg) { struct DnsRequest req = *(struct DnsRequest*) arg; INFO("Recieved packet request ID %hu", req.request.header.id); Packet response; handle_query(&req.request, &response, req.connection.type, &map); if (!write_connection(&req.connection, &response)) { ERROR("Faled to respond to connection ID %hu: %s", req.request.header.id, strerror(errno) ); } free_packet(&req.request); free_connection(&req.connection); if (response.header.z == false) { free_packet(&response); } else { // Dont free from config free(response.questions); free(response.answers); free(response.authorities); free(response.resources); } return NULL; } static void* server_listen(void* arg) { Binding* binding = (Binding*) arg; 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; } struct DnsRequest req; req.connection = connection; req.request = request; pthread_t thread; if(pthread_create(&thread, NULL, &server_respond, &req)) { ERROR("Failed to create thread for dns request ID %hu: %s", request.header.id, strerror(errno) ); free_packet(&request); free_connection(&connection); continue; } pthread_detach(thread); } return NULL; } static void signal_handler() { printf("\n"); pthread_kill(udp, SIGTERM); pthread_kill(tcp, SIGTERM); } void server_run(Server* server) { if (!pthread_create(&udp, NULL, &server_listen, &server->udp)) { INFO("Listening for connections on UDP"); } else { ERROR("Failed to start UDP thread"); exit(EXIT_FAILURE); } if (!pthread_create(&tcp, NULL, &server_listen, &server->tcp)) { INFO("Listening for connections on TCP"); } else { ERROR("Failed to start TCP thread"); exit(EXIT_FAILURE); } signal(SIGINT, signal_handler); pthread_join(udp, NULL); pthread_join(tcp, NULL); pthread_exit(0); } void server_free(Server* server) { free_binding(&server->udp); free_binding(&server->tcp); record_map_free(&map); }