mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Gracefully exit programs during tests.
Makes the test environment a bit more robust. Also makes a lot of the tests pass under Wine(!).
This commit is contained in:
parent
bb7d4beeab
commit
597bf27204
@ -36,6 +36,7 @@ sub new
|
|||||||
|
|
||||||
my $self = bless({
|
my $self = bless({
|
||||||
pid => $pid,
|
pid => $pid,
|
||||||
|
stdin => $in,
|
||||||
sockets => [],
|
sockets => [],
|
||||||
}, $class);
|
}, $class);
|
||||||
|
|
||||||
@ -72,8 +73,18 @@ sub DESTROY
|
|||||||
{
|
{
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
kill(SIGKILL, $self->{pid});
|
# bind.exe will exit once it reads EOF.
|
||||||
|
delete $self->{stdin};
|
||||||
|
|
||||||
|
local $SIG{ALRM} = sub
|
||||||
|
{
|
||||||
|
warn "Killing hung bind.exe process";
|
||||||
|
kill(SIGKILL, $self->{pid});
|
||||||
|
};
|
||||||
|
|
||||||
|
alarm(5);
|
||||||
waitpid($self->{pid}, 0);
|
waitpid($self->{pid}, 0);
|
||||||
|
alarm(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub result
|
sub result
|
||||||
|
@ -33,7 +33,10 @@ sub new
|
|||||||
# No need for error checking here - open3 throws on failure.
|
# No need for error checking here - open3 throws on failure.
|
||||||
my $pid = open3(my $in, my $out, undef, @command);
|
my $pid = open3(my $in, my $out, undef, @command);
|
||||||
|
|
||||||
my $self = bless(\$pid, $class);
|
my $self = bless({
|
||||||
|
pid => $pid,
|
||||||
|
in => $in,
|
||||||
|
}, $class);
|
||||||
|
|
||||||
my $output = "";
|
my $output = "";
|
||||||
|
|
||||||
@ -56,8 +59,18 @@ sub DESTROY
|
|||||||
{
|
{
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
kill(SIGKILL, $$self);
|
# Process should exit once it gets EOF
|
||||||
waitpid($$self, 0);
|
delete $self->{in};
|
||||||
|
|
||||||
|
local $SIG{ALRM} = sub
|
||||||
|
{
|
||||||
|
warn "Killing hung process";
|
||||||
|
kill(SIGKILL, $self->{pid});
|
||||||
|
};
|
||||||
|
|
||||||
|
alarm(5);
|
||||||
|
waitpid($self->{pid}, 0);
|
||||||
|
alarm(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -65,11 +65,32 @@ sub DESTROY
|
|||||||
|
|
||||||
if(defined($self->{pid}))
|
if(defined($self->{pid}))
|
||||||
{
|
{
|
||||||
kill(SIGKILL, $self->{pid});
|
$self->_end();
|
||||||
waitpid($self->{pid}, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _end
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
# ipx-isr.exe will exit when it reads EOF
|
||||||
|
delete $self->{in};
|
||||||
|
|
||||||
|
local $SIG{ALRM} = sub
|
||||||
|
{
|
||||||
|
warn "Killing hung ipx-isr.exe process";
|
||||||
|
kill(SIGKILL, $self->{pid});
|
||||||
|
};
|
||||||
|
|
||||||
|
alarm(5);
|
||||||
|
waitpid($self->{pid}, 0);
|
||||||
|
alarm(0);
|
||||||
|
|
||||||
|
delete $self->{pid};
|
||||||
|
|
||||||
|
return ($? == 0);
|
||||||
|
}
|
||||||
|
|
||||||
sub kill_and_read
|
sub kill_and_read
|
||||||
{
|
{
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
@ -82,9 +103,11 @@ sub kill_and_read
|
|||||||
# Kill the child process so we can read EOF from the pipe once we have
|
# Kill the child process so we can read EOF from the pipe once we have
|
||||||
# all the output.
|
# all the output.
|
||||||
|
|
||||||
kill(SIGKILL, $self->{pid});
|
if(!$self->_end())
|
||||||
waitpid($self->{pid}, 0);
|
{
|
||||||
delete $self->{pid};
|
# Didn't exit properly, pipe might still have a writer.
|
||||||
|
die "ipx-isr.exe didn't exit cleanly";
|
||||||
|
}
|
||||||
|
|
||||||
my $out = $self->{out};
|
my $out = $self->{out};
|
||||||
my @packets = ();
|
my @packets = ();
|
||||||
|
@ -38,6 +38,7 @@ sub new
|
|||||||
my $self = bless({
|
my $self = bless({
|
||||||
pid => $pid,
|
pid => $pid,
|
||||||
out => $out,
|
out => $out,
|
||||||
|
in => $in,
|
||||||
|
|
||||||
sockets => {},
|
sockets => {},
|
||||||
}, $class);
|
}, $class);
|
||||||
@ -73,11 +74,32 @@ sub DESTROY
|
|||||||
|
|
||||||
if(defined($self->{pid}))
|
if(defined($self->{pid}))
|
||||||
{
|
{
|
||||||
kill(SIGKILL, $self->{pid});
|
$self->_end();
|
||||||
waitpid($self->{pid}, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _end
|
||||||
|
{
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
# ipx-recv.exe will exit once we close its stdin
|
||||||
|
delete $self->{in};
|
||||||
|
|
||||||
|
local $SIG{ALRM} = sub
|
||||||
|
{
|
||||||
|
warn "Killing hung ipx-recv.exe process";
|
||||||
|
kill(SIGKILL, $self->{pid});
|
||||||
|
};
|
||||||
|
|
||||||
|
alarm(5);
|
||||||
|
waitpid($self->{pid}, 0);
|
||||||
|
alarm(0);
|
||||||
|
|
||||||
|
delete $self->{pid};
|
||||||
|
|
||||||
|
return ($? == 0);
|
||||||
|
}
|
||||||
|
|
||||||
sub kill_and_read
|
sub kill_and_read
|
||||||
{
|
{
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
@ -90,9 +112,11 @@ sub kill_and_read
|
|||||||
# Kill the child process so we can read EOF from the pipe once we have
|
# Kill the child process so we can read EOF from the pipe once we have
|
||||||
# all the output.
|
# all the output.
|
||||||
|
|
||||||
kill(SIGKILL, $self->{pid});
|
if(!$self->_end())
|
||||||
waitpid($self->{pid}, 0);
|
{
|
||||||
delete $self->{pid};
|
# Didn't exit properly, pipe might still have a writer.
|
||||||
|
die "ipx-recv.exe didn't exit cleanly";
|
||||||
|
}
|
||||||
|
|
||||||
my $out = $self->{out};
|
my $out = $self->{out};
|
||||||
my @packets = ();
|
my @packets = ();
|
||||||
|
@ -97,13 +97,10 @@ int main(int argc, const char **argv)
|
|||||||
*/
|
*/
|
||||||
printf("Ready\n");
|
printf("Ready\n");
|
||||||
|
|
||||||
/* Hang around until we're killed. This is to facilitate testing bind
|
/* Hang around until something is written to our stdin. This is to
|
||||||
* behaviour in concurrent processes.
|
* facilitate testing bind behaviour in concurrent processes.
|
||||||
*/
|
*/
|
||||||
while(1)
|
getchar();
|
||||||
{
|
|
||||||
Sleep(10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -96,30 +96,55 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
assert(bind(sock, (struct sockaddr*)(&local_addr), sizeof(local_addr)) == 0);
|
assert(bind(sock, (struct sockaddr*)(&local_addr), sizeof(local_addr)) == 0);
|
||||||
|
|
||||||
assert(CreateThread(NULL, 0, &send_thread, &sock, 0, NULL));
|
HANDLE send_thread_h = CreateThread(NULL, 0, &send_thread, &sock, 0, NULL);
|
||||||
|
assert(send_thread_h != NULL);
|
||||||
|
|
||||||
printf("Ready\n");
|
printf("Ready\n");
|
||||||
|
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
struct sockaddr_ipx recv_addr;
|
fd_set read_fds;
|
||||||
int addrlen = sizeof(recv_addr);
|
FD_ZERO(&read_fds);
|
||||||
|
FD_SET(sock, &read_fds);
|
||||||
|
|
||||||
int r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)(&recv_addr), &addrlen);
|
struct timeval timeout = {
|
||||||
assert(r > 0);
|
.tv_sec = 0,
|
||||||
|
.tv_usec = 100000, /* 1/10th sec */
|
||||||
|
};
|
||||||
|
|
||||||
buf[r] = '\0';
|
assert(select(sock + 1, &read_fds, NULL, NULL, &timeout) >= 0);
|
||||||
|
|
||||||
char net_s[ADDR32_STRING_SIZE];
|
if(WaitForSingleObject(send_thread_h, 0) == WAIT_OBJECT_0)
|
||||||
addr32_string(net_s, addr32_in(recv_addr.sa_netnum));
|
{
|
||||||
|
/* Send thread ended, must've hit EOF. Time to exit */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
char node_s[ADDR48_STRING_SIZE];
|
if(FD_ISSET(sock, &read_fds))
|
||||||
addr48_string(node_s, addr48_in(recv_addr.sa_nodenum));
|
{
|
||||||
|
/* Packet waiting to be read. */
|
||||||
printf("%s %s %hu %s\n", net_s, node_s, ntohs(recv_addr.sa_socket), buf);
|
|
||||||
|
struct sockaddr_ipx recv_addr;
|
||||||
|
int addrlen = sizeof(recv_addr);
|
||||||
|
|
||||||
|
int r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)(&recv_addr), &addrlen);
|
||||||
|
assert(r > 0);
|
||||||
|
|
||||||
|
buf[r] = '\0';
|
||||||
|
|
||||||
|
char net_s[ADDR32_STRING_SIZE];
|
||||||
|
addr32_string(net_s, addr32_in(recv_addr.sa_netnum));
|
||||||
|
|
||||||
|
char node_s[ADDR48_STRING_SIZE];
|
||||||
|
addr48_string(node_s, addr48_in(recv_addr.sa_nodenum));
|
||||||
|
|
||||||
|
printf("%s %s %hu %s\n", net_s, node_s, ntohs(recv_addr.sa_socket), buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CloseHandle(send_thread_h);
|
||||||
|
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
|
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
|
@ -38,6 +38,12 @@ static void usage(const char *argv0)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI getchar_thread_main(LPVOID lpParameter)
|
||||||
|
{
|
||||||
|
getchar();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
setbuf(stdout, NULL);
|
setbuf(stdout, NULL);
|
||||||
@ -128,6 +134,9 @@ int main(int argc, char **argv)
|
|||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, NULL);
|
||||||
|
assert(getchar_thread != NULL);
|
||||||
|
|
||||||
printf("Ready\n");
|
printf("Ready\n");
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
@ -140,7 +149,18 @@ int main(int argc, char **argv)
|
|||||||
FD_SET(sockets[i], &read_fds);
|
FD_SET(sockets[i], &read_fds);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(select(n_sockets, &read_fds, NULL, NULL, NULL) > 0);
|
struct timeval timeout = {
|
||||||
|
.tv_sec = 0,
|
||||||
|
.tv_usec = 100000, /* 1/10th sec */
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(select(n_sockets, &read_fds, NULL, NULL, &timeout) >= 0);
|
||||||
|
|
||||||
|
if(WaitForSingleObject(getchar_thread, 0) == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
/* Input is available on stdin, time to exit. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < n_sockets; ++i)
|
for(int i = 0; i < n_sockets; ++i)
|
||||||
{
|
{
|
||||||
@ -165,6 +185,8 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CloseHandle(getchar_thread);
|
||||||
|
|
||||||
for(int i = 0; i < n_sockets; ++i)
|
for(int i = 0; i < n_sockets; ++i)
|
||||||
{
|
{
|
||||||
closesocket(sockets[i]);
|
closesocket(sockets[i]);
|
||||||
|
@ -39,6 +39,12 @@ static void usage(const char *argv0)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI getchar_thread_main(LPVOID lpParameter)
|
||||||
|
{
|
||||||
|
getchar();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
setbuf(stdout, NULL);
|
setbuf(stdout, NULL);
|
||||||
@ -116,6 +122,9 @@ int main(int argc, char **argv)
|
|||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, NULL);
|
||||||
|
assert(getchar_thread != NULL);
|
||||||
|
|
||||||
printf("Ready\n");
|
printf("Ready\n");
|
||||||
|
|
||||||
int clients[MAX_CLIENTS];
|
int clients[MAX_CLIENTS];
|
||||||
@ -136,7 +145,18 @@ int main(int argc, char **argv)
|
|||||||
FD_SET(clients[i], &read_fds);
|
FD_SET(clients[i], &read_fds);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(select(n_listeners + n_clients, &read_fds, NULL, NULL, NULL) > 0);
|
struct timeval timeout = {
|
||||||
|
.tv_sec = 0,
|
||||||
|
.tv_usec = 100000, /* 1/10th sec */
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(select(n_listeners + n_clients, &read_fds, NULL, NULL, &timeout) >= 0);
|
||||||
|
|
||||||
|
if(WaitForSingleObject(getchar_thread, 0) == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
/* Input is available on stdin, time to exit. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < n_listeners; ++i)
|
for(int i = 0; i < n_listeners; ++i)
|
||||||
{
|
{
|
||||||
@ -198,6 +218,8 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CloseHandle(getchar_thread);
|
||||||
|
|
||||||
for(int i = 0; i < n_clients; ++i)
|
for(int i = 0; i < n_clients; ++i)
|
||||||
{
|
{
|
||||||
closesocket(clients[i]);
|
closesocket(clients[i]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user