Skip to content

Commit

Permalink
Version 4.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vitlabuda committed Dec 4, 2022
1 parent f7c801c commit 6280ee9
Show file tree
Hide file tree
Showing 21 changed files with 292 additions and 197 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,9 @@

[4.2.0 @ 2022-12-03]
- Added the 'io.tun.multi_queue' configuration option, making it possible to configure whether each translator thread will be given its own TUN file descriptor or not

[4.3.0 @ 2022-12-04]
- Completely reworked signal handling, translator thread termination and packet I/O (receiving & sending)
- Vastly improved performance in case a single-queue TUN interface is used
- Removed the ability to use non-blocking file descriptors to receive and send packets
- Other minor improvements
6 changes: 3 additions & 3 deletions src/t64_conf_rfc7050.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _T64C_CONF_RFC7050__DNS_NAME "ipv4only.arpa."
#define _T64C_CONF_RFC7050__TARGET_IPV4_1 "\xc0\x00\x00\xaa"
#define _T64C_CONF_RFC7050__TARGET_IPV4_2 "\xc0\x00\x00\xab"
#define _T64C_CONF_RFC7050__RETRY_INTERVAL_SECONDS ((unsigned int) 3)
#define _T64C_CONF_RFC7050__RETRY_INTERVAL ((unsigned int) 3) // In seconds


static void _t64f_conf_rfc7050__print_info_log_message_on_start(void);
Expand All @@ -48,7 +48,7 @@ void t64f_conf_rfc7050__autodiscover_addressing_prefix_using_ipv4only_arpa(uint8
for(;;) {
struct addrinfo *results;
if(getaddrinfo(_T64C_CONF_RFC7050__DNS_NAME, NULL, (const struct addrinfo *) &hints, &results) != 0) {
sleep(_T64C_CONF_RFC7050__RETRY_INTERVAL_SECONDS);
sleep(_T64C_CONF_RFC7050__RETRY_INTERVAL);
continue;
}

Expand All @@ -67,7 +67,7 @@ void t64f_conf_rfc7050__autodiscover_addressing_prefix_using_ipv4only_arpa(uint8
}

freeaddrinfo(results);
sleep(_T64C_CONF_RFC7050__RETRY_INTERVAL_SECONDS);
sleep(_T64C_CONF_RFC7050__RETRY_INTERVAL);
}
}

Expand Down
29 changes: 3 additions & 26 deletions src/t64_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include"t64_tundra.h"
#include"t64_init.h"

#include"t64_utils.h"
#include"t64_log.h"
#include"t64_signal.h"
#include"t64_conf_cmdline.h"
#include"t64_conf_file.h"
#include"t64_opmode_translate.h"
Expand All @@ -35,7 +35,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

static void _t64f_init__check_compile_time_config(void);
static void _t64f_init__initialize_program(void);
static void _t64f_init__ignore_sigpipe(void);
static void _t64f_init__finalize_program(void);
static void _t64f_init__run_program_according_to_operation_mode(const t64ts_tundra__conf_cmdline *cmdline_configuration, const t64ts_tundra__conf_file *file_configuration);

Expand Down Expand Up @@ -82,37 +81,15 @@ static void _t64f_init__check_compile_time_config(void) {
static void _t64f_init__initialize_program(void) {
t64f_log__initialize(); // Must be called first!

t64f_signal__initialize();

if(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
t64f_log__crash(true, "Failed to set 'PR_SET_NO_NEW_PRIVS' to 1!");

_t64f_init__ignore_sigpipe();

if(setlocale(LC_ALL, "C") == NULL)
t64f_log__crash(false, "Failed to set the program's locale to 'C'!");
}

static void _t64f_init__ignore_sigpipe(void) {
/*
* It is ABSOLUTELY CRUCIAL for this program to ignore 'SIGPIPE' signals, as it handles errors caused by
* unexpectedly closed file descriptors itself, and is sometimes able to recover from them (for example,
* the subsystem dealing with external addressing mode [t64_xlat_addr_external.c] is programmed to reconnect to
* the configured external address translation server in case an unexpected error occurs)!
*/

sigset_t signal_mask;
sigemptyset(&signal_mask);

struct sigaction signal_action;
T64M_UTILS__MEMORY_ZERO_OUT(&signal_action, sizeof(struct sigaction));
signal_action.sa_handler = SIG_IGN;
signal_action.sa_mask = signal_mask;
signal_action.sa_flags = 0;
signal_action.sa_restorer = NULL;

if(sigaction(SIGPIPE, &signal_action, NULL) < 0)
t64f_log__crash(true, "Failed to make the program ignore the 'SIGPIPE' signal!");
}

static void _t64f_init__finalize_program(void) {
t64f_log__finalize(); // Must be called last!
}
Expand Down
17 changes: 2 additions & 15 deletions src/t64_init_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


// Creates the interface if it doesn't exist
int t64f_init_io__open_tun_interface(const t64ts_tundra__conf_file *file_configuration, const bool non_blocking) {
int t64f_init_io__open_tun_interface(const t64ts_tundra__conf_file *file_configuration) {
int tun_flags = IFF_TUN | IFF_NO_PI;
if(file_configuration->io_tun_multi_queue)
tun_flags |= IFF_MULTI_QUEUE;
Expand All @@ -37,11 +37,7 @@ int t64f_init_io__open_tun_interface(const t64ts_tundra__conf_file *file_configu
tun_interface_request.ifr_flags = tun_flags;
t64f_utils__secure_strncpy(tun_interface_request.ifr_name, file_configuration->io_tun_interface_name, IFNAMSIZ);

int open_flags = O_RDWR;
if(non_blocking)
open_flags |= O_NONBLOCK;

const int tun_fd = open(file_configuration->io_tun_device_path, open_flags);
const int tun_fd = open(file_configuration->io_tun_device_path, O_RDWR);
if(tun_fd < 0)
t64f_log__crash(true, "Failed to open the TUN device file: %s", file_configuration->io_tun_device_path);

Expand Down Expand Up @@ -87,15 +83,6 @@ char *t64f_init_io__get_fd_pair_from_inherited_fds_string(int *read_fd, int *wri
return (separator_ptr + 1);
}

void t64f_init_io__create_anonymous_pipe(int *pipe_read_fd, int *pipe_write_fd) {
int pipe_fds[2];
if(pipe(pipe_fds) < 0)
t64f_log__crash(true, "Failed to create a new anonymous pipe!");

*pipe_read_fd = pipe_fds[0];
*pipe_write_fd = pipe_fds[1];
}

void t64f_init_io__close_fd(const int fd, const bool ignore_ebadf) {
if(close(fd) < 0) {
if(ignore_ebadf && errno == EBADF)
Expand Down
3 changes: 1 addition & 2 deletions src/t64_init_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include"t64_tundra.h"


extern int t64f_init_io__open_tun_interface(const t64ts_tundra__conf_file *file_configuration, const bool non_blocking);
extern int t64f_init_io__open_tun_interface(const t64ts_tundra__conf_file *file_configuration);
extern void t64f_init_io__set_tun_interface_persistent(const int tun_fd, const bool tun_persistent);
extern void t64f_init_io__change_ownership_of_persistent_tun_interface(const t64ts_tundra__conf_file *file_configuration, const int persistent_tun_fd);
extern char *t64f_init_io__get_fd_pair_from_inherited_fds_string(int *read_fd, int *write_fd, char *next_fds_string_ptr, const char short_opt, const char *long_opt);
extern void t64f_init_io__create_anonymous_pipe(int *pipe_read_fd, int *pipe_write_fd);
extern void t64f_init_io__close_fd(const int fd, const bool ignore_ebadf);


Expand Down
6 changes: 2 additions & 4 deletions src/t64_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ void t64f_log__thread_info(const size_t thread_id, const char *format, ...) {
}

static void _t64f_log__print_log_message(const size_t thread_id, const bool print_errno, const char *category_banner, const char *format, va_list argument_list) {
if(pthread_mutex_lock(&_t64g_log__log_output_mutex) != 0)
exit(T64C_TUNDRA__EXIT_CODE_MUTEX_FAILURE);
pthread_mutex_lock(&_t64g_log__log_output_mutex);

fprintf(stderr, "[T%zu :: %s] ", thread_id, category_banner);
vfprintf(stderr, format, argument_list);
Expand All @@ -102,6 +101,5 @@ static void _t64f_log__print_log_message(const size_t thread_id, const bool prin

fflush(stderr);

if(pthread_mutex_unlock(&_t64g_log__log_output_mutex) != 0)
exit(T64C_TUNDRA__EXIT_CODE_MUTEX_FAILURE);
pthread_mutex_unlock(&_t64g_log__log_output_mutex);
}
2 changes: 1 addition & 1 deletion src/t64_opmode_mktun.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void t64f_opmode_mktun__run(const t64ts_tundra__conf_file *file_configuration) {
t64f_log__crash(false, "The I/O mode is not '"T64C_CONF_FILE__IO_MODE_TUN"'; therefore, persistent TUN interfaces cannot be created!");

{
const int tun_fd = t64f_init_io__open_tun_interface(file_configuration, false);
const int tun_fd = t64f_init_io__open_tun_interface(file_configuration);
t64f_init_io__set_tun_interface_persistent(tun_fd, true);
t64f_init_io__change_ownership_of_persistent_tun_interface(file_configuration, tun_fd);
t64f_init_io__close_fd(tun_fd, false);
Expand Down
3 changes: 2 additions & 1 deletion src/t64_opmode_print_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ static void _t64f_opmode_print_config__print_compile_time_config(void) {
printf("* %s = %s\n", _T64M_OPMODE_PRINT_CONFIG__STRINGIFY(T64C_TUNDRA__WORKING_DIRECTORY), _t64f_opmode_print_config__get_printable_representation_of_string(T64C_TUNDRA__WORKING_DIRECTORY));
printf("* %s = %zu\n", _T64M_OPMODE_PRINT_CONFIG__STRINGIFY(T64C_TUNDRA__MAX_TRANSLATOR_THREADS), T64C_TUNDRA__MAX_TRANSLATOR_THREADS);
printf("* %s = %zu\n", _T64M_OPMODE_PRINT_CONFIG__STRINGIFY(T64C_TUNDRA__MAX_ADDRESSING_EXTERNAL_CACHE_SIZE), T64C_TUNDRA__MAX_ADDRESSING_EXTERNAL_CACHE_SIZE);
printf("* %s = %u\n", _T64M_OPMODE_PRINT_CONFIG__STRINGIFY(T64C_TUNDRA__TRANSLATOR_THREAD_MONITOR_INTERVAL), T64C_TUNDRA__TRANSLATOR_THREAD_MONITOR_INTERVAL);
printf("* %s = %"PRIuMAX"\n", _T64M_OPMODE_PRINT_CONFIG__STRINGIFY(T64C_TUNDRA__TRANSLATOR_THREAD_MONITOR_INTERVAL), (uintmax_t) T64C_TUNDRA__TRANSLATOR_THREAD_MONITOR_INTERVAL);
printf("* %s = %"PRIuMAX"\n", _T64M_OPMODE_PRINT_CONFIG__STRINGIFY(T64C_TUNDRA__TRANSLATOR_THREAD_TERMINATION_INTERVAL), (uintmax_t) T64C_TUNDRA__TRANSLATOR_THREAD_TERMINATION_INTERVAL);

printf("\n");

Expand Down
2 changes: 1 addition & 1 deletion src/t64_opmode_rmtun.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void t64f_opmode_rmtun__run(const t64ts_tundra__conf_file *file_configuration) {
t64f_log__crash(false, "The I/O mode is not '"T64C_CONF_FILE__IO_MODE_TUN"'; therefore, persistent TUN interfaces cannot be removed!");

{
const int tun_fd = t64f_init_io__open_tun_interface(file_configuration, false);
const int tun_fd = t64f_init_io__open_tun_interface(file_configuration);
t64f_init_io__set_tun_interface_persistent(tun_fd, false);
t64f_init_io__close_fd(tun_fd, false);
}
Expand Down
79 changes: 48 additions & 31 deletions src/t64_opmode_translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include"t64_conf_cmdline.h"


static t64ts_tundra__xlat_thread_context *_t64fa_opmode_translate__initialize_xlat_thread_contexts(const t64ts_tundra__conf_cmdline *cmdline_configuration, const t64ts_tundra__conf_file *file_configuration, int termination_pipe_read_fd);
static t64ts_tundra__xlat_thread_context *_t64fa_opmode_translate__initialize_xlat_thread_contexts(const t64ts_tundra__conf_cmdline *cmdline_configuration, const t64ts_tundra__conf_file *file_configuration);
static void _t64fa_opmode_translate__initialize_packet_struct(t64ts_tundra__packet *packet);
static t64ts_tundra__external_addr_xlat_state *_t64fa_opmode_translate__initialize_external_addr_xlat_state_struct(const t64ts_tundra__conf_file *file_configuration, char **addressing_external_next_fds_string_ptr);
static void _t64f_opmode_translate__free_xlat_thread_contexts(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts);
Expand All @@ -41,7 +41,7 @@ static void _t64f_opmode_translate__daemonize(const t64ts_tundra__conf_file *fil
static void _t64f_opmode_translate__start_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts);
static void _t64f_opmode_translate__print_information_about_translation_start(const t64ts_tundra__conf_file *file_configuration);
static void _t64f_opmode_translate__monitor_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts);
static void _t64f_opmode_translate__terminate_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts, int termination_pipe_write_fd);
static void _t64f_opmode_translate__terminate_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts);


void t64f_opmode_translate__run(const t64ts_tundra__conf_cmdline *cmdline_configuration, const t64ts_tundra__conf_file *file_configuration) {
Expand All @@ -50,27 +50,20 @@ void t64f_opmode_translate__run(const t64ts_tundra__conf_cmdline *cmdline_config

t64f_log__info("%s", T64C_TUNDRA__PROGRAM_INFO_STRING);

int termination_pipe_read_fd, termination_pipe_write_fd;
t64f_init_io__create_anonymous_pipe(&termination_pipe_read_fd, &termination_pipe_write_fd);

t64ts_tundra__xlat_thread_context *thread_contexts = _t64fa_opmode_translate__initialize_xlat_thread_contexts(cmdline_configuration, file_configuration, termination_pipe_read_fd);
t64ts_tundra__xlat_thread_context *thread_contexts = _t64fa_opmode_translate__initialize_xlat_thread_contexts(cmdline_configuration, file_configuration);
_t64f_opmode_translate__daemonize(file_configuration);
_t64f_opmode_translate__start_xlat_threads(file_configuration, thread_contexts);
t64f_signal__set_signal_handlers();
_t64f_opmode_translate__print_information_about_translation_start(file_configuration);

_t64f_opmode_translate__monitor_xlat_threads(file_configuration, thread_contexts);

_t64f_opmode_translate__terminate_xlat_threads(file_configuration, thread_contexts, termination_pipe_write_fd);
_t64f_opmode_translate__terminate_xlat_threads(file_configuration, thread_contexts);
_t64f_opmode_translate__free_xlat_thread_contexts(file_configuration, thread_contexts);

t64f_init_io__close_fd(termination_pipe_read_fd, false);
t64f_init_io__close_fd(termination_pipe_write_fd, false);

t64f_log__info("Tundra will now terminate.");
}

static t64ts_tundra__xlat_thread_context *_t64fa_opmode_translate__initialize_xlat_thread_contexts(const t64ts_tundra__conf_cmdline *cmdline_configuration, const t64ts_tundra__conf_file *file_configuration, int termination_pipe_read_fd) {
static t64ts_tundra__xlat_thread_context *_t64fa_opmode_translate__initialize_xlat_thread_contexts(const t64ts_tundra__conf_cmdline *cmdline_configuration, const t64ts_tundra__conf_file *file_configuration) {
t64ts_tundra__xlat_thread_context *thread_contexts = t64fa_utils__allocate_zeroed_out_memory(file_configuration->program_translator_threads, sizeof(t64ts_tundra__xlat_thread_context));

if(file_configuration->io_mode == T64TE_TUNDRA__IO_MODE_INHERITED_FDS && cmdline_configuration->io_inherited_fds == NULL)
Expand All @@ -86,6 +79,7 @@ static t64ts_tundra__xlat_thread_context *_t64fa_opmode_translate__initialize_xl
// context[i].thread stays uninitialized (it is initialized in _t64f_opmode_translate_start_xlat_threads())
thread_contexts[i].thread_id = (i + 1); // Thread ID 0 is reserved for the main thread
thread_contexts[i].configuration = file_configuration;
thread_contexts[i].joined = false;

_t64fa_opmode_translate__initialize_packet_struct(&thread_contexts[i].in_packet);
_t64fa_opmode_translate__initialize_packet_struct(&thread_contexts[i].out_packet);
Expand All @@ -100,20 +94,18 @@ static t64ts_tundra__xlat_thread_context *_t64fa_opmode_translate__initialize_xl
NULL
);

thread_contexts[i].termination_pipe_read_fd = termination_pipe_read_fd;

switch(file_configuration->io_mode) {
case T64TE_TUNDRA__IO_MODE_INHERITED_FDS:
io_next_fds_string_ptr = t64f_init_io__get_fd_pair_from_inherited_fds_string(&thread_contexts[i].packet_read_fd, &thread_contexts[i].packet_write_fd, io_next_fds_string_ptr, T64C_CONF_CMDLINE__SHORTOPT_IO_INHERITED_FDS, T64C_CONF_CMDLINE__LONGOPT_IO_INHERITED_FDS);
break;

case T64TE_TUNDRA__IO_MODE_TUN:
if(file_configuration->io_tun_multi_queue) {
thread_contexts[i].packet_read_fd = t64f_init_io__open_tun_interface(file_configuration, false);
thread_contexts[i].packet_read_fd = t64f_init_io__open_tun_interface(file_configuration);
thread_contexts[i].packet_write_fd = thread_contexts[i].packet_read_fd;
} else {
if(single_queue_tun_fd < 0)
single_queue_tun_fd = t64f_init_io__open_tun_interface(file_configuration, true);
single_queue_tun_fd = t64f_init_io__open_tun_interface(file_configuration);

thread_contexts[i].packet_read_fd = single_queue_tun_fd;
thread_contexts[i].packet_write_fd = single_queue_tun_fd;
Expand Down Expand Up @@ -269,30 +261,55 @@ static void _t64f_opmode_translate__print_information_about_translation_start(co
}

static void _t64f_opmode_translate__monitor_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts) {
while(t64f_signal__should_translator_continue_running()) {
while(t64f_signal__should_this_thread_continue_running()) {
for(size_t i = 0; i < file_configuration->program_translator_threads; i++) {
if(pthread_tryjoin_np(thread_contexts[i].thread, NULL) != EBUSY)
t64f_log__crash(false, "A translator thread has terminated unexpectedly!");
}

sleep(T64C_TUNDRA__TRANSLATOR_THREAD_MONITOR_INTERVAL);
usleep(T64C_TUNDRA__TRANSLATOR_THREAD_MONITOR_INTERVAL);
}
}

static void _t64f_opmode_translate__terminate_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts, int termination_pipe_write_fd) {
// Inform the threads that they should terminate
{
const char write_char = 'x'; // The data are never read, so the value does not matter
if(write(termination_pipe_write_fd, &write_char, 1) != 1)
t64f_log__crash(true, "Failed to inform the translator threads that they should terminate!");
}
static void _t64f_opmode_translate__terminate_xlat_threads(const t64ts_tundra__conf_file *file_configuration, t64ts_tundra__xlat_thread_context *thread_contexts) {
// Even though it is extremely unlikely, threads may not terminate on first signal (due to a race condition - when
// the signal is delivered between t64f_signal__should_this_thread_continue_running() and a blocking system call);
// therefore, the termination is performed within an "infinite" loop.
for(;;) {
bool are_there_running_threads = false;

// Wait for the threads to terminate
for(size_t i = 0; i < file_configuration->program_translator_threads; i++) {
const int pthread_errno = pthread_join(thread_contexts[i].thread, NULL);
if(pthread_errno != 0) {
errno = pthread_errno;
t64f_log__crash(true, "Failed to join a translator thread!");
for(size_t i = 0; i < file_configuration->program_translator_threads; i++) {
if(thread_contexts[i].joined)
continue;

switch(pthread_tryjoin_np(thread_contexts[i].thread, NULL)) {
case 0:
{
thread_contexts[i].joined = true;
}
break;

case EBUSY:
{
are_there_running_threads = true;

// There is a possibility of a race condition occurring (when the thread terminates between
// pthread_tryjoin_np() and pthread_kill()), but it is ignored, because the chance of it
// occurring is extremely tiny, and there seems to be no easy (!) and performance-friendly way
// of implementing the termination process 100% atomically.
if(pthread_kill(thread_contexts[i].thread, T64C_SIGNAL__TRANSLATOR_THREAD_TERMINATION_SIGNAL) != 0)
t64f_log__crash(false, "Failed to inform a translator thread that it should terminate (using a signal)!");
}
break;

default:
t64f_log__crash(false, "Failed to join a translator thread!");
}
}

if(are_there_running_threads)
usleep(T64C_TUNDRA__TRANSLATOR_THREAD_TERMINATION_INTERVAL);
else
break;
}
}

0 comments on commit 6280ee9

Please sign in to comment.