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({
|
||||
pid => $pid,
|
||||
stdin => $in,
|
||||
sockets => [],
|
||||
}, $class);
|
||||
|
||||
@ -72,8 +73,18 @@ sub DESTROY
|
||||
{
|
||||
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);
|
||||
alarm(0);
|
||||
}
|
||||
|
||||
sub result
|
||||
|
@ -33,7 +33,10 @@ sub new
|
||||
# No need for error checking here - open3 throws on failure.
|
||||
my $pid = open3(my $in, my $out, undef, @command);
|
||||
|
||||
my $self = bless(\$pid, $class);
|
||||
my $self = bless({
|
||||
pid => $pid,
|
||||
in => $in,
|
||||
}, $class);
|
||||
|
||||
my $output = "";
|
||||
|
||||
@ -56,8 +59,18 @@ sub DESTROY
|
||||
{
|
||||
my ($self) = @_;
|
||||
|
||||
kill(SIGKILL, $$self);
|
||||
waitpid($$self, 0);
|
||||
# Process should exit once it gets EOF
|
||||
delete $self->{in};
|
||||
|
||||
local $SIG{ALRM} = sub
|
||||
{
|
||||
warn "Killing hung process";
|
||||
kill(SIGKILL, $self->{pid});
|
||||
};
|
||||
|
||||
alarm(5);
|
||||
waitpid($self->{pid}, 0);
|
||||
alarm(0);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -65,11 +65,32 @@ sub DESTROY
|
||||
|
||||
if(defined($self->{pid}))
|
||||
{
|
||||
kill(SIGKILL, $self->{pid});
|
||||
waitpid($self->{pid}, 0);
|
||||
$self->_end();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
# all the output.
|
||||
|
||||
kill(SIGKILL, $self->{pid});
|
||||
waitpid($self->{pid}, 0);
|
||||
delete $self->{pid};
|
||||
if(!$self->_end())
|
||||
{
|
||||
# Didn't exit properly, pipe might still have a writer.
|
||||
die "ipx-isr.exe didn't exit cleanly";
|
||||
}
|
||||
|
||||
my $out = $self->{out};
|
||||
my @packets = ();
|
||||
|
@ -38,6 +38,7 @@ sub new
|
||||
my $self = bless({
|
||||
pid => $pid,
|
||||
out => $out,
|
||||
in => $in,
|
||||
|
||||
sockets => {},
|
||||
}, $class);
|
||||
@ -73,11 +74,32 @@ sub DESTROY
|
||||
|
||||
if(defined($self->{pid}))
|
||||
{
|
||||
kill(SIGKILL, $self->{pid});
|
||||
waitpid($self->{pid}, 0);
|
||||
$self->_end();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
# all the output.
|
||||
|
||||
kill(SIGKILL, $self->{pid});
|
||||
waitpid($self->{pid}, 0);
|
||||
delete $self->{pid};
|
||||
if(!$self->_end())
|
||||
{
|
||||
# Didn't exit properly, pipe might still have a writer.
|
||||
die "ipx-recv.exe didn't exit cleanly";
|
||||
}
|
||||
|
||||
my $out = $self->{out};
|
||||
my @packets = ();
|
||||
|
@ -97,13 +97,10 @@ int main(int argc, const char **argv)
|
||||
*/
|
||||
printf("Ready\n");
|
||||
|
||||
/* Hang around until we're killed. This is to facilitate testing bind
|
||||
* behaviour in concurrent processes.
|
||||
/* Hang around until something is written to our stdin. This is to
|
||||
* facilitate testing bind behaviour in concurrent processes.
|
||||
*/
|
||||
while(1)
|
||||
{
|
||||
Sleep(10000);
|
||||
}
|
||||
getchar();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -96,30 +96,55 @@ int main(int argc, char **argv)
|
||||
|
||||
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");
|
||||
|
||||
char buf[1024];
|
||||
while(1)
|
||||
{
|
||||
struct sockaddr_ipx recv_addr;
|
||||
int addrlen = sizeof(recv_addr);
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(sock, &read_fds);
|
||||
|
||||
int r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)(&recv_addr), &addrlen);
|
||||
assert(r > 0);
|
||||
struct timeval timeout = {
|
||||
.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];
|
||||
addr32_string(net_s, addr32_in(recv_addr.sa_netnum));
|
||||
if(WaitForSingleObject(send_thread_h, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
/* Send thread ended, must've hit EOF. Time to exit */
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
if(FD_ISSET(sock, &read_fds))
|
||||
{
|
||||
/* Packet waiting to be read. */
|
||||
|
||||
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);
|
||||
|
||||
WSACleanup();
|
||||
|
@ -38,6 +38,12 @@ static void usage(const char *argv0)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static DWORD WINAPI getchar_thread_main(LPVOID lpParameter)
|
||||
{
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
setbuf(stdout, NULL);
|
||||
@ -128,6 +134,9 @@ int main(int argc, char **argv)
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, NULL);
|
||||
assert(getchar_thread != NULL);
|
||||
|
||||
printf("Ready\n");
|
||||
|
||||
while(1)
|
||||
@ -140,7 +149,18 @@ int main(int argc, char **argv)
|
||||
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)
|
||||
{
|
||||
@ -165,6 +185,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(getchar_thread);
|
||||
|
||||
for(int i = 0; i < n_sockets; ++i)
|
||||
{
|
||||
closesocket(sockets[i]);
|
||||
|
@ -39,6 +39,12 @@ static void usage(const char *argv0)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static DWORD WINAPI getchar_thread_main(LPVOID lpParameter)
|
||||
{
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
setbuf(stdout, NULL);
|
||||
@ -116,6 +122,9 @@ int main(int argc, char **argv)
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
HANDLE getchar_thread = CreateThread(NULL, 0, &getchar_thread_main, NULL, 0, NULL);
|
||||
assert(getchar_thread != NULL);
|
||||
|
||||
printf("Ready\n");
|
||||
|
||||
int clients[MAX_CLIENTS];
|
||||
@ -136,7 +145,18 @@ int main(int argc, char **argv)
|
||||
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)
|
||||
{
|
||||
@ -198,6 +218,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(getchar_thread);
|
||||
|
||||
for(int i = 0; i < n_clients; ++i)
|
||||
{
|
||||
closesocket(clients[i]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user