1
0
mirror of https://github.com/solemnwarning/ipxwrapper synced 2024-12-30 16:45:37 +01:00

Support DOSBox servers using DNS names.

This commit is contained in:
Daniel Collins 2023-09-13 00:24:08 +01:00
parent a91e05c11b
commit 435df05496
6 changed files with 202 additions and 65 deletions

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Interface functions
* Copyright (C) 2011-2021 Daniel Collins <solemnwarning@solemnwarning.net>
* Copyright (C) 2011-2023 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
@ -24,6 +24,7 @@
#include <pcap.h>
#include "interface.h"
#include "ipxwrapper.h"
#include "common.h"
#include "config.h"
@ -523,43 +524,50 @@ void ipx_interfaces_init(void)
free(ip_ifaces);
}
/* Virtual IPX interfaces... */
log_printf(LOG_INFO, "Listing IPX interfaces:");
log_printf(LOG_INFO, "--");
ipx_interface_t *ipx_root = get_ipx_interfaces(), *ipx;
if(!ipx_root)
if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
{
log_printf(LOG_INFO, "No IPX interfaces detected!");
log_printf(LOG_INFO, "--");
log_printf(LOG_INFO, "Using DOSBox server: %s port %hu",
main_config.dosbox_server_addr, main_config.dosbox_server_port);
}
DL_FOREACH(ipx_root, ipx)
{
char net[ADDR32_STRING_SIZE];
addr32_string(net, ipx->ipx_net);
else{
/* Virtual IPX interfaces... */
char node[ADDR48_STRING_SIZE];
addr48_string(node, ipx->ipx_node);
log_printf(LOG_INFO, "Listing IPX interfaces:");
log_printf(LOG_INFO, "--");
log_printf(LOG_INFO, "Network: %s", net);
log_printf(LOG_INFO, "Node: %s", node);
ipx_interface_t *ipx_root = get_ipx_interfaces(), *ipx;
ipx_interface_ip_t *ip;
DL_FOREACH(ipx->ipaddr, ip)
if(!ipx_root)
{
log_printf(LOG_INFO, "IP address: %s", inet_ntoa(*((struct in_addr*)&(ip->ipaddr))));
log_printf(LOG_INFO, "Netmask: %s", inet_ntoa(*((struct in_addr*)&(ip->netmask))));
log_printf(LOG_INFO, "Broadcast: %s", inet_ntoa(*((struct in_addr*)&(ip->bcast))));
log_printf(LOG_INFO, "No IPX interfaces detected!");
log_printf(LOG_INFO, "--");
}
log_printf(LOG_INFO, "--");
DL_FOREACH(ipx_root, ipx)
{
char net[ADDR32_STRING_SIZE];
addr32_string(net, ipx->ipx_net);
char node[ADDR48_STRING_SIZE];
addr48_string(node, ipx->ipx_node);
log_printf(LOG_INFO, "Network: %s", net);
log_printf(LOG_INFO, "Node: %s", node);
ipx_interface_ip_t *ip;
DL_FOREACH(ipx->ipaddr, ip)
{
log_printf(LOG_INFO, "IP address: %s", inet_ntoa(*((struct in_addr*)&(ip->ipaddr))));
log_printf(LOG_INFO, "Netmask: %s", inet_ntoa(*((struct in_addr*)&(ip->netmask))));
log_printf(LOG_INFO, "Broadcast: %s", inet_ntoa(*((struct in_addr*)&(ip->bcast))));
}
log_printf(LOG_INFO, "--");
}
free_ipx_interface_list(&ipx_root);
}
free_ipx_interface_list(&ipx_root);
}
/* Release any resources used by the IPX interface cache. */

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Interface header
* Copyright (C) 2011-2021 Daniel Collins <solemnwarning@solemnwarning.net>
* Copyright (C) 2011-2023 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
@ -81,7 +81,7 @@ extern enum main_config_encap_type ipx_encap_type;
enum dosbox_state
{
DOSBOX_DISCONNECTED,
DOSBOX_RESOLVING,
/* DOSBOX_RESOLVING, */
DOSBOX_REGISTERING,
DOSBOX_CONNECTED,
};

View File

@ -35,3 +35,4 @@ r_getpeername:4
inet_ntoa:4
__WSAFDIsSet:4
r_WSAAsyncSelect:4
gethostbyname:4

View File

@ -57,17 +57,20 @@ static HANDLE router_thread = NULL;
SOCKET shared_socket = -1;
SOCKET private_socket = -1;
#define DOSBOX_CONNECT_TIMEOUT_SECS 10
struct sockaddr_in dosbox_server_addr;
static time_t dosbox_connect_begin;
static HANDLE dosbox_ready_event = NULL;
static int dosbox_next_registration_request_at;
static int dosbox_registration_retry_interval_ms;
static uint64_t dosbox_next_connection_attempt_at;
static const unsigned int dosbox_connect_retry_interval_ms = 10000;
static const int INITIAL_DOSBOX_REGISTRATION_RETRY_INTERVAL_MS = 250;
static const int MAX_DOSBOX_REGISTRATION_RETRY_INTERVAL_MS = 8000;
static uint64_t dosbox_next_registration_request_at;
static unsigned int dosbox_registration_retry_interval_ms;
static uint64_t dosbox_registration_timeout_at;
static const unsigned int INITIAL_DOSBOX_REGISTRATION_RETRY_INTERVAL_MS = 250;
static const unsigned int MAX_DOSBOX_REGISTRATION_RETRY_INTERVAL_MS = 8000;
static const unsigned int DOSBOX_REGISTRATION_TIMEOUT_MS = 30000;
static void _send_dosbox_registration_request(void);
static DWORD router_main(void *arg);
@ -155,18 +158,9 @@ void router_init(void)
abort();
}
/* TODO: Support DNS. Do this async somewhere within router_main. */
_init_socket(&private_socket, 0, FALSE, FALSE);
dosbox_server_addr.sin_family = AF_INET;
dosbox_server_addr.sin_addr.s_addr = inet_addr(main_config.dosbox_server_addr);
dosbox_server_addr.sin_port = htons(main_config.dosbox_server_port);
dosbox_next_registration_request_at = 0;
dosbox_registration_retry_interval_ms = INITIAL_DOSBOX_REGISTRATION_RETRY_INTERVAL_MS;
dosbox_state = DOSBOX_REGISTERING;
dosbox_next_connection_attempt_at = 0;
}
else{
_init_socket(&shared_socket, main_config.udp_port, TRUE, TRUE);
@ -519,8 +513,7 @@ static void _handle_dosbox_registration_response(novell_ipx_packet *packet, size
/* || packet->type != 2) */
{
/* Doesn't look valid. */
log_printf(LOG_ERROR, "Got invalid registration response from DOSBox server!");
abort();
log_printf(LOG_ERROR, "Got invalid registration response from DOSBox server, ignoring");
}
dosbox_local_netnum = addr32_in(packet->dest_net);
@ -546,7 +539,7 @@ static void _handle_dosbox_recv(novell_ipx_packet *packet, size_t packet_size)
if(packet_size < sizeof(novell_ipx_packet) || ntohs(packet->length) != packet_size)
{
/* Doesn't look valid. */
log_printf(LOG_ERROR, "Recieved invalid IPX packet from DOSBox server, dropping");
log_printf(LOG_ERROR, "Recieved invalid IPX packet from DOSBox server, ignoring");
return;
}
@ -758,20 +751,32 @@ static DWORD router_main(void *arg)
{
DWORD wait_ms = 1000;
if(ipx_encap_type == ENCAP_TYPE_DOSBOX && dosbox_state == DOSBOX_REGISTERING)
if(ipx_encap_type == ENCAP_TYPE_DOSBOX)
{
uint64_t now = get_ticks();
if(now >= dosbox_next_registration_request_at)
if(dosbox_state == DOSBOX_DISCONNECTED)
{
wait_ms = 0;
}
else{
wait_ms = dosbox_next_registration_request_at - 1;
uint64_t now = get_ticks();
if(wait_ms > 1000)
if(now >= dosbox_next_connection_attempt_at)
{
wait_ms = 1000;
wait_ms = 0;
}
else{
wait_ms = dosbox_next_connection_attempt_at - now;
wait_ms = min(wait_ms, 1000);
}
}
else if(dosbox_state == DOSBOX_REGISTERING)
{
uint64_t now = get_ticks();
if(now >= dosbox_next_registration_request_at)
{
wait_ms = 0;
}
else{
wait_ms = dosbox_next_registration_request_at - now;
wait_ms = min(wait_ms, 1000);
}
}
}
@ -815,10 +820,48 @@ static DWORD router_main(void *arg)
}
}
if(ipx_encap_type == ENCAP_TYPE_DOSBOX && dosbox_state == DOSBOX_DISCONNECTED)
{
if(get_ticks() >= dosbox_next_connection_attempt_at)
{
struct hostent *host = gethostbyname(main_config.dosbox_server_addr);
uint64_t now = get_ticks();
if(host != NULL)
{
dosbox_server_addr.sin_family = AF_INET;
memcpy(&(dosbox_server_addr.sin_addr), host->h_addr, 4);
dosbox_server_addr.sin_port = htons(main_config.dosbox_server_port);
log_printf(LOG_INFO, "Resolved DOSBox server address %s, connecting...\n", inet_ntoa(dosbox_server_addr.sin_addr));
dosbox_next_registration_request_at = 0;
dosbox_registration_retry_interval_ms = INITIAL_DOSBOX_REGISTRATION_RETRY_INTERVAL_MS;
dosbox_registration_timeout_at = now + DOSBOX_REGISTRATION_TIMEOUT_MS;
dosbox_state = DOSBOX_REGISTERING;
}
else{
DWORD error = WSAGetLastError();
log_printf(LOG_ERROR, "Error resolving %s: %s (%u)",
main_config.dosbox_server_addr, w32_error(error), (unsigned int)(error));
dosbox_next_connection_attempt_at = now + dosbox_connect_retry_interval_ms;
}
}
}
if(ipx_encap_type == ENCAP_TYPE_DOSBOX && dosbox_state == DOSBOX_REGISTERING)
{
uint64_t now = get_ticks();
if(now >= dosbox_registration_timeout_at)
{
log_printf(LOG_ERROR, "Connection to DOSBox server %s timed out", inet_ntoa(dosbox_server_addr.sin_addr));
dosbox_state = DOSBOX_DISCONNECTED;
}
if(now >= dosbox_next_registration_request_at)
{
_send_dosbox_registration_request();

View File

@ -266,10 +266,10 @@ describe "IPXWrapper" => sub
};
};
describe "using DOSBox UDP encapsulation" => sub
my $dosbox_server;
describe "using DOSBox UDP encapsulation (via IP address)" => sub
{
my $dosbox_server;
before all => sub
{
reg_delete_key($remote_ip_a, "HKCU\\Software\\IPXWrapper");
@ -277,6 +277,7 @@ describe "IPXWrapper" => sub
reg_set_string($remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_addr", $local_ip_a);
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_port", $dosbox_port);
$dosbox_server = undef;
$dosbox_server = IPXWrapper::DOSBoxServer->new($dosbox_port);
@expected_addrs = (
@ -316,6 +317,90 @@ describe "IPXWrapper" => sub
};
};
};
describe "using DOSBox UDP encapsulation (via DNS name)" => sub
{
before all => sub
{
reg_delete_key($remote_ip_a, "HKCU\\Software\\IPXWrapper");
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "use_pcap", ENCAP_TYPE_DOSBOX);
reg_set_string($remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_addr", "dosbox-ipv4.com");
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_port", $dosbox_port);
$dosbox_server = undef;
$dosbox_server = IPXWrapper::DOSBoxServer->new($dosbox_port);
@expected_addrs = (
{
# The node number is randomly selected by the DOSBox server
# when each client connects.
net => "00:00:00:00",
maxpkt => DOSBOX_MAX_DATA_SIZE,
},
);
};
after all => sub
{
$dosbox_server = undef;
};
# Duplicate of common getsockopt block to skip the default interface selection
# logic test (because there is only ever one interface here).
describe "getsockopt" => sub
{
it "returns correct addresses" => sub
{
my @addrs = getsockopt_interfaces($remote_ip_a);
cmp_hashes_partial(\@addrs, \@expected_addrs);
};
it "returns correct IPX_MAX_ADAPTER_NUM" => sub
{
my @addrs = getsockopt_interfaces($remote_ip_a);
my $output = run_remote_cmd($remote_ip_a, "Z:\\tools\\list-interfaces.exe");
my ($got_num) = ($output =~ m/^IPX_MAX_ADAPTER_NUM = (\d+)$/m);
is($got_num, (scalar @addrs));
};
};
};
describe "using DOSBox UDP encapsulation (server is down)" => sub
{
before all => sub
{
reg_delete_key($remote_ip_a, "HKCU\\Software\\IPXWrapper");
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "use_pcap", ENCAP_TYPE_DOSBOX);
reg_set_string($remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_addr", $local_ip_a);
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_port", $dosbox_port);
$dosbox_server = undef;
};
# Duplicate of common getsockopt block to skip the default interface selection
# logic test (because there is only ever one interface here).
describe "getsockopt" => sub
{
it "returns no addresses" => sub
{
my @addrs = getsockopt_interfaces($remote_ip_a);
cmp_deeply(\@addrs, []);
};
it "returns correct IPX_MAX_ADAPTER_NUM" => sub
{
my @addrs = getsockopt_interfaces($remote_ip_a);
my $output = run_remote_cmd($remote_ip_a, "Z:\\tools\\list-interfaces.exe");
my ($got_num) = ($output =~ m/^IPX_MAX_ADAPTER_NUM = (\d+)$/m);
is($got_num, 0);
};
};
};
};
sub get_first_addr_node

View File

@ -45,7 +45,7 @@ describe "IPXWrapper using DOSBox UDP encapsulation" => sub
{
reg_delete_key($remote_ip_a, "HKCU\\Software\\IPXWrapper");
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "use_pcap", ENCAP_TYPE_DOSBOX);
reg_set_string($remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_addr", $local_ip_a);
reg_set_string($remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_addr", "dosbox-ipv4.com");
reg_set_dword( $remote_ip_a, "HKCU\\Software\\IPXWrapper", "dosbox_server_port", $dosbox_port);
};