diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2011-01-07 22:06:09 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2011-01-07 22:06:09 +0000 |
commit | 288eb9bdabfd29a4643657cee203bd87068d9425 (patch) | |
tree | 6e580e504fff76e283741f51e0a6742ef40359c9 /regress/sys | |
parent | 3a2bd2908bcd71d2b15fc9ea62ac8a08d5c304db (diff) |
Add kernel regression tests for socket splicing.
Diffstat (limited to 'regress/sys')
89 files changed, 3098 insertions, 0 deletions
diff --git a/regress/sys/kern/splice/Child.pm b/regress/sys/kern/splice/Child.pm new file mode 100644 index 00000000000..091c2c9e448 --- /dev/null +++ b/regress/sys/kern/splice/Child.pm @@ -0,0 +1,34 @@ +# $OpenBSD: Child.pm,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; + +package Child; +use parent 'Proc'; + +sub new { + my $class = shift; + my %args = @_; + $args{up} ||= "Forked"; + my $self = Proc::new($class, %args); + return $self; +} + +sub child { +} + +1; diff --git a/regress/sys/kern/splice/Client.pm b/regress/sys/kern/splice/Client.pm new file mode 100644 index 00000000000..74f3b866e93 --- /dev/null +++ b/regress/sys/kern/splice/Client.pm @@ -0,0 +1,81 @@ +# $OpenBSD: Client.pm,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; + +package Client; +use parent 'Proc'; +use Carp; +use Socket qw(IPPROTO_TCP TCP_NODELAY); +use Socket6; +use IO::Socket; +use IO::Socket::INET6; + +sub new { + my $class = shift; + my %args = @_; + $args{logfile} ||= "client.log"; + $args{up} ||= "Connected"; + $args{down} ||= "Shutdown|Broken pipe|Connection reset by peer"; + my $self = Proc::new($class, %args); + $self->{connectdomain} + or croak "$class connect domain not given"; + $self->{connectaddr} + or croak "$class connect addr not given"; + $self->{connectport} + or croak "$class connect port not given"; + return $self; +} + +sub child { + my $self = shift; + + my $cs = IO::Socket::INET6->new( + Proto => "tcp", + Domain => $self->{connectdomain}, + Blocking => ($self->{nonblocking} ? 0 : 1), + ) or die ref($self), " socket connect failed: $!"; + if ($self->{oobinline}) { + setsockopt($cs, SOL_SOCKET, SO_OOBINLINE, pack('i', 1)) + or die ref($self), " set oobinline connect failed: $!"; + } + if ($self->{sndbuf}) { + setsockopt($cs, SOL_SOCKET, SO_SNDBUF, + pack('i', $self->{sndbuf})) + or die ref($self), " set sndbuf connect failed: $!"; + } + if ($self->{rcvbuf}) { + setsockopt($cs, SOL_SOCKET, SO_RCVBUF, + pack('i', $self->{rcvbuf})) + or die ref($self), " set rcvbuf connect failed: $!"; + } + setsockopt($cs, IPPROTO_TCP, TCP_NODELAY, pack('i', 1)) + or die ref($self), " set nodelay connect failed: $!"; + my @rres = getaddrinfo($self->{connectaddr}, $self->{connectport}, + $self->{connectdomain}, SOCK_STREAM); + $cs->connect($rres[3]) + or die ref($self), " connect failed: $!"; + print STDERR "connect sock: ",$cs->sockhost()," ",$cs->sockport(),"\n"; + print STDERR "connect peer: ",$cs->peerhost()," ",$cs->peerport(),"\n"; + + open(STDOUT, '>&', $cs) + or die ref($self), " dup STDOUT failed: $!"; + open(STDIN, '<&', $cs) + or die ref($self), " dup STDIN failed: $!"; +} + +1; diff --git a/regress/sys/kern/splice/Makefile b/regress/sys/kern/splice/Makefile new file mode 100644 index 00000000000..390da442f89 --- /dev/null +++ b/regress/sys/kern/splice/Makefile @@ -0,0 +1,51 @@ +# $OpenBSD: Makefile,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# The following ports must be installed for the args-* regression test: +# p5-IO-Socket-INET6 object interface for AF_INET and AF_INET6 domain sockets +# p5-Socket6 Perl defines relating to AF_INET6 sockets + +ERRS != ls error-*.pl +ARGS != ls args-*.pl +TARGETS ?= ${ERRS} ${ARGS} +REGRESS_TARGETS = ${TARGETS:S/^/run-regress-/} +CLEANFILES = *.log ktrace.out + +# Fill out these variables if you want to test socket splicing with +# the relay process running on a remote machine. You have to specify +# a local and remote ip address for the tcp connections. To control +# the remote machine you need a hostname for ssh to log in. All the +# test files must be in the same directory local and remote. +#LOCAL_ADDR ?= +#REMOTE_ADDR ?= +#REMOTE_SSH ?= + +# The error tests try to splice unsuitable sockets and check the +# kernel error code. + +.for e in ${ERRS} +run-regress-$e: $e + time perl $e +.endfor + +# The arg tests take a perl hash with arguments controlling the +# test parameters. Generally they consist of client, relay, server. +# The relay.pl test fork these three processes locally. The remote.pl +# test has local client and server but the relay process is running +# on a remote machine reachable with ssh. For echo.pl test the +# relay is an echo process and the client and server process share +# the same tcp connection. All tests can run with a regular userland +# copy relay or with a kernel socket splicing relay. + +.for a in ${ARGS} +run-regress-$a: $a + time perl relay.pl copy $a + time perl relay.pl splice $a +.if REMOTE_SSH + time perl remote.pl copy ${LOCAL_ADDR} ${REMOTE_ADDR} ${REMOTE_SSH} $a + time perl remote.pl splice ${LOCAL_ADDR} ${REMOTE_ADDR} ${REMOTE_SSH} $a +.endif + time perl echo.pl copy $a + time perl echo.pl splice $a +.endfor + +.include <bsd.regress.mk> diff --git a/regress/sys/kern/splice/Proc.pm b/regress/sys/kern/splice/Proc.pm new file mode 100644 index 00000000000..ac04baa9938 --- /dev/null +++ b/regress/sys/kern/splice/Proc.pm @@ -0,0 +1,153 @@ +# $OpenBSD: Proc.pm,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; + +package Proc; +use Carp; +use List::Util qw(first); +use POSIX; +use Time::HiRes qw(time alarm sleep); + +my %CHILDREN; + +BEGIN { + $SIG{TERM} = $SIG{INT} = sub { + my $sig = shift; + kill TERM => keys %CHILDREN; + $SIG{TERM} = $SIG{INT} = 'DEFAULT'; + POSIX::raise($sig); + }; +} + +END { + $SIG{TERM} = $SIG{INT} = 'DEFAULT'; + kill TERM => keys %CHILDREN; +} + +sub new { + my $class = shift; + my $self = { @_ }; + $self->{down} ||= "Shutdown"; + $self->{func} && ref($self->{func}) eq 'CODE' + or croak "$class func not given"; + $self->{logfile} + or croak "$class log file not given"; + open(my $fh, '>', $self->{logfile}) + or die "$class log file $self->{logfile} create failed: $!"; + $self->{log} = $fh; + return bless $self, $class; +} + +sub run { + my $self = shift; + + defined(my $pid = fork()) + or die ref($self), " fork child failed"; + if ($pid) { + $CHILDREN{$pid} = 1; + $self->{pid} = $pid; + return $self; + } + %CHILDREN = (); + $SIG{TERM} = $SIG{INT} = 'DEFAULT'; + $SIG{__DIE__} = sub { + die @_ if $^S; + warn @_; + IO::Handle::flush(\*STDERR); + POSIX::_exit(255); + }; + open(STDERR, '>&', $self->{log}) + or die ref($self), " dup STDERR failed: $!"; + + $self->child(); + print STDERR $self->{up}, "\n"; + $self->{func}->($self); + print STDERR "Shutdown", "\n"; + IO::Handle::flush(\*STDOUT); + IO::Handle::flush(\*STDERR); + + POSIX::_exit(0); +} + +sub wait { + my $self = shift; + my $flags = shift; + + my $pid = $self->{pid} + or croak ref($self), " no child pid"; + my $kid = waitpid($pid, $flags); + if ($kid > 0) { + my $status = $?; + my $code; + $code = "exit: ". WEXITSTATUS($?) if WIFEXITED($?); + $code = "signal: ". WTERMSIG($?) if WIFSIGNALED($?); + $code = "stop: ". WSTOPSIG($?) if WIFSTOPPED($?); + return wantarray ? ($kid, $status, $code) : $kid; + } + return $kid; +} + +sub loggrep { + my $self = shift; + my($regex, $timeout) = @_; + + my $end = time() + $timeout if $timeout; + + do { + my($kid, $status, $code) = $self->wait(WNOHANG); + if ($kid > 0 && $status != 0) { + # child terminated with failure + die ref($self), " child status: $status $code"; + } + open(my $fh, '<', $self->{logfile}) + or die ref($self), " log file open failed: $!"; + my $match = first { /$regex/ } <$fh>; + return $match if $match; + close($fh); + # pattern not found + if ($kid == 0) { + # child still running, wait for log data + sleep .1; + } else { + # child terminated, no new log data possible + return; + } + } while ($timeout and time() < $end); + + return; +} + +sub up { + my $self = shift; + my $timeout = shift || 10; + $self->loggrep(qr/$self->{up}/, $timeout) + or croak ref($self), " no $self->{up} in $self->{logfile} ". + "after $timeout seconds"; + return $self; +} + +sub down { + my $self = shift; + my $timeout = shift || 30; + $self->loggrep(qr/$self->{down}/, $timeout) + or croak ref($self), " no $self->{down} in $self->{logfile} ". + "after $timeout seconds"; + return $self; +} + +1; diff --git a/regress/sys/kern/splice/Relay.pm b/regress/sys/kern/splice/Relay.pm new file mode 100644 index 00000000000..c2ac5240cd5 --- /dev/null +++ b/regress/sys/kern/splice/Relay.pm @@ -0,0 +1,122 @@ +# $OpenBSD: Relay.pm,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; + +package Relay; +use parent 'Proc'; +use Carp; +use Socket qw(IPPROTO_TCP TCP_NODELAY); +use Socket6; +use IO::Socket; +use IO::Socket::INET6; + +sub new { + my $class = shift; + my %args = @_; + $args{logfile} ||= "relay.log"; + $args{up} ||= "Connected"; + my $self = Proc::new($class, %args); + $self->{listendomain} + or croak "$class listen domain not given"; + $self->{connectdomain} + or croak "$class connect domain not given"; + $self->{connectaddr} + or croak "$class connect addr not given"; + $self->{connectport} + or croak "$class connect port not given"; + my $ls = IO::Socket::INET6->new( + Proto => "tcp", + ReuseAddr => 1, + Domain => $self->{listendomain}, + $self->{listenaddr} ? (LocalAddr => $self->{listenaddr}) : (), + $self->{listenport} ? (LocalPort => $self->{listenport}) : (), + ) or die ref($self), " socket failed: $!"; + if ($self->{oobinline}) { + setsockopt($ls, SOL_SOCKET, SO_OOBINLINE, pack('i', 1)) + or die ref($self), " set oobinline listen failed: $!"; + } + if ($self->{sndbuf}) { + setsockopt($ls, SOL_SOCKET, SO_SNDBUF, + pack('i', $self->{sndbuf})) + or die ref($self), " set sndbuf listen failed: $!"; + } + if ($self->{rcvbuf}) { + setsockopt($ls, SOL_SOCKET, SO_RCVBUF, + pack('i', $self->{rcvbuf})) + or die ref($self), " set rcvbuf listen failed: $!"; + } + setsockopt($ls, IPPROTO_TCP, TCP_NODELAY, pack('i', 1)) + or die ref($self), " set nodelay listen failed: $!"; + listen($ls, 1) + or die ref($self), " listen failed: $!"; + my $log = $self->{log}; + print $log "listen sock: ",$ls->sockhost()," ",$ls->sockport(),"\n"; + $self->{listenaddr} = $ls->sockhost() unless $self->{listenaddr}; + $self->{listenport} = $ls->sockport() unless $self->{listenport}; + $self->{ls} = $ls; + return $self; +} + +sub child { + my $self = shift; + + my $as = $self->{ls}->accept() + or die ref($self), " socket accept failed: $!"; + print STDERR "accept sock: ",$as->sockhost()," ",$as->sockport(),"\n"; + print STDERR "accept peer: ",$as->peerhost()," ",$as->peerport(),"\n"; + $as->blocking($self->{nonblocking} ? 0 : 1) + or die ref($self), " non-blocking accept failed: $!"; + + open(STDIN, '<&', $as) + or die ref($self), " dup STDIN failed: $!"; + print STDERR "Accepted\n"; + + my $cs = IO::Socket::INET6->new( + Proto => "tcp", + Domain => $self->{connectdomain}, + Blocking => ($self->{nonblocking} ? 0 : 1), + ) or die ref($self), " socket connect failed: $!"; + if ($self->{oobinline}) { + setsockopt($cs, SOL_SOCKET, SO_OOBINLINE, pack('i', 1)) + or die ref($self), " set oobinline connect failed: $!"; + } + if ($self->{sndbuf}) { + setsockopt($cs, SOL_SOCKET, SO_SNDBUF, + pack('i', $self->{sndbuf})) + or die ref($self), " set sndbuf connect failed: $!"; + } + if ($self->{rcvbuf}) { + setsockopt($cs, SOL_SOCKET, SO_RCVBUF, + pack('i', $self->{rcvbuf})) + or die ref($self), " set rcvbuf connect failed: $!"; + } + setsockopt($cs, IPPROTO_TCP, TCP_NODELAY, pack('i', 1)) + or die ref($self), " set nodelay connect failed: $!"; + my @rres = getaddrinfo($self->{connectaddr}, $self->{connectport}, + $self->{connectdomain}, SOCK_STREAM); + $cs->connect($rres[3]) + or die ref($self), " connect failed: $!"; + print STDERR "connect sock: ",$cs->sockhost()," ",$cs->sockport(),"\n"; + print STDERR "connect peer: ",$cs->peerhost()," ",$cs->peerport(),"\n" + unless $self->{nonblocking}; + + open(STDOUT, '>&', $cs) + or die ref($self), " dup STDOUT failed: $!"; +} + +1; diff --git a/regress/sys/kern/splice/Remote.pm b/regress/sys/kern/splice/Remote.pm new file mode 100644 index 00000000000..2f68c09d0ff --- /dev/null +++ b/regress/sys/kern/splice/Remote.pm @@ -0,0 +1,73 @@ +# $OpenBSD: Remote.pm,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; + +package Remote; +use parent 'Proc'; +use Carp; +use Cwd; +use File::Basename; + +sub new { + my $class = shift; + my %args = @_; + $args{logfile} ||= "remote.log"; + $args{up} ||= "Started"; + $args{func} = sub { Carp::confess "$class func may not be called" }; + $args{remotessh} + or croak "$class remote ssh host not given"; + $args{forward} + or croak "$class forward not given"; + my $self = Proc::new($class, %args); + $self->{listenaddr} + or croak "$class listen addr not given"; + $self->{connectaddr} + or croak "$class connect addr not given"; + $self->{connectport} + or croak "$class connect port not given"; + return $self; +} + +sub up { + my $self = Proc::up(shift, @_); + my $timeout = shift || 10; + my $lsock = $self->loggrep(qr/^listen sock: /, $timeout) + or croak ref($self), " no listen sock in $self->{logfile} ". + "after $timeout seconds"; + my($addr, $port) = $lsock =~ /: (\S+) (\S+)$/ + or croak ref($self), " no listen addr and port in $self->{logfile}"; + $self->{listenaddr} = $addr; + $self->{listenport} = $port; + return $self; +} + +sub child { + my $self = shift; + + print STDERR $self->{up}, "\n"; + my @opts = split(' ', $ENV{SSH_OPTIONS}) if $ENV{SSH_OPTIONS}; + my @cmd = ('ssh', '-n', @opts, $self->{remotessh}, 'perl', + '-I', getcwd(), getcwd().'/'.basename($0), $self->{forward}, + $self->{listenaddr}, $self->{connectaddr}, $self->{connectport}, + ($self->{testfile} ? getcwd().'/'.basename($self->{testfile}) : + ())); + exec @cmd; + die "Exec @cmd failed: $!"; +} + +1; diff --git a/regress/sys/kern/splice/Server.pm b/regress/sys/kern/splice/Server.pm new file mode 100644 index 00000000000..32168d820a5 --- /dev/null +++ b/regress/sys/kern/splice/Server.pm @@ -0,0 +1,85 @@ +# $OpenBSD: Server.pm,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; + +package Server; +use parent 'Proc'; +use Carp; +use Socket qw(IPPROTO_TCP TCP_NODELAY); +use Socket6; +use IO::Socket; +use IO::Socket::INET6; + +sub new { + my $class = shift; + my %args = @_; + $args{logfile} ||= "server.log"; + $args{up} ||= "Accepted"; + my $self = Proc::new($class, %args); + $self->{listendomain} + or croak "$class listen domain not given"; + my $ls = IO::Socket::INET6->new( + Proto => "tcp", + ReuseAddr => 1, + Domain => $self->{listendomain}, + $self->{listenaddr} ? (LocalAddr => $self->{listenaddr}) : (), + $self->{listenport} ? (LocalPort => $self->{listenport}) : (), + ) or die ref($self), " socket failed: $!"; + if ($self->{oobinline}) { + setsockopt($ls, SOL_SOCKET, SO_OOBINLINE, pack('i', 1)) + or die ref($self), " set oobinline listen failed: $!"; + } + if ($self->{sndbuf}) { + setsockopt($ls, SOL_SOCKET, SO_SNDBUF, + pack('i', $self->{sndbuf})) + or die ref($self), " set sndbuf listen failed: $!"; + } + if ($self->{rcvbuf}) { + setsockopt($ls, SOL_SOCKET, SO_RCVBUF, + pack('i', $self->{rcvbuf})) + or die ref($self), " set rcvbuf listen failed: $!"; + } + setsockopt($ls, IPPROTO_TCP, TCP_NODELAY, pack('i', 1)) + or die ref($self), " set nodelay listen failed: $!"; + listen($ls, 1) + or die ref($self), " socket failed: $!"; + my $log = $self->{log}; + print $log "listen sock: ",$ls->sockhost()," ",$ls->sockport(),"\n"; + $self->{listenaddr} = $ls->sockhost() unless $self->{listenaddr}; + $self->{listenport} = $ls->sockport() unless $self->{listenport}; + $self->{ls} = $ls; + return $self; +} + +sub child { + my $self = shift; + + my $as = $self->{ls}->accept() + or die ref($self), " socket accept failed: $!"; + print STDERR "accept sock: ",$as->sockhost()," ",$as->sockport(),"\n"; + print STDERR "accept peer: ",$as->peerhost()," ",$as->peerport(),"\n"; + $as->blocking($self->{nonblocking} ? 0 : 1) + or die ref($self), " non-blocking accept failed: $!"; + + open(STDIN, '<&', $as) + or die ref($self), " dup STDIN failed: $!"; + open(STDOUT, '>&', $as) + or die ref($self), " dup STDOUT failed: $!"; +} + +1; diff --git a/regress/sys/kern/splice/args-default.pl b/regress/sys/kern/splice/args-default.pl new file mode 100644 index 00000000000..28e53a92126 --- /dev/null +++ b/regress/sys/kern/splice/args-default.pl @@ -0,0 +1,11 @@ +# test default values + +use strict; +use warnings; + +our %args = ( + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-inet6-client.pl b/regress/sys/kern/splice/args-inet6-client.pl new file mode 100644 index 00000000000..a542fd12f6d --- /dev/null +++ b/regress/sys/kern/splice/args-inet6-client.pl @@ -0,0 +1,23 @@ +# test ipv6 client + +use strict; +use warnings; + +our %args = ( + client => { + connectdomain => AF_INET6, + connectaddr => "::1", + }, + relay => { + listendomain => AF_INET6, + listenaddr => "::1", + connectdomain => AF_INET, + connectaddr => "127.0.0.1", + }, + server => { + listendomain => AF_INET, + listenaddr => "127.0.0.1", + }, +); + +1; diff --git a/regress/sys/kern/splice/args-inet6-server.pl b/regress/sys/kern/splice/args-inet6-server.pl new file mode 100644 index 00000000000..fa560098f5b --- /dev/null +++ b/regress/sys/kern/splice/args-inet6-server.pl @@ -0,0 +1,23 @@ +# test ipv6 server + +use strict; +use warnings; + +our %args = ( + client => { + connectdomain => AF_INET, + connectaddr => "127.0.0.1", + }, + relay => { + listendomain => AF_INET, + listenaddr => "127.0.0.1", + connectdomain => AF_INET6, + connectaddr => "::1", + }, + server => { + listendomain => AF_INET6, + listenaddr => "::1", + }, +); + +1; diff --git a/regress/sys/kern/splice/args-inet6.pl b/regress/sys/kern/splice/args-inet6.pl new file mode 100644 index 00000000000..31b481ca796 --- /dev/null +++ b/regress/sys/kern/splice/args-inet6.pl @@ -0,0 +1,23 @@ +# test ipv6 client and server + +use strict; +use warnings; + +our %args = ( + client => { + connectdomain => AF_INET6, + connectaddr => "::1", + }, + relay => { + listendomain => AF_INET6, + listenaddr => "::1", + connectdomain => AF_INET6, + connectaddr => "::1", + }, + server => { + listendomain => AF_INET6, + listenaddr => "::1", + }, +); + +1; diff --git a/regress/sys/kern/splice/args-long.pl b/regress/sys/kern/splice/args-long.pl new file mode 100644 index 00000000000..e88d6f40c0d --- /dev/null +++ b/regress/sys/kern/splice/args-long.pl @@ -0,0 +1,14 @@ +# test longer data length + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-max-sleep-client-nonblock.pl b/regress/sys/kern/splice/args-max-sleep-client-nonblock.pl new file mode 100644 index 00000000000..6bf962dcca3 --- /dev/null +++ b/regress/sys/kern/splice/args-max-sleep-client-nonblock.pl @@ -0,0 +1,19 @@ +# test maximum data length with delay before client write with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + nocheck => 1, + }, + relay => { + max => 113, + nonblocking => 1, + }, + len => 113, + md5 => "dc099ef642faa02bce71298f11e7d44d", +); + +1; diff --git a/regress/sys/kern/splice/args-max-sleep-client-short.pl b/regress/sys/kern/splice/args-max-sleep-client-short.pl new file mode 100644 index 00000000000..79d21aea536 --- /dev/null +++ b/regress/sys/kern/splice/args-max-sleep-client-short.pl @@ -0,0 +1,18 @@ +# test maximum data length with delay before client write + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + nocheck => 1, + }, + relay => { + max => 113, + }, + len => 113, + md5 => "dc099ef642faa02bce71298f11e7d44d", +); + +1; diff --git a/regress/sys/kern/splice/args-max-sleep-client.pl b/regress/sys/kern/splice/args-max-sleep-client.pl new file mode 100644 index 00000000000..e46f44e68ee --- /dev/null +++ b/regress/sys/kern/splice/args-max-sleep-client.pl @@ -0,0 +1,19 @@ +# test maximum data length with delay before client write + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); sleep 3; write_char(@_); }, + len => 2**17, + nocheck => 1, + }, + relay => { + max => 32117, + }, + len => 32117, + md5 => "ee338e9693fb2a2ec101bb28935ed123", +); + +1; diff --git a/regress/sys/kern/splice/args-max-sleep-relay-short.pl b/regress/sys/kern/splice/args-max-sleep-relay-short.pl new file mode 100644 index 00000000000..f8d38b64a3f --- /dev/null +++ b/regress/sys/kern/splice/args-max-sleep-relay-short.pl @@ -0,0 +1,18 @@ +# test maximum data length with delay before relay copy and short len + +use strict; +use warnings; + +our %args = ( + client => { + nocheck => 1, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + max => 113, + }, + len => 113, + md5 => "dc099ef642faa02bce71298f11e7d44d", +); + +1; diff --git a/regress/sys/kern/splice/args-max-sleep-relay.pl b/regress/sys/kern/splice/args-max-sleep-relay.pl new file mode 100644 index 00000000000..a921608e704 --- /dev/null +++ b/regress/sys/kern/splice/args-max-sleep-relay.pl @@ -0,0 +1,21 @@ +# test maximum data length with delay before relay copy + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**17, + down => "Client print failed: Broken pipe", + nocheck => 1, + }, + relay => { + func => sub { sleep 3; relay(@_); shutin(@_); sleep 1; }, + max => 32117, + }, + len => 32117, + md5 => "ee338e9693fb2a2ec101bb28935ed123", +); + +1; diff --git a/regress/sys/kern/splice/args-max-sleep-server.pl b/regress/sys/kern/splice/args-max-sleep-server.pl new file mode 100644 index 00000000000..13f01f4e8a5 --- /dev/null +++ b/regress/sys/kern/splice/args-max-sleep-server.pl @@ -0,0 +1,22 @@ +# test maximum data length with delay before server read + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**17, + nocheck => 1, + }, + relay => { + max => 32117, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 32117, + md5 => "ee338e9693fb2a2ec101bb28935ed123", +); + +1; diff --git a/regress/sys/kern/splice/args-max.pl b/regress/sys/kern/splice/args-max.pl new file mode 100644 index 00000000000..33d98d02130 --- /dev/null +++ b/regress/sys/kern/splice/args-max.pl @@ -0,0 +1,19 @@ +# test maximum data length + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**17, + nocheck => 1, + }, + relay => { + max => 32117, + }, + len => 32117, + md5 => "ee338e9693fb2a2ec101bb28935ed123", +); + +1; diff --git a/regress/sys/kern/splice/args-maxcopy-sleep-client.pl b/regress/sys/kern/splice/args-maxcopy-sleep-client.pl new file mode 100644 index 00000000000..adaed950640 --- /dev/null +++ b/regress/sys/kern/splice/args-maxcopy-sleep-client.pl @@ -0,0 +1,18 @@ +# test relay maximum data length then copy with delay before client + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + }, + relay => { + func => sub { relay(@_, 61); relay_copy(@_); }, + nocheck => 1, + }, + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-maxcopy-sleep-relay.pl b/regress/sys/kern/splice/args-maxcopy-sleep-relay.pl new file mode 100644 index 00000000000..36e0832cb0e --- /dev/null +++ b/regress/sys/kern/splice/args-maxcopy-sleep-relay.pl @@ -0,0 +1,15 @@ +# test relay maximum data length then copy with delay before relay + +use strict; +use warnings; + +our %args = ( + relay => { + func => sub { sleep 3; relay(@_, 61); relay_copy(@_); }, + nocheck => 1, + }, + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-maxcopy-sleep-server.pl b/regress/sys/kern/splice/args-maxcopy-sleep-server.pl new file mode 100644 index 00000000000..672c90db1ef --- /dev/null +++ b/regress/sys/kern/splice/args-maxcopy-sleep-server.pl @@ -0,0 +1,18 @@ +# test relay maximum data length then copy with delay before server + +use strict; +use warnings; + +our %args = ( + relay => { + func => sub { relay(@_, 61); relay_copy(@_); }, + nocheck => 1, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-nonblock.pl b/regress/sys/kern/splice/args-nonblock.pl new file mode 100644 index 00000000000..4f3ae6a9737 --- /dev/null +++ b/regress/sys/kern/splice/args-nonblock.pl @@ -0,0 +1,17 @@ +# test with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + nonblocking => 1, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-null-max-sleep-client-nonblock.pl b/regress/sys/kern/splice/args-null-max-sleep-client-nonblock.pl new file mode 100644 index 00000000000..801a9584d7e --- /dev/null +++ b/regress/sys/kern/splice/args-null-max-sleep-client-nonblock.pl @@ -0,0 +1,19 @@ +# test maximum data length with delay before empty client write with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3 }, + len => 0, + }, + relay => { + max => 113, + nonblocking => 1, + }, + len => 0, + md5 => "d41d8cd98f00b204e9800998ecf8427e", +); + +1; diff --git a/regress/sys/kern/splice/args-null-max-sleep-client.pl b/regress/sys/kern/splice/args-null-max-sleep-client.pl new file mode 100644 index 00000000000..cbf89b46a49 --- /dev/null +++ b/regress/sys/kern/splice/args-null-max-sleep-client.pl @@ -0,0 +1,18 @@ +# test maximum data length with delay before empty client write + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3 }, + len => 0, + }, + relay => { + max => 113, + }, + len => 0, + md5 => "d41d8cd98f00b204e9800998ecf8427e", +); + +1; diff --git a/regress/sys/kern/splice/args-null-sleep-client.pl b/regress/sys/kern/splice/args-null-sleep-client.pl new file mode 100644 index 00000000000..5a02ceb43f4 --- /dev/null +++ b/regress/sys/kern/splice/args-null-sleep-client.pl @@ -0,0 +1,15 @@ +# test with delay before empty client write + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3 }, + len => 0, + }, + len => 0, + md5 => "d41d8cd98f00b204e9800998ecf8427e", +); + +1; diff --git a/regress/sys/kern/splice/args-null.pl b/regress/sys/kern/splice/args-null.pl new file mode 100644 index 00000000000..fcb0c70826f --- /dev/null +++ b/regress/sys/kern/splice/args-null.pl @@ -0,0 +1,14 @@ +# test emtpy client write + +use strict; +use warnings; + +our %args = ( + client => { + len => 0, + }, + len => 0, + md5 => "d41d8cd98f00b204e9800998ecf8427e", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-max-sleep-client.pl b/regress/sys/kern/splice/args-oob-max-sleep-client.pl new file mode 100644 index 00000000000..3fa0302317a --- /dev/null +++ b/regress/sys/kern/splice/args-oob-max-sleep-client.pl @@ -0,0 +1,22 @@ +# test out-of-band data with maximum data length delay before client + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); sleep 3; write_oob(@_); }, + nocheck => 1, + }, + relay => { + max => 61, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 61, + md5 => "e4282daf8d2ca21cc8b70b1314713314", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-max-sleep-relay.pl b/regress/sys/kern/splice/args-oob-max-sleep-relay.pl new file mode 100644 index 00000000000..72e0d2d6aa6 --- /dev/null +++ b/regress/sys/kern/splice/args-oob-max-sleep-relay.pl @@ -0,0 +1,23 @@ +# test out-of-band data with maximum data length delay before relay + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_oob(@_); }, + nocheck => 1, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + max => 61, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 61, + md5 => "e4282daf8d2ca21cc8b70b1314713314", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-max-sleep-server.pl b/regress/sys/kern/splice/args-oob-max-sleep-server.pl new file mode 100644 index 00000000000..39193a63585 --- /dev/null +++ b/regress/sys/kern/splice/args-oob-max-sleep-server.pl @@ -0,0 +1,22 @@ +# test out-of-band data with maximum data length delay before server + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_oob(@_); }, + nocheck => 1, + }, + relay => { + max => 61, + nocheck => 1, + }, + server => { + func => sub { sleep 3; read_oob(@_); }, + }, + len => 61, + md5 => "e4282daf8d2ca21cc8b70b1314713314", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-max.pl b/regress/sys/kern/splice/args-oob-max.pl new file mode 100644 index 00000000000..a60cfed6d48 --- /dev/null +++ b/regress/sys/kern/splice/args-oob-max.pl @@ -0,0 +1,22 @@ +# test out-of-band data with maximum data length + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_oob(@_); }, + nocheck => 1, + }, + relay => { + max => 61, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 61, + md5 => "e4282daf8d2ca21cc8b70b1314713314", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-nonblock.pl b/regress/sys/kern/splice/args-oob-nonblock.pl new file mode 100644 index 00000000000..63ca0c55471 --- /dev/null +++ b/regress/sys/kern/splice/args-oob-nonblock.pl @@ -0,0 +1,22 @@ +# test out-of-band data with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => \&write_oob, + nocheck => 1, + }, + relay => { + nonblocking => 1, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 247, + md5 => "f76df02a35322058b8c29002aaea944f", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-reverse-nonblock.pl b/regress/sys/kern/splice/args-oob-reverse-nonblock.pl new file mode 100644 index 00000000000..b9b8f3bb712 --- /dev/null +++ b/regress/sys/kern/splice/args-oob-reverse-nonblock.pl @@ -0,0 +1,23 @@ +# test out-of-band data when reverse sending with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_oob, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + nonblocking => 1, + nocheck => 1, + }, + server => { + func => \&write_oob, + nocheck => 1, + }, + len => 247, + md5 => "f76df02a35322058b8c29002aaea944f", +); + +1; diff --git a/regress/sys/kern/splice/args-oob-reverse.pl b/regress/sys/kern/splice/args-oob-reverse.pl new file mode 100644 index 00000000000..fb83bb3b645 --- /dev/null +++ b/regress/sys/kern/splice/args-oob-reverse.pl @@ -0,0 +1,22 @@ +# test out-of-band data when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_oob, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + nocheck => 1, + }, + server => { + func => \&write_oob, + nocheck => 1, + }, + len => 247, + md5 => "f76df02a35322058b8c29002aaea944f", +); + +1; diff --git a/regress/sys/kern/splice/args-oob.pl b/regress/sys/kern/splice/args-oob.pl new file mode 100644 index 00000000000..b630a0702e7 --- /dev/null +++ b/regress/sys/kern/splice/args-oob.pl @@ -0,0 +1,21 @@ +# test out-of-band data + +use strict; +use warnings; + +our %args = ( + client => { + func => \&write_oob, + nocheck => 1, + }, + relay => { + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 247, + md5 => "f76df02a35322058b8c29002aaea944f", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-max-sleep-client.pl b/regress/sys/kern/splice/args-oobinline-max-sleep-client.pl new file mode 100644 index 00000000000..9e48feb9cfe --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-max-sleep-client.pl @@ -0,0 +1,23 @@ +# test inline out-of-band data with maximum data length delay before client + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); sleep 3; write_oob(@_); }, + nocheck => 1, + }, + relay => { + oobinline => 1, + max => 61, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 61, + md5 => "c9f459db9b4f369980c79bff17e1c2a0", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-max-sleep-relay.pl b/regress/sys/kern/splice/args-oobinline-max-sleep-relay.pl new file mode 100644 index 00000000000..d778af41778 --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-max-sleep-relay.pl @@ -0,0 +1,25 @@ +# test inline out-of-band data with maximum data length delay before relay + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_oob(@_); }, + nocheck => 1, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + oobinline => 1, + max => 61, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 61, + # the oob data is converted to non-oob + md5 => "4b5efc5f86fa5fc873c82103ceece85d", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-max-sleep-server.pl b/regress/sys/kern/splice/args-oobinline-max-sleep-server.pl new file mode 100644 index 00000000000..7f35a2cb405 --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-max-sleep-server.pl @@ -0,0 +1,23 @@ +# test inline out-of-band data with maximum data length delay before server + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_oob(@_); }, + nocheck => 1, + }, + relay => { + oobinline => 1, + max => 61, + nocheck => 1, + }, + server => { + func => sub { sleep 3; read_oob(@_); }, + }, + len => 61, + md5 => "c9f459db9b4f369980c79bff17e1c2a0", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-max.pl b/regress/sys/kern/splice/args-oobinline-max.pl new file mode 100644 index 00000000000..c6801ddfb5f --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-max.pl @@ -0,0 +1,23 @@ +# test inline out-of-band data with maximum data length + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_oob(@_); }, + nocheck => 1, + }, + relay => { + oobinline => 1, + max => 61, + nocheck => 1, + }, + server => { + func => \&read_oob, + }, + len => 61, + md5 => "c9f459db9b4f369980c79bff17e1c2a0", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-nonblock.pl b/regress/sys/kern/splice/args-oobinline-nonblock.pl new file mode 100644 index 00000000000..31e3f69d92a --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-nonblock.pl @@ -0,0 +1,22 @@ +# test inline out-of-band data with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => \&write_oob, + }, + relay => { + oobinline => 1, + nonblocking => 1, + }, + server => { + func => \&read_oob, + oobinline => 1, + }, + len => 251, + md5 => "24b69642243fee9834bceee5b47078ae", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-reverse-nonblock.pl b/regress/sys/kern/splice/args-oobinline-reverse-nonblock.pl new file mode 100644 index 00000000000..e9a784433c1 --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-reverse-nonblock.pl @@ -0,0 +1,23 @@ +# test inline out-of-band data when reverse sending with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_oob, + oobinline => 1, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + oobinline => 1, + nonblocking => 1, + }, + server => { + func => \&write_oob, + }, + len => 251, + md5 => "24b69642243fee9834bceee5b47078ae", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline-reverse.pl b/regress/sys/kern/splice/args-oobinline-reverse.pl new file mode 100644 index 00000000000..4a570b3e5bf --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline-reverse.pl @@ -0,0 +1,22 @@ +# test inline out-of-band data when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_oob, + oobinline => 1, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + oobinline => 1, + }, + server => { + func => \&write_oob, + }, + len => 251, + md5 => "24b69642243fee9834bceee5b47078ae", +); + +1; diff --git a/regress/sys/kern/splice/args-oobinline.pl b/regress/sys/kern/splice/args-oobinline.pl new file mode 100644 index 00000000000..7de0bcb55a0 --- /dev/null +++ b/regress/sys/kern/splice/args-oobinline.pl @@ -0,0 +1,21 @@ +# test inline out-of-band data + +use strict; +use warnings; + +our %args = ( + client => { + func => \&write_oob, + }, + relay => { + oobinline => 1, + }, + server => { + func => \&read_oob, + oobinline => 1, + }, + len => 251, + md5 => "24b69642243fee9834bceee5b47078ae", +); + +1; diff --git a/regress/sys/kern/splice/args-relay-close-in.pl b/regress/sys/kern/splice/args-relay-close-in.pl new file mode 100644 index 00000000000..06180bc910c --- /dev/null +++ b/regress/sys/kern/splice/args-relay-close-in.pl @@ -0,0 +1,29 @@ +# test relay closes stdin after relaying some data + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**30, # not reached + sndbuf => 2**10, # small buffer triggers error during write + # the error message seems to be timing dependent + down => "Client print failed: (Broken pipe|Connection reset by peer)", + error => 54, + }, + relay => { + func => sub { errignore(@_); $SIG{ALRM} = sub { close STDIN }; + alarm(3); relay(@_); }, + rcvbuf => 2**10, + sndbuf => 2**10, + down => "Bad file descriptor", + nocheck => 1, + errorin => "", + }, + server => { + rcvbuf => 2**10, + }, +); + +1; diff --git a/regress/sys/kern/splice/args-reset-eof.pl b/regress/sys/kern/splice/args-reset-eof.pl new file mode 100644 index 00000000000..11665fc628e --- /dev/null +++ b/regress/sys/kern/splice/args-reset-eof.pl @@ -0,0 +1,12 @@ +# test connection reset by server at eof, after all data has been read + +use strict; +use warnings; + +our %args = ( + server => { + func => sub { read_char(@_); sleep 3; solinger(@_); }, + }, +); + +1; diff --git a/regress/sys/kern/splice/args-reset.pl b/regress/sys/kern/splice/args-reset.pl new file mode 100644 index 00000000000..319425c5053 --- /dev/null +++ b/regress/sys/kern/splice/args-reset.pl @@ -0,0 +1,24 @@ +# test connection reset by server + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**17, + }, + relay => { + func => sub { errignore(@_); relay(@_); }, + sndbuf => 2**12, + rcvbuf => 2**12, + down => "Broken pipe|Connection reset by peer", + }, + server => { + func => sub { sleep 3; solinger(@_); }, + rcvbuf => 2**12, + }, + nocheck => 1, +); + +1; diff --git a/regress/sys/kern/splice/args-reverse-long.pl b/regress/sys/kern/splice/args-reverse-long.pl new file mode 100644 index 00000000000..27d5f0e4ae8 --- /dev/null +++ b/regress/sys/kern/splice/args-reverse-long.pl @@ -0,0 +1,21 @@ +# test longer data lenght when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_char, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + }, + server => { + func => \&write_char, + len => 2**17, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-reverse-nonblock.pl b/regress/sys/kern/splice/args-reverse-nonblock.pl new file mode 100644 index 00000000000..48146c8b354 --- /dev/null +++ b/regress/sys/kern/splice/args-reverse-nonblock.pl @@ -0,0 +1,21 @@ +# test reverse sending with non-blocking relay + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_char, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + nonblocking => 1, + }, + server => { + func => \&write_char, + }, + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-reverse-null.pl b/regress/sys/kern/splice/args-reverse-null.pl new file mode 100644 index 00000000000..65c54a93b0a --- /dev/null +++ b/regress/sys/kern/splice/args-reverse-null.pl @@ -0,0 +1,21 @@ +# test emtpy server write when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_char, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + }, + server => { + func => \&write_char, + len => 0, + }, + len => 0, + md5 => "d41d8cd98f00b204e9800998ecf8427e", +); + +1; diff --git a/regress/sys/kern/splice/args-reverse-sleep-client.pl b/regress/sys/kern/splice/args-reverse-sleep-client.pl new file mode 100644 index 00000000000..244e65dc85b --- /dev/null +++ b/regress/sys/kern/splice/args-reverse-sleep-client.pl @@ -0,0 +1,21 @@ +# test delay before client read when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; read_char(@_); }, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + }, + server => { + func => \&write_char, + len => 2**17, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-reverse-sleep-relay.pl b/regress/sys/kern/splice/args-reverse-sleep-relay.pl new file mode 100644 index 00000000000..fbc218f82cf --- /dev/null +++ b/regress/sys/kern/splice/args-reverse-sleep-relay.pl @@ -0,0 +1,21 @@ +# test delay before relay copy when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_char, + }, + relay => { + func => sub { ioflip(@_); sleep 3; relay(@_); }, + }, + server => { + func => \&write_char, + len => 2**17, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-reverse-sleep-server.pl b/regress/sys/kern/splice/args-reverse-sleep-server.pl new file mode 100644 index 00000000000..ceff0eac461 --- /dev/null +++ b/regress/sys/kern/splice/args-reverse-sleep-server.pl @@ -0,0 +1,21 @@ +# test delay before server write when reverse sending + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_char, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + }, + server => { + func => sub { sleep 3; write_char(@_); }, + len => 2**17, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-reverse.pl b/regress/sys/kern/splice/args-reverse.pl new file mode 100644 index 00000000000..33ef06466a7 --- /dev/null +++ b/regress/sys/kern/splice/args-reverse.pl @@ -0,0 +1,20 @@ +# test reverse sending from server to client + +use strict; +use warnings; + +our %args = ( + client => { + func => \&read_char, + }, + relay => { + func => sub { ioflip(@_); relay(@_); }, + }, + server => { + func => \&write_char, + }, + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-server-abort.pl b/regress/sys/kern/splice/args-server-abort.pl new file mode 100644 index 00000000000..b0b64874e6d --- /dev/null +++ b/regress/sys/kern/splice/args-server-abort.pl @@ -0,0 +1,31 @@ +# test server reads and exits after reading some data + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**30, # not reached + sndbuf => 2**10, # small buffer triggers error during write + # the error message seems to be timing dependent + down => "Client print failed: (Broken pipe|Connection reset by peer)", + error => 54, + }, + relay => { + func => sub { errignore(@_); relay(@_); }, + rcvbuf => 2**10, + sndbuf => 2**10, + down => "Broken pipe|Connection reset by peer", + nocheck => 1, + errorin => 0, # syscall has read the error and resetted it + errorout => 54, + }, + server => { + func => sub { $SIG{ALRM} = sub { print STDERR "\nShutdown\n"; exit 0 }; + alarm(3); read_char(@_); }, + }, + noecho => 1, +); + +1; diff --git a/regress/sys/kern/splice/args-server-exit.pl b/regress/sys/kern/splice/args-server-exit.pl new file mode 100644 index 00000000000..99cc94b0bb6 --- /dev/null +++ b/regress/sys/kern/splice/args-server-exit.pl @@ -0,0 +1,33 @@ +# test server sleeps and exits without reading data + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { errignore(@_); write_char(@_); }, + len => 2**17, + sndbuf => 2**10, # small buffer triggers error during write + # the error message seems to be timing dependent + down => "Client print failed: (Broken pipe|Connection reset by peer)", + error => 54, + }, + relay => { + func => sub { errignore(@_); relay(@_); }, + rcvbuf => 2**10, + sndbuf => 2**10, + down => "Broken pipe", + nocheck => 1, + errorin => 0, # syscall has read the error and resetted it + errorout => 54, + }, + server => { + func => sub { sleep 3; }, + rcvbuf => 2**10, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", + noecho => 1, +); + +1; diff --git a/regress/sys/kern/splice/args-short.pl b/regress/sys/kern/splice/args-short.pl new file mode 100644 index 00000000000..39c238c9c31 --- /dev/null +++ b/regress/sys/kern/splice/args-short.pl @@ -0,0 +1,14 @@ +# test copy with short block size + +use strict; +use warnings; + +our %args = ( + realy => { + size => 17, + }, + len => 251, + md5 => "bc3a3f39af35fe5b1687903da2b00c7f", +); + +1; diff --git a/regress/sys/kern/splice/args-sleep-client.pl b/regress/sys/kern/splice/args-sleep-client.pl new file mode 100644 index 00000000000..9070a18c691 --- /dev/null +++ b/regress/sys/kern/splice/args-sleep-client.pl @@ -0,0 +1,15 @@ +# test delay before client write + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + len => 2**17, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-sleep-relay.pl b/regress/sys/kern/splice/args-sleep-relay.pl new file mode 100644 index 00000000000..3b3b9b1651c --- /dev/null +++ b/regress/sys/kern/splice/args-sleep-relay.pl @@ -0,0 +1,17 @@ +# test delay before relay copy + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-sleep-server.pl b/regress/sys/kern/splice/args-sleep-server.pl new file mode 100644 index 00000000000..50920d1a091 --- /dev/null +++ b/regress/sys/kern/splice/args-sleep-server.pl @@ -0,0 +1,17 @@ +# test delay before server read + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallbuf-sleep-client.pl b/regress/sys/kern/splice/args-smallbuf-sleep-client.pl new file mode 100644 index 00000000000..e3f01629433 --- /dev/null +++ b/regress/sys/kern/splice/args-smallbuf-sleep-client.pl @@ -0,0 +1,19 @@ +# test with smaller relay send and receive buffers delay before client + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + len => 2**17, + }, + relay => { + sndbuf => 2**12, + rcvbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallbuf-sleep-relay.pl b/regress/sys/kern/splice/args-smallbuf-sleep-relay.pl new file mode 100644 index 00000000000..3a116bfeafe --- /dev/null +++ b/regress/sys/kern/splice/args-smallbuf-sleep-relay.pl @@ -0,0 +1,19 @@ +# test with smaller relay send and receive buffers delay before relay + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + sndbuf => 2**12, + rcvbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallbuf-sleep-server.pl b/regress/sys/kern/splice/args-smallbuf-sleep-server.pl new file mode 100644 index 00000000000..0ffbf9bae0f --- /dev/null +++ b/regress/sys/kern/splice/args-smallbuf-sleep-server.pl @@ -0,0 +1,21 @@ +# test with smaller relay send and receive buffers delay before server + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + sndbuf => 2**12, + rcvbuf => 2**12, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallbuf.pl b/regress/sys/kern/splice/args-smallbuf.pl new file mode 100644 index 00000000000..a554b849c4f --- /dev/null +++ b/regress/sys/kern/splice/args-smallbuf.pl @@ -0,0 +1,18 @@ +# test with smaller relay send and receive buffers + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + sndbuf => 2**12, + rcvbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallrcv-sleep-client.pl b/regress/sys/kern/splice/args-smallrcv-sleep-client.pl new file mode 100644 index 00000000000..154e7ee0c0b --- /dev/null +++ b/regress/sys/kern/splice/args-smallrcv-sleep-client.pl @@ -0,0 +1,18 @@ +# test with smaller relay receive buffer delay before client + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + len => 2**17, + }, + relay => { + rcvbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallrcv-sleep-relay.pl b/regress/sys/kern/splice/args-smallrcv-sleep-relay.pl new file mode 100644 index 00000000000..f1845c55d36 --- /dev/null +++ b/regress/sys/kern/splice/args-smallrcv-sleep-relay.pl @@ -0,0 +1,18 @@ +# test with smaller relay receive buffer delay before relay + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + rcvbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallrcv-sleep-server.pl b/regress/sys/kern/splice/args-smallrcv-sleep-server.pl new file mode 100644 index 00000000000..6f30c7ee903 --- /dev/null +++ b/regress/sys/kern/splice/args-smallrcv-sleep-server.pl @@ -0,0 +1,20 @@ +# test with smaller relay receive buffer delay before server + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + rcvbuf => 2**12, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallrcv.pl b/regress/sys/kern/splice/args-smallrcv.pl new file mode 100644 index 00000000000..f13f4e09d32 --- /dev/null +++ b/regress/sys/kern/splice/args-smallrcv.pl @@ -0,0 +1,17 @@ +# test with smaller relay receive buffer + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + rcvbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallsnd-sleep-client.pl b/regress/sys/kern/splice/args-smallsnd-sleep-client.pl new file mode 100644 index 00000000000..f2c2715023c --- /dev/null +++ b/regress/sys/kern/splice/args-smallsnd-sleep-client.pl @@ -0,0 +1,18 @@ +# test with smaller relay send buffer delay before client + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 3; write_char(@_); }, + len => 2**17, + }, + relay => { + sndbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallsnd-sleep-relay.pl b/regress/sys/kern/splice/args-smallsnd-sleep-relay.pl new file mode 100644 index 00000000000..0d79e6bc0cf --- /dev/null +++ b/regress/sys/kern/splice/args-smallsnd-sleep-relay.pl @@ -0,0 +1,18 @@ +# test with smaller relay send buffer delay before relay + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + func => sub { sleep 3; relay(@_); }, + sndbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallsnd-sleep-server.pl b/regress/sys/kern/splice/args-smallsnd-sleep-server.pl new file mode 100644 index 00000000000..62270e60d2b --- /dev/null +++ b/regress/sys/kern/splice/args-smallsnd-sleep-server.pl @@ -0,0 +1,20 @@ +# test with smaller relay send buffer delay before server + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + sndbuf => 2**12, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-smallsnd.pl b/regress/sys/kern/splice/args-smallsnd.pl new file mode 100644 index 00000000000..3193d69830e --- /dev/null +++ b/regress/sys/kern/splice/args-smallsnd.pl @@ -0,0 +1,17 @@ +# test with smaller relay send buffer + +use strict; +use warnings; + +our %args = ( + client => { + len => 2**17, + }, + relay => { + sndbuf => 2**12, + }, + len => 131072, + md5 => "31e5ad3d0d2aeb1ad8aaa847dfa665c2", +); + +1; diff --git a/regress/sys/kern/splice/args-write-sleep-server.pl b/regress/sys/kern/splice/args-write-sleep-server.pl new file mode 100644 index 00000000000..a67ba013adb --- /dev/null +++ b/regress/sys/kern/splice/args-write-sleep-server.pl @@ -0,0 +1,28 @@ +# test mix write and relay delaying before server read + +use strict; +use warnings; + +our %args = ( + client => { + func => sub { sleep 4; write_char(@_); }, + len => 65521, + nocheck => 1, + }, + relay => { + func => sub { + write_char(@_, 32749); + IO::Handle::flush(\*STDOUT); + relay(@_); + write_char(@_, 2039); + }, + nocheck => 1, + }, + server => { + func => sub { sleep 3; read_char(@_); }, + }, + len => 100309, + md5 => "0efc7833e5c0652823ca63eaccb9918f", +); + +1; diff --git a/regress/sys/kern/splice/args-write.pl b/regress/sys/kern/splice/args-write.pl new file mode 100644 index 00000000000..055475f7dc9 --- /dev/null +++ b/regress/sys/kern/splice/args-write.pl @@ -0,0 +1,24 @@ +# test mix write and relay + +use strict; +use warnings; + +our %args = ( + client => { + len => 65521, + nocheck => 1, + }, + relay => { + func => sub { + write_char(@_, 32749); + IO::Handle::flush(\*STDOUT); + relay(@_); + write_char(@_, 2039); + }, + nocheck => 1, + }, + len => 100309, + md5 => "0efc7833e5c0652823ca63eaccb9918f", +); + +1; diff --git a/regress/sys/kern/splice/direct.pl b/regress/sys/kern/splice/direct.pl new file mode 100755 index 00000000000..f7823132fd9 --- /dev/null +++ b/regress/sys/kern/splice/direct.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl +# $OpenBSD: direct.pl,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; +use Socket; +use Socket6; + +use Client; +use Server; +require 'funcs.pl'; + +our %args; +if (my $test = pop) { + do $test + or die "Do test file $test failed: ", $@ || $!; +} + +@ARGV == 0 or die "usage: direct.pl [test-args.pl]\n"; + +my $s = Server->new( + func => \&read_char, + %{$args{server}}, + listendomain => AF_INET, + listenaddr => "127.0.0.1", +); +my $c = Client->new( + func => \&write_char, + %{$args{client}}, + connectdomain => AF_INET, + connectaddr => "127.0.0.1", + connectport => $s->{listenport}, +); + +$s->run; +$c->run->up; +$s->up; + +$c->down; +$s->down; + +exit if $args{nocheck} || $args{client}{nocheck}; + +my $clen = $c->loggrep(qr/^LEN: /) unless $args{client}{nocheck}; +my $slen = $s->loggrep(qr/^LEN: /) unless $args{server}{nocheck}; +!$clen || !$slen || $clen eq $slen + or die "client: $clen", "server: $slen", "len mismatch"; +!defined($args{len}) || !$clen || $clen eq "LEN: $args{len}\n" + or die "client: $clen", "len $args{len} expected"; +!defined($args{len}) || !$slen || $slen eq "LEN: $args{len}\n" + or die "server: $slen", "len $args{len} expected"; + +my $cmd5 = $c->loggrep(qr/^MD5: /) unless $args{client}{nocheck}; +my $smd5 = $s->loggrep(qr/^MD5: /) unless $args{server}{nocheck}; +!$cmd5 || !$smd5 || $cmd5 eq $smd5 + or die "client: $cmd5", "server: $smd5", "md5 mismatch"; +!defined($args{md5}) || !$cmd5 || $cmd5 eq "MD5: $args{md5}\n" + or die "client: $cmd5", "md5 $args{md5} expected"; +!defined($args{md5}) || !$smd5 || $smd5 eq "MD5: $args{md5}\n" + or die "server: $smd5", "md5 $args{md5} expected"; + +my %name2proc = (client => $c, server => $s); +foreach my $name (qw(client server)) { + $args{$name}{errorin} //= $args{$name}{error}; + if (defined($args{$name}{errorin})) { + my $ein = $name2proc{$name}->loggrep(qr/^ERROR IN: /); + defined($ein) && $ein eq "ERROR IN: $args{$name}{errorin}\n" + or die "$name: $ein", + "error in $args{$name}{errorin} expected"; + } + if (defined($args{$name}{errorout})) { + my $eout = $name2proc{$name}->loggrep(qr/^ERROR OUT: /); + defined($eout) && $eout eq "ERROR OUT: $args{$name}{errorout}\n" + or die "$name: $eout", + "error out $args{$name}{errorout} expected"; + } +} diff --git a/regress/sys/kern/splice/echo.pl b/regress/sys/kern/splice/echo.pl new file mode 100755 index 00000000000..4cf12252fa2 --- /dev/null +++ b/regress/sys/kern/splice/echo.pl @@ -0,0 +1,123 @@ +#!/usr/bin/perl +# $OpenBSD: echo.pl,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; +use Socket; +use Socket6; + +use Child; +use Client; +use Server; +require 'funcs.pl'; + +sub usage { + die "usage: echo.pl copy|splice [test-args.pl]\n"; +} + +my $test; +our %args; +if (@ARGV and -f $ARGV[-1]) { + $test = pop; + do $test + or die "Do test file $test failed: ", $@ || $!; +} +@ARGV == 1 or usage(); + +exit 0 if $args{noecho}; + +my $r = Server->new( + forward => $ARGV[0], + func => \&relay, + logfile => "relay.log", + listendomain => AF_INET, + listenaddr => "127.0.0.1", + %{$args{relay}}, +); +my $s = Child->new( + logfile => "server.log", + oobinline => 1, + %{$args{server}}, + func => sub { + ($args{server}{func} || \&read_char)->(@_); + eval { shutout(@_) }; + }, +); +my $c = Client->new( + connectdomain => AF_INET, + connectaddr => "127.0.0.1", + connectport => $r->{listenport}, + oobinline => 1, + %{$args{client}}, + func => sub { + $s->run->up; + ($args{client}{func} || \&write_char)->(@_); + eval { shutout(@_) }; + $s->down; + }, +); + +$r->run; +$c->run->up; +$r->up; + +$c->down; +$r->down; +$s->{pid} = -1; # XXX hack + +exit if $args{nocheck}; + +my $clen = $c->loggrep(qr/^LEN: /) unless $args{client}{nocheck}; +my $rlen = $r->loggrep(qr/^LEN: /) unless $args{relay}{nocheck}; +my $slen = $s->loggrep(qr/^LEN: /) unless $args{server}{nocheck}; +!$clen || !$rlen || $clen eq $rlen + or die "client: $clen", "relay: $rlen", "len mismatch"; +!$rlen || !$slen || $rlen eq $slen + or die "relay: $rlen", "server: $slen", "len mismatch"; +!$clen || !$slen || $clen eq $slen + or die "client: $clen", "server: $slen", "len mismatch"; +!defined($args{len}) || !$clen || $clen eq "LEN: $args{len}\n" + or die "client: $clen", "len $args{len} expected"; +!defined($args{len}) || !$rlen || $rlen eq "LEN: $args{len}\n" + or die "relay: $rlen", "len $args{len} expected"; +!defined($args{len}) || !$slen || $slen eq "LEN: $args{len}\n" + or die "server: $slen", "len $args{len} expected"; + +my $cmd5 = $c->loggrep(qr/^MD5: /) unless $args{client}{nocheck}; +my $smd5 = $s->loggrep(qr/^MD5: /) unless $args{server}{nocheck}; +!$cmd5 || !$smd5 || $cmd5 eq $smd5 + or die "client: $cmd5", "server: $smd5", "md5 mismatch"; +!defined($args{md5}) || !$cmd5 || $cmd5 eq "MD5: $args{md5}\n" + or die "client: $cmd5", "md5 $args{md5} expected"; +!defined($args{md5}) || !$smd5 || $smd5 eq "MD5: $args{md5}\n" + or die "server: $smd5", "md5 $args{md5} expected"; + +$args{relay}{errorin} = 0 unless $args{relay}{nocheck}; +$args{relay}{errorout} = 0 unless $args{relay}{nocheck}; +$args{relay}{errorin} //= $args{relay}{error}; +if (defined($args{relay}{errorin})) { + my $ein = $r->loggrep(qr/^ERROR IN: /); + defined($ein) && $ein eq "ERROR IN: $args{relay}{errorin}\n" + or die "relay: $ein", + "error in $args{relay}{errorin} expected"; +} +if (defined($args{relay}{errorout})) { + my $eout = $r->loggrep(qr/^ERROR OUT: /); + defined($eout) && $eout eq "ERROR OUT: $args{relay}{errorout}\n" + or die "relay: $eout", + "error out $args{relay}{errorout} expected"; +} diff --git a/regress/sys/kern/splice/error-EBUSY.pl b/regress/sys/kern/splice/error-EBUSY.pl new file mode 100755 index 00000000000..e75431413ea --- /dev/null +++ b/regress/sys/kern/splice/error-EBUSY.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# test EBUSY for splicing from a spliced socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket connect failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket splice connect failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + or die "splice failed: $!"; + +my $so = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket other failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $so->fileno())) + and die "splice from spliced socket succeeded"; +$!{EBUSY} + or die "error not EBUSY: $!" diff --git a/regress/sys/kern/splice/error-ENOTCONN.pl b/regress/sys/kern/splice/error-ENOTCONN.pl new file mode 100755 index 00000000000..b08fb9cecb8 --- /dev/null +++ b/regress/sys/kern/splice/error-ENOTCONN.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +# test ENOTCONN for splicing from unconnected socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $s = IO::Socket::INET->new( + Proto => "tcp", +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice from unconnected socket succeeded"; +$!{ENOTCONN} + or die "error not ENOTCONN: $!" diff --git a/regress/sys/kern/splice/error-EOPNOTSUPP.pl b/regress/sys/kern/splice/error-EOPNOTSUPP.pl new file mode 100755 index 00000000000..916f92d96b9 --- /dev/null +++ b/regress/sys/kern/splice/error-EOPNOTSUPP.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +# test EOPNOTSUPP for splicing from listen socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + Listen => 1, +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice from listen socket succeeded"; +$!{EOPNOTSUPP} + or die "error not EOPNOTSUPP: $!" diff --git a/regress/sys/kern/splice/error-EPROTONOSUPPORT.pl b/regress/sys/kern/splice/error-EPROTONOSUPPORT.pl new file mode 100755 index 00000000000..612f81a64fe --- /dev/null +++ b/regress/sys/kern/splice/error-EPROTONOSUPPORT.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +# test EPROTONOSUPPORT for splicing udp sockets + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $s = IO::Socket::INET->new( + Proto => "udp", +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "udp", +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice udp sockets succeeded"; +$!{EPROTONOSUPPORT} + or die "error not EPROTONOSUPPORT: $!" diff --git a/regress/sys/kern/splice/error-max-EINVAL.pl b/regress/sys/kern/splice/error-max-EINVAL.pl new file mode 100755 index 00000000000..d26525f17c5 --- /dev/null +++ b/regress/sys/kern/splice/error-max-EINVAL.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +# test EINVAL for splicing with negative maximum + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('iiii', $ss->fileno(),-1,-1,-1)) + and die "splice to unconnected socket succeeded"; +$!{EINVAL} + or die "error not EINVAL: $!" diff --git a/regress/sys/kern/splice/error-splice-EBADF.pl b/regress/sys/kern/splice/error-splice-EBADF.pl new file mode 100755 index 00000000000..53b30ecfc84 --- /dev/null +++ b/regress/sys/kern/splice/error-splice-EBADF.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# test EBADF for splicing with non existing fileno + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', 23)) + and die "splice with non existing fileno succeeded"; +$!{EBADF} + or die "error not EBADF: $!" diff --git a/regress/sys/kern/splice/error-splice-EBUSY.pl b/regress/sys/kern/splice/error-splice-EBUSY.pl new file mode 100755 index 00000000000..dd0f169d6f1 --- /dev/null +++ b/regress/sys/kern/splice/error-splice-EBUSY.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# test EBUSY for splicing to a spliced socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket connect failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket splice connect failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + or die "splice failed: $!"; + +my $so = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket other failed: $!"; + +$so->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice to spliced socket succeeded"; +$!{EBUSY} + or die "error not EBUSY: $!" diff --git a/regress/sys/kern/splice/error-splice-EINVAL.pl b/regress/sys/kern/splice/error-splice-EINVAL.pl new file mode 100755 index 00000000000..c36b2f80e3e --- /dev/null +++ b/regress/sys/kern/splice/error-splice-EINVAL.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +# test EINVAL for splicing with short fileno size + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('s', $ss->fileno())) + and die "splice with short fileno size succeeded"; +$!{EINVAL} + or die "error not EINVAL: $!" diff --git a/regress/sys/kern/splice/error-splice-ENOTCONN.pl b/regress/sys/kern/splice/error-splice-ENOTCONN.pl new file mode 100755 index 00000000000..a20a8171ac8 --- /dev/null +++ b/regress/sys/kern/splice/error-splice-ENOTCONN.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +# test ENOTCONN for splicing to unconnected socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice to unconnected socket succeeded"; +$!{ENOTCONN} + or die "error not ENOTCONN: $!" diff --git a/regress/sys/kern/splice/error-splice-EOPNOTSUPP.pl b/regress/sys/kern/splice/error-splice-EOPNOTSUPP.pl new file mode 100755 index 00000000000..843da7b37fc --- /dev/null +++ b/regress/sys/kern/splice/error-splice-EOPNOTSUPP.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl +# test EOPNOTSUPP for splicing to listen socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "tcp", + Listen => 1, +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice to listen socket succeeded"; +$!{EOPNOTSUPP} + or die "error not EOPNOTSUPP: $!" diff --git a/regress/sys/kern/splice/error-splice-EPROTONOSUPPORT.pl b/regress/sys/kern/splice/error-splice-EPROTONOSUPPORT.pl new file mode 100755 index 00000000000..20fb388c9e3 --- /dev/null +++ b/regress/sys/kern/splice/error-splice-EPROTONOSUPPORT.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl +# test EPROTONOSUPPORT for splicing to udp socket + +use Errno; +use IO::Socket; +use constant SO_SPLICE => 0x1023; + +my $sl = IO::Socket::INET->new( + Proto => "tcp", + Listen => 5, + LocalAddr => "127.0.0.1", +) or die "socket listen failed: $!"; + +my $s = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $sl->sockhost(), + PeerPort => $sl->sockport(), +) or die "socket failed: $!"; + +my $ss = IO::Socket::INET->new( + Proto => "udp", +) or die "socket splice failed: $!"; + +$s->setsockopt(SOL_SOCKET, SO_SPLICE, pack('i', $ss->fileno())) + and die "splice to udp socket succeeded"; +$!{EPROTONOSUPPORT} + or die "error not EPROTONOSUPPORT: $!" diff --git a/regress/sys/kern/splice/funcs.pl b/regress/sys/kern/splice/funcs.pl new file mode 100644 index 00000000000..a5507b22c8d --- /dev/null +++ b/regress/sys/kern/splice/funcs.pl @@ -0,0 +1,367 @@ +# $OpenBSD: funcs.pl,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; +use feature 'switch'; +use Errno; +use Digest::MD5; +use IO::Socket qw(sockatmark); +use Socket; +use Time::HiRes qw(time alarm sleep); +use constant SO_SPLICE => 0x1023; + +######################################################################## +# Client funcs +######################################################################## + +sub write_char { + my $self = shift; + my $len = shift // $self->{len} // 251; + + my $ctx = Digest::MD5->new(); + my $char = '0'; + for (my $i = 1; $i < $len; $i++) { + $ctx->add($char); + print $char + or die ref($self), " print failed: $!"; + given ($char) { + when(/9/) { $char = 'A' } + when(/Z/) { $char = 'a' } + when(/z/) { $char = "\n" } + when(/\n/) { print STDERR "."; $char = '0' } + default { $char++ } + } + } + if ($len) { + $char = "\n"; + $ctx->add($char); + print $char + or die ref($self), " print failed: $!"; + print STDERR ".\n"; + } + + print STDERR "LEN: ", $len, "\n"; + print STDERR "MD5: ", $ctx->hexdigest, "\n"; +} + +sub write_oob { + my $self = shift; + my $len = shift // $self->{len} // 251; + + my $ctx = Digest::MD5->new(); + my $msg = ""; + my $char = '0'; + for (my $i = 1; $i < $len; $i++) { + $msg .= $char; + given ($char) { + when(/9/) { + $ctx->add("[$char]"); + defined(send(STDOUT, $msg, MSG_OOB)) + or die ref($self), " send OOB failed: $!"; + # If tcp urgent data is sent too fast, + # it may get overwritten and lost. + sleep .1; + $msg = ""; + $char = 'A'; + } + when(/Z/) { $ctx->add($char); $char = 'a' } + when(/z/) { $ctx->add($char); $char = "\n" } + when(/\n/) { + $ctx->add($char); + defined(send(STDOUT, $msg, 0)) + or die ref($self), " send failed: $!"; + print STDERR "."; + $msg = ""; + $char = '0'; + } + default { $ctx->add($char); $char++ } + } + } + if ($len) { + $char = "\n"; + $msg .= $char; + $ctx->add($char); + send(STDOUT, $msg, 0) + or die ref($self), " send failed: $!"; + print STDERR ".\n"; + } + + print STDERR "LEN: ", $len, "\n"; + print STDERR "MD5: ", $ctx->hexdigest, "\n"; +} + +######################################################################## +# Relay funcs +######################################################################## + +sub relay_copy { + my $self = shift; + my $max = shift // $self->{max}; + my $size = $self->{size} || 8093; + + my $len = 0; + while (1) { + my $rin = my $win = my $ein = ''; + vec($rin, fileno(STDIN), 1) = 1; + vec($ein, fileno(STDIN), 1) = 1 unless $self->{oobinline}; + select($rin, undef, $ein, undef) + or die ref($self), " select failed: $!"; + my $buf; + my $atmark = sockatmark(\*STDIN) + or die ref($self), " sockatmark failed: $!"; + if ($atmark == 1) { + if ($self->{oobinline}) { + defined(recv(STDIN, $buf, 1, 0)) + or die ref($self), " recv OOB failed: $!"; + $len += length($buf); + defined(send(STDOUT, $buf, MSG_OOB)) + or die ref($self), " send OOB failed: $!"; + } else { + defined(recv(STDIN, $buf, 1, MSG_OOB)) || + $!{EINVAL} + or die ref($self), " recv OOB failed: $!"; + print STDERR "OOB: $buf\n" if length($buf); + } + } + if ($self->{nonblocking}) { + vec($rin, fileno(STDIN), 1) = 1; + select($rin, undef, undef, undef) + or die ref($self), " select read failed: $!"; + } + my $read = sysread(STDIN, $buf, + $max && $max < $size ? $max : $size); + defined $read + or die ref($self), " sysread at $len failed: $!"; + if ($read == 0) { + print STDERR "\n"; + print STDERR "End\n"; + last; + } + print STDERR "."; + if ($max && $len + $read > $max) { + $read = $max - $len; + } + my $off = 0; + while ($off < $read) { + if ($self->{nonblocking}) { + vec($win, fileno(STDOUT), 1) = 1; + select(undef, $win, undef, undef) + or die ref($self), + " select write failed: $!"; + } + my $write = syswrite(STDOUT, $buf, $read - $off, $off); + defined $write + or die ref($self), " syswrite at $len failed: $!"; + defined $write or next; + $off += $write; + $len += $write; + } + if ($max && $len == $max) { + print STDERR "\n"; + print STDERR "Max\n"; + last; + } + } + + print STDERR "LEN: ", $len, "\n"; +} + +sub relay_splice { + my $self = shift; + my $max = shift // $self->{max}; + + my $len = 0; + my $splicelen; + my $shortsplice = 0; + do { + $shortsplice++ > 1 + and die ref($self), " more than one short splice"; + + my $splicemax = $max ? $max - $len : 0; # XXX should be quad + # XXX this works for i386 only + my $sosplice = pack('iii', fileno(STDOUT), $splicemax, 0); + setsockopt(STDIN, SOL_SOCKET, SO_SPLICE, $sosplice) + or die ref($self), " splice stdin to stdout failed: $!"; + + my $rin = ''; + vec($rin, fileno(STDIN), 1) = 1; + select($rin, undef, undef, undef) + or die ref($self), " select failed: $!"; + + my $error = getsockopt(STDIN, SOL_SOCKET, SO_ERROR) + or die ref($self), " get error from stdin failed: $!"; + $! = unpack('i', $error) + and die ref($self), " splice failed: $!"; + + $sosplice = getsockopt(STDIN, SOL_SOCKET, SO_SPLICE) + or die ref($self), " get splice len from stdin failed: $!"; + $splicelen = unpack('ii', $sosplice); # XXX should be quad + print STDERR "SPLICELEN: ", $splicelen, "\n"; + !$max || $splicelen <= $splicemax + or die ref($self), " splice len $splicelen ". + "greater than max $splicemax"; + $len += $splicelen; + } while ($splicelen and !$max || $max > $len); + + if ($max && $max == $len) { + print STDERR "Max\n"; + } elsif ($max && $max < $len) { + die ref($self), " max $max less than len $len"; + } elsif ($max && $max > $len && $splicelen) { + die ref($self), " max $max greater than len $len"; + } else { + defined(my $read = sysread(STDIN, my $buf, 2**16)) + or die ref($self), " sysread stdin failed: $!"; + $read > 0 + and die ref($self), " sysread stdin has data: $read"; + print STDERR "End\n"; + } + print STDERR "LEN: ", $len, "\n"; +} + +sub relay { + my $self = shift; + my $forward = $self->{forward}; + + given ($forward) { + when (/splice/) { relay_splice($self, @_) } + when (/copy/) { relay_copy($self, @_) } + default { die "Unknown forward name: $forward" } + } + + my $soerror; + $soerror = getsockopt(STDIN, SOL_SOCKET, SO_ERROR) + or die ref($self), " get error from stdin failed: $!"; + print STDERR "ERROR IN: ", unpack('i', $soerror), "\n"; + $soerror = getsockopt(STDOUT, SOL_SOCKET, SO_ERROR) + or die ref($self), " get error from stdout failed: $!"; + print STDERR "ERROR OUT: ", unpack('i', $soerror), "\n"; +} + +sub ioflip { + my $self = shift; + + open(my $fh, '<&', \*STDIN) + or die ref($self), " ioflip dup failed: $!"; + open(STDIN, '<&', \*STDOUT) + or die ref($self), " ioflip dup STDIN failed: $!"; + open(STDOUT, '>&', $fh) + or die ref($self), " ioflip dup STDOUT failed: $!"; + close($fh) + or die ref($self), " ioflip close failed: $!"; +} + +sub errignore { + $SIG{PIPE} = 'IGNORE'; + $SIG{__DIE__} = sub { + die @_ if $^S; + warn @_; + my $soerror; + $soerror = getsockopt(STDIN, SOL_SOCKET, SO_ERROR); + print STDERR "ERROR IN: ", unpack('i', $soerror), "\n"; + $soerror = getsockopt(STDOUT, SOL_SOCKET, SO_ERROR); + print STDERR "ERROR OUT: ", unpack('i', $soerror), "\n"; + IO::Handle::flush(\*STDERR); + POSIX::_exit(0); + }; +} + +sub shutin { + my $self = shift; + shutdown(\*STDIN, SHUT_RD) + or die ref($self), " shutdown read failed: $!"; +} + +sub shutout { + my $self = shift; + IO::Handle::flush(\*STDOUT) + or die ref($self), " flush stdout failed: $!"; + shutdown(\*STDOUT, SHUT_WR) + or die ref($self), " shutdown write failed: $!"; +} + +######################################################################## +# Server funcs +######################################################################## + +sub read_char { + my $self = shift; + + my $ctx = Digest::MD5->new(); + my $len = 0; + while (<STDIN>) { + $len += length($_); + $ctx->add($_); + print STDERR "."; + } + print STDERR "\n"; + + print STDERR "LEN: ", $len, "\n"; + print STDERR "MD5: ", $ctx->hexdigest, "\n"; +} + +sub read_oob { + my $self = shift; + my $size = $self->{size} || 4091; + + my $ctx = Digest::MD5->new(); + my $len = 0; + while (1) { + my $rin = my $ein = ''; + vec($rin, fileno(STDIN), 1) = 1; + vec($ein, fileno(STDIN), 1) = 1 unless $self->{oobinline}; + select($rin, undef, $ein, undef) + or die ref($self), " select failed: $!"; + my $buf; + my $atmark = sockatmark(\*STDIN) + or die ref($self), " sockatmark failed: $!"; + if ($atmark == 1) { + if ($self->{oobinline}) { + defined(recv(STDIN, $buf, 1, 0)) + or die ref($self), " recv OOB failed: $!"; + print STDERR "[$buf]"; + $ctx->add("[$buf]"); + $len += length($buf); + } else { + defined(recv(STDIN, $buf, 1, MSG_OOB)) || + $!{EINVAL} + or die ref($self), " recv OOB failed: $!"; + print STDERR "OOB: $buf\n" if length($buf); + } + } + defined(recv(STDIN, $buf, $size, 0)) + or die ref($self), " recv failed: $!"; + last unless length($buf); + print STDERR $buf; + $ctx->add($buf); + $len += length($buf); + print STDERR "."; + } + print STDERR "\n"; + + print STDERR "LEN: ", $len, "\n"; + print STDERR "MD5: ", $ctx->hexdigest, "\n"; +} + +sub solinger { + my $self = shift; + + setsockopt(STDIN, SOL_SOCKET, SO_LINGER, pack('ii', 1, 0)) + or die ref($self), " set linger failed: $!"; +} + +1; diff --git a/regress/sys/kern/splice/relay.pl b/regress/sys/kern/splice/relay.pl new file mode 100755 index 00000000000..d7740cd1e41 --- /dev/null +++ b/regress/sys/kern/splice/relay.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl +# $OpenBSD: relay.pl,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; +use Socket; +use Socket6; + +use Client; +use Relay; +use Server; +require 'funcs.pl'; + +sub usage { + die "usage: relay.pl copy|splice [test-args.pl]\n"; +} + +my $test; +our %args; +if (@ARGV and -f $ARGV[-1]) { + $test = pop; + do $test + or die "Do test file $test failed: ", $@ || $!; +} +@ARGV == 1 or usage(); + +my $s = Server->new( + func => \&read_char, + listendomain => AF_INET, + listenaddr => "127.0.0.1", + oobinline => 1, + %{$args{server}}, +); +my $r = Relay->new( + forward => $ARGV[0], + func => \&relay, + listendomain => AF_INET, + listenaddr => "127.0.0.1", + connectdomain => AF_INET, + connectaddr => "127.0.0.1", + connectport => $s->{listenport}, + %{$args{relay}}, +); +my $c = Client->new( + func => \&write_char, + connectdomain => AF_INET, + connectaddr => "127.0.0.1", + connectport => $r->{listenport}, + oobinline => 1, + %{$args{client}}, +); + +$s->run; +$r->run; +$c->run->up; +$r->up; +$s->up; + +$c->down; +$r->down; +$s->down; + +exit if $args{nocheck}; + +my $clen = $c->loggrep(qr/^LEN: /) unless $args{client}{nocheck}; +my $rlen = $r->loggrep(qr/^LEN: /) unless $args{relay}{nocheck}; +my $slen = $s->loggrep(qr/^LEN: /) unless $args{server}{nocheck}; +!$clen || !$rlen || $clen eq $rlen + or die "client: $clen", "relay: $rlen", "len mismatch"; +!$rlen || !$slen || $rlen eq $slen + or die "relay: $rlen", "server: $slen", "len mismatch"; +!$clen || !$slen || $clen eq $slen + or die "client: $clen", "server: $slen", "len mismatch"; +!defined($args{len}) || !$clen || $clen eq "LEN: $args{len}\n" + or die "client: $clen", "len $args{len} expected"; +!defined($args{len}) || !$rlen || $rlen eq "LEN: $args{len}\n" + or die "relay: $rlen", "len $args{len} expected"; +!defined($args{len}) || !$slen || $slen eq "LEN: $args{len}\n" + or die "server: $slen", "len $args{len} expected"; + +my $cmd5 = $c->loggrep(qr/^MD5: /) unless $args{client}{nocheck}; +my $smd5 = $s->loggrep(qr/^MD5: /) unless $args{server}{nocheck}; +!$cmd5 || !$smd5 || $cmd5 eq $smd5 + or die "client: $cmd5", "server: $smd5", "md5 mismatch"; +!defined($args{md5}) || !$cmd5 || $cmd5 eq "MD5: $args{md5}\n" + or die "client: $cmd5", "md5 $args{md5} expected"; +!defined($args{md5}) || !$smd5 || $smd5 eq "MD5: $args{md5}\n" + or die "server: $smd5", "md5 $args{md5} expected"; + +$args{relay}{errorin} = 0 unless $args{relay}{nocheck}; +$args{relay}{errorout} = 0 unless $args{relay}{nocheck}; +my %name2proc = (client => $c, relay => $r, server => $s); +foreach my $name (qw(client relay server)) { + $args{$name}{errorin} //= $args{$name}{error}; + if (defined($args{$name}{errorin})) { + my $ein = $name2proc{$name}->loggrep(qr/^ERROR IN: /); + defined($ein) && $ein eq "ERROR IN: $args{$name}{errorin}\n" + or die "$name: $ein", + "error in $args{$name}{errorin} expected"; + } + if (defined($args{$name}{errorout})) { + my $eout = $name2proc{$name}->loggrep(qr/^ERROR OUT: /); + defined($eout) && $eout eq "ERROR OUT: $args{$name}{errorout}\n" + or die "$name: $eout", + "error out $args{$name}{errorout} expected"; + } +} diff --git a/regress/sys/kern/splice/remote.pl b/regress/sys/kern/splice/remote.pl new file mode 100755 index 00000000000..4d08e54657f --- /dev/null +++ b/regress/sys/kern/splice/remote.pl @@ -0,0 +1,166 @@ +#!/usr/bin/perl +# $OpenBSD: remote.pl,v 1.1 2011/01/07 22:06:08 bluhm Exp $ + +# Copyright (c) 2010 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +use strict; +use warnings; +use File::Basename; +use File::Copy; +use Socket; +use Socket6; + +use Client; +use Relay; +use Server; +use Remote; +require 'funcs.pl'; + +sub usage { + die <<"EOF"; +usage: + remote.pl localport remoteaddr remoteport [test-args.pl] + Run test with local client and server. Remote relay + forwarding from remoteaddr remoteport to server localport + has to be started manually. + remote.pl copy|splice listenaddr connectaddr connectport [test-args.pl] + Only start remote relay. + remote.pl copy|splice localaddr remoteaddr remotessh [test-args.pl] + Run test with local client and server. Remote relay is + started automatically with ssh on remotessh. +EOF +} + +my $test; +our %args; +if (@ARGV and -f $ARGV[-1]) { + $test = pop; + do $test + or die "Do test file $test failed: ", $@ || $!; +} +my $mode = + @ARGV == 3 && $ARGV[0] =~ /^\d+$/ && $ARGV[2] =~ /^\d+$/ ? "manual" : + @ARGV == 4 && $ARGV[1] !~ /^\d+$/ && $ARGV[3] =~ /^\d+$/ ? "relay" : + @ARGV == 4 && $ARGV[1] !~ /^\d+$/ && $ARGV[3] !~ /^\d+$/ ? "auto" : + usage(); + +my $r; +if ($mode eq "relay") { + $r = Relay->new( + forward => $ARGV[0], + logfile => dirname($0)."/remote.log", + func => \&relay, + %{$args{relay}}, + listendomain => AF_INET, + listenaddr => $ARGV[1], + connectdomain => AF_INET, + connectaddr => $ARGV[2], + connectport => $ARGV[3], + ); + open(my $log, '<', $r->{logfile}) + or die "Remote log file open failed: $!"; + $SIG{__DIE__} = sub { + die @_ if $^S; + copy($log, \*STDERR); + warn @_; + exit 255; + }; + copy($log, \*STDERR); + $r->run; + copy($log, \*STDERR); + $r->up; + copy($log, \*STDERR); + $r->down; + copy($log, \*STDERR); + + exit; +} + +my $s = Server->new( + func => \&read_char, + oobinline => 1, + %{$args{server}}, + listendomain => AF_INET, + listenaddr => ($mode eq "auto" ? $ARGV[1] : undef), + listenport => ($mode eq "manual" ? $ARGV[0] : undef), +); +if ($mode eq "auto") { + $r = Remote->new( + forward => $ARGV[0], + logfile => "relay.log", + testfile => $test, + %{$args{relay}}, + remotessh => $ARGV[3], + listenaddr => $ARGV[2], + connectaddr => $ARGV[1], + connectport => $s->{listenport}, + ); + $r->run->up; +} +my $c = Client->new( + func => \&write_char, + oobinline => 1, + %{$args{client}}, + connectdomain => AF_INET, + connectaddr => ($mode eq "manual" ? $ARGV[1] : $r->{listenaddr}), + connectport => ($mode eq "manual" ? $ARGV[2] : $r->{listenport}), +); + +$s->run; +$c->run->up; +$s->up; + +$c->down; +$r->down if $r; +$s->down; + +exit if $args{nocheck}; + +my $clen = $c->loggrep(qr/^LEN: /) unless $args{client}{nocheck}; +my $slen = $s->loggrep(qr/^LEN: /) unless $args{server}{nocheck}; +!$clen || !$slen || $clen eq $slen + or die "client: $clen", "server: $slen", "len mismatch"; +!defined($args{len}) || !$clen || $clen eq "LEN: $args{len}\n" + or die "client: $clen", "len $args{len} expected"; +!defined($args{len}) || !$slen || $slen eq "LEN: $args{len}\n" + or die "server: $slen", "len $args{len} expected"; + +my $cmd5 = $c->loggrep(qr/^MD5: /) unless $args{client}{nocheck}; +my $smd5 = $s->loggrep(qr/^MD5: /) unless $args{server}{nocheck}; +!$cmd5 || !$smd5 || $cmd5 eq $smd5 + or die "client: $cmd5", "server: $smd5", "md5 mismatch"; +!defined($args{md5}) || !$cmd5 || $cmd5 eq "MD5: $args{md5}\n" + or die "client: $cmd5", "md5 $args{md5} expected"; +!defined($args{md5}) || !$smd5 || $smd5 eq "MD5: $args{md5}\n" + or die "server: $smd5", "md5 $args{md5} expected"; + +$args{relay}{errorin} = 0 unless $args{relay}{nocheck}; +$args{relay}{errorout} = 0 unless $args{relay}{nocheck}; +my %name2proc = (client => $c, relay => $r, server => $s); +foreach my $name (qw(client relay server)) { + $args{$name}{errorin} //= $args{$name}{error}; + if (defined($args{$name}{errorin})) { + my $ein = $name2proc{$name}->loggrep(qr/^ERROR IN: /); + defined($ein) && $ein eq "ERROR IN: $args{$name}{errorin}\n" + or die "$name: $ein", + "error in $args{$name}{errorin} expected"; + } + if (defined($args{$name}{errorout})) { + my $eout = $name2proc{$name}->loggrep(qr/^ERROR OUT: /); + defined($eout) && $eout eq "ERROR OUT: $args{$name}{errorout}\n" + or die "$name: $eout", + "error out $args{$name}{errorout} expected"; + } +} |