@ -10,6 +10,9 @@
# define MAX_LINE_LEN 1024
# define INITIAL_CONNECTION_CAPACITY 4
# define INITIAL_SERVER_CAPACITY 4
# define INITIAL_CLIENT_CAPACITY 4
# define INITIAL_CONNECTION_V2_CAPACITY 4
// Helper function to trim whitespace
static char * trim ( char * str ) {
@ -49,192 +52,119 @@ static int parse_key_value(const char *line, char *key, size_t key_len,
return 0 ;
}
// Parse connection mode string
static config_conn_mode_t parse_mode ( const char * mode_str ) {
if ( ! mode_str ) return CONFIG_MODE_UNKNOWN ;
if ( strcasecmp ( mode_str , " client " ) = = 0 ) {
return CONFIG_MODE_CLIENT ;
} else if ( strcasecmp ( mode_str , " server " ) = = 0 ) {
return CONFIG_MODE_SERVER ;
}
return CONFIG_MODE_UNKNOWN ;
}
// Add a connection to the config
static int add_connection ( utun_config_t * config , const connection_config_t * conn ) {
if ( config - > connection_count > = config - > connection_capacity ) {
// Add a server to the config
static int add_server ( utun_config_t * config , const server_config_t * server ) {
if ( config - > server_count > = config - > server_capacity ) {
// Resize array
int new_capacity = config - > connection_capacity * 2 ;
connection_config_t * new_connections = realloc ( config - > connections ,
new_capacity * sizeof ( connection _config_t) ) ;
if ( ! new_connection s ) return - 1 ;
int new_capacity = config - > server_capacity * 2 ;
server_config_t * new_servers = realloc ( config - > servers ,
new_capacity * sizeof ( server_config_t ) ) ;
if ( ! new_servers ) return - 1 ;
config - > connections = new_connection s;
config - > connection _capacity = new_capacity ;
config - > servers = new_server s;
config - > server _capacity = new_capacity ;
}
// Copy connection data
memcpy ( & config - > connection s[ config - > connection_count ] , conn , sizeof ( connection _config_t) ) ;
config - > connection _count+ + ;
// Copy server data
memcpy ( & config - > server s[ config - > server_count ] , server , sizeof ( server _config_t) ) ;
config - > server _count+ + ;
return 0 ;
}
// Parse configuration file
utun_config_t * parse_config ( const char * filename ) {
FILE * fp = fopen ( filename , " r " ) ;
if ( ! fp ) {
fprintf ( stderr , " Failed to open config file: %s \n " , filename ) ;
return NULL ;
// Add a client to the config
static int add_client ( utun_config_t * config , const client_config_t * client ) {
if ( config - > client_count > = config - > client_capacity ) {
// Resize array
int new_capacity = config - > client_capacity * 2 ;
client_config_t * new_clients = realloc ( config - > clients ,
new_capacity * sizeof ( client_config_t ) ) ;
if ( ! new_clients ) return - 1 ;
config - > clients = new_clients ;
config - > client_capacity = new_capacity ;
}
// Allocate config structure
utun_config_t * config = calloc ( 1 , sizeof ( utun_config_t ) ) ;
if ( ! config ) {
fclose ( fp ) ;
return NULL ;
}
// Copy client data
memcpy ( & config - > clients [ config - > client_count ] , client , sizeof ( client_config_t ) ) ;
config - > client_count + + ;
// Initialize connection array
config - > connection_capacity = INITIAL_CONNECTION_CAPACITY ;
config - > connections = malloc ( config - > connection_capacity * sizeof ( connection_config_t ) ) ;
if ( ! config - > connections ) {
free ( config ) ;
fclose ( fp ) ;
return NULL ;
return 0 ;
}
// Add a route to connection v2
static int add_route_to_connection ( connection_config_v2_t * conn_v2 , const route_pair_t * route ) {
if ( conn_v2 - > route_count > = conn_v2 - > route_capacity ) {
// Resize array
int new_capacity = conn_v2 - > route_capacity = = 0 ? INITIAL_CONNECTION_V2_CAPACITY : conn_v2 - > route_capacity * 2 ;
route_pair_t * new_routes = realloc ( conn_v2 - > routes ,
new_capacity * sizeof ( route_pair_t ) ) ;
if ( ! new_routes ) return - 1 ;
conn_v2 - > routes = new_routes ;
conn_v2 - > route_capacity = new_capacity ;
}
char line [ MAX_LINE_LEN ] ;
char current_section [ 128 ] = " " ;
connection_config_t current_conn = { 0 } ;
int in_connection_section = 0 ;
// Copy route data
memcpy ( & conn_v2 - > routes [ conn_v2 - > route_count ] , route , sizeof ( route_pair_t ) ) ;
conn_v2 - > route_count + + ;
while ( fgets ( line , sizeof ( line ) , fp ) ) {
// Remove newline
line [ strcspn ( line , " \n " ) ] = ' \0 ' ;
char * trimmed = trim ( line ) ;
// Skip empty lines and comments
if ( strlen ( trimmed ) = = 0 | | trimmed [ 0 ] = = ' ; ' | | trimmed [ 0 ] = = ' # ' ) {
continue ;
}
// Check for section header
if ( trimmed [ 0 ] = = ' [ ' & & trimmed [ strlen ( trimmed ) - 1 ] = = ' ] ' ) {
// End previous connection section if any
if ( in_connection_section ) {
if ( strlen ( current_conn . name ) > 0 ) {
if ( add_connection ( config , & current_conn ) ! = 0 ) {
fprintf ( stderr , " Failed to add connection: %s \n " , current_conn . name ) ;
}
}
memset ( & current_conn , 0 , sizeof ( current_conn ) ) ;
in_connection_section = 0 ;
}
// Extract section name
strncpy ( current_section , trimmed + 1 , sizeof ( current_section ) - 1 ) ;
current_section [ sizeof ( current_section ) - 1 ] = ' \0 ' ;
current_section [ strcspn ( current_section , " ] " ) ] = ' \0 ' ;
trim ( current_section ) ;
// Check if it's a connection section
if ( strncmp ( current_section , " connection: " , 11 ) = = 0 ) {
in_connection_section = 1 ;
// Extract connection name
char * name = trim ( current_section + 11 ) ;
if ( strlen ( name ) > 0 ) {
strncpy ( current_conn . name , name , sizeof ( current_conn . name ) - 1 ) ;
}
}
continue ;
}
// Parse key-value pair
char key [ 256 ] , value [ 256 ] ;
if ( parse_key_value ( trimmed , key , sizeof ( key ) , value , sizeof ( value ) ) ! = 0 ) {
fprintf ( stderr , " Invalid key-value line: %s \n " , trimmed ) ;
continue ;
}
return 0 ;
}
// Add a connection v2 to the config
static int add_connection_v2 ( utun_config_t * config , const connection_config_v2_t * conn_v2 ) {
if ( config - > connection_v2_count > = config - > connection_v2_capacity ) {
// Resize array
int new_capacity = config - > connection_v2_capacity * 2 ;
connection_config_v2_t * new_connections = realloc ( config - > connections_v2 ,
new_capacity * sizeof ( connection_config_v2_t ) ) ;
if ( ! new_connections ) return - 1 ;
// Process based on current section
if ( strcasecmp ( current_section , " global " ) = = 0 ) {
if ( strcasecmp ( key , " my_private_key " ) = = 0 ) {
strncpy ( config - > global . my_private_key_hex , value , sizeof ( config - > global . my_private_key_hex ) - 1 ) ;
} else if ( strcasecmp ( key , " my_public_key " ) = = 0 ) {
strncpy ( config - > global . my_public_key_hex , value , sizeof ( config - > global . my_public_key_hex ) - 1 ) ;
} else if ( strcasecmp ( key , " option " ) = = 0 ) {
strncpy ( config - > global . option_value , value , sizeof ( config - > global . option_value ) - 1 ) ;
} else if ( strcasecmp ( key , " control_ip " ) = = 0 ) {
strncpy ( config - > global . control_ip , value , sizeof ( config - > global . control_ip ) - 1 ) ;
} else if ( strcasecmp ( key , " control_port " ) = = 0 ) {
config - > global . control_port = atoi ( value ) ;
} else if ( strcasecmp ( key , " net_debug " ) = = 0 ) {
config - > global . net_debug = atoi ( value ) ;
}
} else if ( strcasecmp ( current_section , " routing " ) = = 0 ) {
if ( strcasecmp ( key , " allowed_subnet " ) = = 0 ) {
if ( config - > allowed_subnet_count < MAX_ALLOWED_SUBNETS ) {
strncpy ( config - > allowed_subnets [ config - > allowed_subnet_count ] . subnet , value , sizeof ( config - > allowed_subnets [ 0 ] . subnet ) - 1 ) ;
config - > allowed_subnet_count + + ;
} else {
fprintf ( stderr , " Too many allowed subnets, maximum is %d \n " , MAX_ALLOWED_SUBNETS ) ;
}
}
} else if ( in_connection_section ) {
if ( strcasecmp ( key , " mode " ) = = 0 ) {
current_conn . mode = parse_mode ( value ) ;
} else if ( strcasecmp ( key , " addr " ) = = 0 ) {
// For server mode
if ( current_conn . mode = = CONFIG_MODE_SERVER ) {
strncpy ( current_conn . local_addr , value , sizeof ( current_conn . local_addr ) - 1 ) ;
}
} else if ( strcasecmp ( key , " from_addr " ) = = 0 ) {
// For client mode
if ( current_conn . mode = = CONFIG_MODE_CLIENT ) {
strncpy ( current_conn . local_addr , value , sizeof ( current_conn . local_addr ) - 1 ) ;
}
} else if ( strcasecmp ( key , " to_addr " ) = = 0 ) {
// For client mode
if ( current_conn . mode = = CONFIG_MODE_CLIENT ) {
strncpy ( current_conn . remote_addr , value , sizeof ( current_conn . remote_addr ) - 1 ) ;
}
} else if ( strcasecmp ( key , " peer_public_key " ) = = 0 ) {
strncpy ( current_conn . peer_public_key_hex , value , sizeof ( current_conn . peer_public_key_hex ) - 1 ) ;
} else if ( strcasecmp ( key , " so_mark " ) = = 0 ) {
current_conn . so_mark = atoi ( value ) ;
} else if ( strcasecmp ( key , " netif " ) = = 0 ) {
strncpy ( current_conn . netif , value , sizeof ( current_conn . netif ) - 1 ) ;
} else if ( strcasecmp ( key , " tun " ) = = 0 ) {
strncpy ( current_conn . tun_ifname , value , sizeof ( current_conn . tun_ifname ) - 1 ) ;
} else if ( strcasecmp ( key , " tun_ip " ) = = 0 ) {
strncpy ( current_conn . tun_ip , value , sizeof ( current_conn . tun_ip ) - 1 ) ;
}
}
config - > connections_v2 = new_connections ;
config - > connection_v2_capacity = new_capacity ;
}
// Add last connection if any
if ( in_connection_section & & strlen ( current_conn . name ) > 0 ) {
if ( add_connection ( config , & current_conn ) ! = 0 ) {
fprintf ( stderr , " Failed to add connection: %s \n " , current_conn . name ) ;
}
}
// Copy connection data
memcpy ( & config - > connections_v2 [ config - > connection_v2_count ] , conn_v2 , sizeof ( connection_config_v2_t ) ) ;
config - > connection_v2_count + + ;
fclose ( fp ) ;
return config ;
return 0 ;
}
// Parse configuration file
utun_config_t * parse_config ( const char * filename ) {
/* Parse only v2 format */
return parse_config_v2 ( filename ) ;
}
// Free configuration structure
void free_config ( utun_config_t * config ) {
if ( ! config ) return ;
if ( config - > connections ) {
free ( config - > connections ) ;
if ( config - > servers ) {
free ( config - > servers ) ;
}
if ( config - > clients ) {
free ( config - > clients ) ;
}
if ( config - > connections_v2 ) {
for ( int i = 0 ; i < config - > connection_v2_count ; i + + ) {
if ( config - > connections_v2 [ i ] . routes ) {
free ( config - > connections_v2 [ i ] . routes ) ;
}
}
free ( config - > connections_v2 ) ;
}
free ( config ) ;
}
@ -259,21 +189,39 @@ void print_config(const utun_config_t *config) {
}
printf ( " \n " ) ;
printf ( " Connections (%d): \n " , config - > connection_count ) ;
for ( int i = 0 ; i < config - > connection_count ; i + + ) {
const connection_config_t * conn = & config - > connections [ i ] ;
printf ( " [%d] %s: \n " , i , conn - > name ) ;
printf ( " mode: %s \n " ,
conn - > mode = = CONFIG_MODE_CLIENT ? " client " :
conn - > mode = = CONFIG_MODE_SERVER ? " server " : " unknown " ) ;
printf ( " local_addr: %s \n " , conn - > local_addr ) ;
printf ( " remote_addr: %s \n " , conn - > remote_addr ) ;
printf ( " Servers (%d): \n " , config - > server_count ) ;
for ( int i = 0 ; i < config - > server_count ; i + + ) {
const server_config_t * server = & config - > servers [ i ] ;
printf ( " [%d] %s: \n " , i , server - > name ) ;
printf ( " addr: %s \n " , server - > addr ) ;
printf ( " so_mark: %d \n " , server - > so_mark ) ;
printf ( " netif: %s \n " , server - > netif ) ;
}
printf ( " \n " ) ;
printf ( " Clients (%d): \n " , config - > client_count ) ;
for ( int i = 0 ; i < config - > client_count ; i + + ) {
const client_config_t * client = & config - > clients [ i ] ;
printf ( " [%d] %s: \n " , i , client - > name ) ;
printf ( " from: %s \n " , client - > from ) ;
printf ( " to_addr: %s \n " , client - > to_addr ) ;
}
printf ( " \n " ) ;
printf ( " Connections v2 (%d): \n " , config - > connection_v2_count ) ;
for ( int i = 0 ; i < config - > connection_v2_count ; i + + ) {
const connection_config_v2_t * conn = & config - > connections_v2 [ i ] ;
printf ( " [%d]: \n " , i ) ;
printf ( " peer_public_key: %s \n " , conn - > peer_public_key_hex ) ;
printf ( " so_mark: %d \n " , conn - > so_mark ) ;
printf ( " netif: %s \n " , conn - > netif ) ;
printf ( " tun: %s \n " , conn - > tun_ifname ) ;
printf ( " tun_ip: %s \n " , conn - > tun_ip ) ;
printf ( " keepalive: %d \n " , conn - > keepalive ) ;
printf ( " routes (%d): \n " , conn - > route_count ) ;
for ( int j = 0 ; j < conn - > route_count ; j + + ) {
printf ( " %s:%s \n " , conn - > routes [ j ] . server_name , conn - > routes [ j ] . client_name ) ;
}
}
printf ( " \n " ) ;
}
// Update keys in configuration file
@ -298,7 +246,7 @@ int update_config_keys(const char *filename,
fclose ( fp ) ;
return 0 ;
}
// Read all lines
char * * lines = NULL ;
size_t line_count = 0 ;
@ -410,4 +358,268 @@ int update_config_keys(const char *filename,
free ( lines ) ;
fclose ( fp ) ;
return 0 ;
}
// Parse new format configuration file
utun_config_t * parse_config_v2 ( const char * filename ) {
FILE * fp = fopen ( filename , " r " ) ;
if ( ! fp ) {
fprintf ( stderr , " Failed to open config file: %s \n " , filename ) ;
return NULL ;
}
// Allocate config structure
utun_config_t * config = calloc ( 1 , sizeof ( utun_config_t ) ) ;
if ( ! config ) {
fclose ( fp ) ;
return NULL ;
}
// Initialize arrays
config - > server_capacity = INITIAL_SERVER_CAPACITY ;
config - > servers = malloc ( config - > server_capacity * sizeof ( server_config_t ) ) ;
if ( ! config - > servers ) {
free ( config ) ;
fclose ( fp ) ;
return NULL ;
}
config - > client_capacity = INITIAL_CLIENT_CAPACITY ;
config - > clients = malloc ( config - > client_capacity * sizeof ( client_config_t ) ) ;
if ( ! config - > clients ) {
free ( config - > servers ) ;
free ( config ) ;
fclose ( fp ) ;
return NULL ;
}
config - > connection_v2_capacity = INITIAL_CONNECTION_V2_CAPACITY ;
config - > connections_v2 = malloc ( config - > connection_v2_capacity * sizeof ( connection_config_v2_t ) ) ;
if ( ! config - > connections_v2 ) {
free ( config - > clients ) ;
free ( config - > servers ) ;
free ( config ) ;
fclose ( fp ) ;
return NULL ;
}
char line [ MAX_LINE_LEN ] ;
char current_section [ 128 ] = " " ;
char current_server_name [ MAX_CONN_NAME_LEN ] = " " ;
char current_client_name [ MAX_CONN_NAME_LEN ] = " " ;
server_config_t current_server = { 0 } ;
client_config_t current_client = { 0 } ;
connection_config_v2_t current_conn_v2 = { 0 } ;
int in_server_section = 0 ;
int in_client_section = 0 ;
int in_connection_section = 0 ;
while ( fgets ( line , sizeof ( line ) , fp ) ) {
// Remove newline
line [ strcspn ( line , " \n " ) ] = ' \0 ' ;
char * trimmed = trim ( line ) ;
// Skip empty lines and comments
if ( strlen ( trimmed ) = = 0 | | trimmed [ 0 ] = = ' ; ' | | trimmed [ 0 ] = = ' # ' ) {
continue ;
}
// Check for section header
if ( trimmed [ 0 ] = = ' [ ' & & trimmed [ strlen ( trimmed ) - 1 ] = = ' ] ' ) {
// End previous sections if any
if ( in_server_section ) {
if ( strlen ( current_server . name ) > 0 ) {
if ( add_server ( config , & current_server ) ! = 0 ) {
fprintf ( stderr , " Failed to add server: %s \n " , current_server . name ) ;
}
}
memset ( & current_server , 0 , sizeof ( current_server ) ) ;
in_server_section = 0 ;
}
if ( in_client_section ) {
if ( strlen ( current_client . name ) > 0 ) {
if ( add_client ( config , & current_client ) ! = 0 ) {
fprintf ( stderr , " Failed to add client: %s \n " , current_client . name ) ;
}
}
memset ( & current_client , 0 , sizeof ( current_client ) ) ;
in_client_section = 0 ;
}
if ( in_connection_section ) {
if ( current_conn_v2 . route_count > 0 ) {
if ( add_connection_v2 ( config , & current_conn_v2 ) ! = 0 ) {
fprintf ( stderr , " Failed to add connection v2 \n " ) ;
}
}
memset ( & current_conn_v2 , 0 , sizeof ( current_conn_v2 ) ) ;
in_connection_section = 0 ;
}
// Extract section name
strncpy ( current_section , trimmed + 1 , sizeof ( current_section ) - 1 ) ;
current_section [ sizeof ( current_section ) - 1 ] = ' \0 ' ;
current_section [ strcspn ( current_section , " ] " ) ] = ' \0 ' ;
trim ( current_section ) ;
// Check section type
if ( strncmp ( current_section , " server: " , 7 ) = = 0 ) {
in_server_section = 1 ;
char * name = trim ( current_section + 7 ) ;
if ( strlen ( name ) > 0 ) {
strncpy ( current_server . name , name , sizeof ( current_server . name ) - 1 ) ;
strncpy ( current_server_name , name , sizeof ( current_server_name ) - 1 ) ;
}
} else if ( strncmp ( current_section , " client: " , 7 ) = = 0 ) {
in_client_section = 1 ;
char * name = trim ( current_section + 7 ) ;
if ( strlen ( name ) > 0 ) {
strncpy ( current_client . name , name , sizeof ( current_client . name ) - 1 ) ;
strncpy ( current_client_name , name , sizeof ( current_client_name ) - 1 ) ;
}
} else if ( strcasecmp ( current_section , " connection " ) = = 0 ) {
in_connection_section = 1 ;
} else if ( strcasecmp ( current_section , " global " ) = = 0 ) {
// Already handled by current_section
} else if ( strcasecmp ( current_section , " routing " ) = = 0 ) {
// Already handled by current_section
} else {
fprintf ( stderr , " Unknown section: %s \n " , current_section ) ;
}
continue ;
}
// Parse key-value pair
char key [ 256 ] , value [ 256 ] ;
if ( parse_key_value ( trimmed , key , sizeof ( key ) , value , sizeof ( value ) ) ! = 0 ) {
fprintf ( stderr , " Invalid key-value line: %s \n " , trimmed ) ;
continue ;
}
// Process based on current section
if ( strcasecmp ( current_section , " global " ) = = 0 ) {
if ( strcasecmp ( key , " my_private_key " ) = = 0 ) {
strncpy ( config - > global . my_private_key_hex , value , sizeof ( config - > global . my_private_key_hex ) - 1 ) ;
} else if ( strcasecmp ( key , " my_public_key " ) = = 0 ) {
strncpy ( config - > global . my_public_key_hex , value , sizeof ( config - > global . my_public_key_hex ) - 1 ) ;
} else if ( strcasecmp ( key , " option " ) = = 0 ) {
strncpy ( config - > global . option_value , value , sizeof ( config - > global . option_value ) - 1 ) ;
} else if ( strcasecmp ( key , " control_ip " ) = = 0 ) {
strncpy ( config - > global . control_ip , value , sizeof ( config - > global . control_ip ) - 1 ) ;
} else if ( strcasecmp ( key , " control_port " ) = = 0 ) {
config - > global . control_port = atoi ( value ) ;
} else if ( strcasecmp ( key , " net_debug " ) = = 0 ) {
config - > global . net_debug = atoi ( value ) ;
} else if ( strcasecmp ( key , " tun_ip " ) = = 0 ) {
strncpy ( config - > global . tun_ip , value , sizeof ( config - > global . tun_ip ) - 1 ) ;
}
} else if ( strcasecmp ( current_section , " routing " ) = = 0 ) {
if ( strcasecmp ( key , " allowed_subnet " ) = = 0 ) {
if ( config - > allowed_subnet_count < MAX_ALLOWED_SUBNETS ) {
strncpy ( config - > allowed_subnets [ config - > allowed_subnet_count ] . subnet , value , sizeof ( config - > allowed_subnets [ 0 ] . subnet ) - 1 ) ;
config - > allowed_subnet_count + + ;
} else {
fprintf ( stderr , " Too many allowed subnets, maximum is %d \n " , MAX_ALLOWED_SUBNETS ) ;
}
}
} else if ( in_server_section ) {
if ( strcasecmp ( key , " addr " ) = = 0 ) {
strncpy ( current_server . addr , value , sizeof ( current_server . addr ) - 1 ) ;
} else if ( strcasecmp ( key , " so_mark " ) = = 0 ) {
current_server . so_mark = atoi ( value ) ;
} else if ( strcasecmp ( key , " netif " ) = = 0 ) {
strncpy ( current_server . netif , value , sizeof ( current_server . netif ) - 1 ) ;
}
} else if ( in_client_section ) {
if ( strcasecmp ( key , " from " ) = = 0 ) {
strncpy ( current_client . from , value , sizeof ( current_client . from ) - 1 ) ;
} else if ( strcasecmp ( key , " to_addr " ) = = 0 ) {
strncpy ( current_client . to_addr , value , sizeof ( current_client . to_addr ) - 1 ) ;
}
} else if ( in_connection_section ) {
if ( strcasecmp ( key , " link " ) = = 0 ) {
// Parse comma-separated route pairs: server1:client1,server2:client2
char * token = strtok ( value , " , " ) ;
while ( token ! = NULL ) {
char * pair = trim ( token ) ;
char * colon = strchr ( pair , ' : ' ) ;
if ( colon ) {
route_pair_t route = { 0 } ;
size_t server_len = colon - pair ;
if ( server_len > = sizeof ( route . server_name ) ) server_len = sizeof ( route . server_name ) - 1 ;
strncpy ( route . server_name , pair , server_len ) ;
route . server_name [ server_len ] = ' \0 ' ;
trim ( route . server_name ) ;
char * client_name = colon + 1 ;
strncpy ( route . client_name , client_name , sizeof ( route . client_name ) - 1 ) ;
trim ( route . client_name ) ;
if ( add_route_to_connection ( & current_conn_v2 , & route ) ! = 0 ) {
fprintf ( stderr , " Failed to add route: %s:%s \n " , route . server_name , route . client_name ) ;
}
} else {
fprintf ( stderr , " Invalid route pair format: %s, expected 'server:client' \n " , pair ) ;
}
token = strtok ( NULL , " , " ) ;
}
} else if ( strcasecmp ( key , " keepalive " ) = = 0 ) {
current_conn_v2 . keepalive = atoi ( value ) ;
} else if ( strcasecmp ( key , " peer_public_key " ) = = 0 ) {
strncpy ( current_conn_v2 . peer_public_key_hex , value , sizeof ( current_conn_v2 . peer_public_key_hex ) - 1 ) ;
}
}
}
// Add last sections if any
if ( in_server_section & & strlen ( current_server . name ) > 0 ) {
if ( add_server ( config , & current_server ) ! = 0 ) {
fprintf ( stderr , " Failed to add server: %s \n " , current_server . name ) ;
}
}
if ( in_client_section & & strlen ( current_client . name ) > 0 ) {
if ( add_client ( config , & current_client ) ! = 0 ) {
fprintf ( stderr , " Failed to add client: %s \n " , current_client . name ) ;
}
}
if ( in_connection_section & & current_conn_v2 . route_count > 0 ) {
if ( add_connection_v2 ( config , & current_conn_v2 ) ! = 0 ) {
fprintf ( stderr , " Failed to add connection v2 \n " ) ;
}
}
fclose ( fp ) ;
// Validate references
for ( int i = 0 ; i < config - > connection_v2_count ; i + + ) {
connection_config_v2_t * conn = & config - > connections_v2 [ i ] ;
for ( int j = 0 ; j < conn - > route_count ; j + + ) {
route_pair_t * route = & conn - > routes [ j ] ;
// Check server exists
int server_found = 0 ;
for ( int k = 0 ; k < config - > server_count ; k + + ) {
if ( strcmp ( config - > servers [ k ] . name , route - > server_name ) = = 0 ) {
server_found = 1 ;
break ;
}
}
if ( ! server_found ) {
fprintf ( stderr , " Warning: server '%s' referenced in route not found \n " , route - > server_name ) ;
}
// Check client exists
int client_found = 0 ;
for ( int k = 0 ; k < config - > client_count ; k + + ) {
if ( strcmp ( config - > clients [ k ] . name , route - > client_name ) = = 0 ) {
client_found = 1 ;
break ;
}
}
if ( ! client_found ) {
fprintf ( stderr , " Warning: client '%s' referenced in route not found \n " , route - > client_name ) ;
}
}
}
return config ;
}