xref: /openbsd/regress/sys/kern/sosplice/loop/loop.pl (revision f6246b7f)
1*f6246b7fSbluhm#!/usr/bin/perl
2*f6246b7fSbluhm#	$OpenBSD: loop.pl,v 1.1 2021/01/02 01:27:45 bluhm Exp $
3*f6246b7fSbluhm
4*f6246b7fSbluhm# Copyright (c) 2021 Alexander Bluhm <bluhm@openbsd.org>
5*f6246b7fSbluhm#
6*f6246b7fSbluhm# Permission to use, copy, modify, and distribute this software for any
7*f6246b7fSbluhm# purpose with or without fee is hereby granted, provided that the above
8*f6246b7fSbluhm# copyright notice and this permission notice appear in all copies.
9*f6246b7fSbluhm#
10*f6246b7fSbluhm# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*f6246b7fSbluhm# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*f6246b7fSbluhm# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*f6246b7fSbluhm# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*f6246b7fSbluhm# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*f6246b7fSbluhm# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*f6246b7fSbluhm# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*f6246b7fSbluhm
18*f6246b7fSbluhmuse strict;
19*f6246b7fSbluhmuse warnings;
20*f6246b7fSbluhmuse BSD::Socket::Splice qw(setsplice geterror);
21*f6246b7fSbluhmuse Errno;
22*f6246b7fSbluhmuse Getopt::Std;
23*f6246b7fSbluhmuse IO::Socket::IP;
24*f6246b7fSbluhmuse Socket qw(getnameinfo AI_PASSIVE NI_NUMERICHOST NI_NUMERICSERV);
25*f6246b7fSbluhm
26*f6246b7fSbluhm# from /usr/include/sys/mbuf.h
27*f6246b7fSbluhmuse constant M_MAXLOOP => 128;
28*f6246b7fSbluhm
29*f6246b7fSbluhmmy %opts;
30*f6246b7fSbluhmgetopts('46p:v', \%opts) or do {
31*f6246b7fSbluhm    print STDERR <<"EOF";
32*f6246b7fSbluhmusage: $0 [-46v] [-p proto]
33*f6246b7fSbluhm    -4		use IPv4
34*f6246b7fSbluhm    -6		use IPv6
35*f6246b7fSbluhm    -p proto	protocol, tcp or udp, default tcp
36*f6246b7fSbluhm    -v		verbose
37*f6246b7fSbluhmEOF
38*f6246b7fSbluhm    exit(2);
39*f6246b7fSbluhm};
40*f6246b7fSbluhm
41*f6246b7fSbluhm$opts{4} && $opts{6}
42*f6246b7fSbluhm    and die "Cannot use -4 and -6 together";
43*f6246b7fSbluhmmy $localhost = $opts{4} ? "127.0.0.1" : $opts{6} ? "::1" : "localhost";
44*f6246b7fSbluhmmy $proto = $opts{p} || "tcp";
45*f6246b7fSbluhmmy $type = $proto eq "tcp" ? SOCK_STREAM : SOCK_DGRAM;
46*f6246b7fSbluhmmy $verbose = $opts{v};
47*f6246b7fSbluhm
48*f6246b7fSbluhmmy $timeout = 10;
49*f6246b7fSbluhm$SIG{ALRM} = sub { die "Timeout triggered after $timeout seconds" };
50*f6246b7fSbluhmalarm($timeout);
51*f6246b7fSbluhm
52*f6246b7fSbluhmmy $ls = IO::Socket::IP->new(
53*f6246b7fSbluhm    GetAddrInfoFlags	=> AI_PASSIVE,
54*f6246b7fSbluhm    Listen		=> ($type == SOCK_STREAM) ? 1 : undef,
55*f6246b7fSbluhm    LocalHost		=> $localhost,
56*f6246b7fSbluhm    Proto		=> $proto,
57*f6246b7fSbluhm    Type		=> $type,
58*f6246b7fSbluhm) or die "Listen socket failed: $@";
59*f6246b7fSbluhmmy ($host, $service) = $ls->sockhost_service(1);
60*f6246b7fSbluhmprint "listen on host '$host' service '$service'\n" if $verbose;
61*f6246b7fSbluhm
62*f6246b7fSbluhmmy $cs = IO::Socket::IP->new(
63*f6246b7fSbluhm    PeerHost		=> $host,
64*f6246b7fSbluhm    PeerService		=> $service,
65*f6246b7fSbluhm    Proto		=> $proto,
66*f6246b7fSbluhm    Type		=> $type,
67*f6246b7fSbluhm) or die "Connect socket failed: $@";
68*f6246b7fSbluhmprint "connect to host '$host' service '$service'\n" if $verbose;
69*f6246b7fSbluhm
70*f6246b7fSbluhmmy ($as, $peer);
71*f6246b7fSbluhmif ($type == SOCK_STREAM) {
72*f6246b7fSbluhm    ($as, $peer) = $ls->accept()
73*f6246b7fSbluhm	or die "Accept socket failed: $!";
74*f6246b7fSbluhm} else {
75*f6246b7fSbluhm    $as = $ls;
76*f6246b7fSbluhm    $peer = $cs->sockname();
77*f6246b7fSbluhm    $as->connect($peer)
78*f6246b7fSbluhm	or die "Connect passive socket failed: $!";
79*f6246b7fSbluhm}
80*f6246b7fSbluhmif ($verbose) {
81*f6246b7fSbluhm    my ($err, $peerhost, $peerservice) = getnameinfo($peer,
82*f6246b7fSbluhm	NI_NUMERICHOST | NI_NUMERICSERV);
83*f6246b7fSbluhm    $err and die "Getnameinfo failed: $err";
84*f6246b7fSbluhm    print "accept from host '$peerhost' service '$peerservice'\n";
85*f6246b7fSbluhm}
86*f6246b7fSbluhm
87*f6246b7fSbluhmsetsplice($as, $cs)
88*f6246b7fSbluhm    or die "Splice accept to connect socket failed: $!";
89*f6246b7fSbluhmsetsplice($cs, $as)
90*f6246b7fSbluhm    or die "Splice connect to accept socket failed: $!";
91*f6246b7fSbluhm
92*f6246b7fSbluhmsystem("\${SUDO} fstat -n -p $$") if $verbose;
93*f6246b7fSbluhmmy ($msg, $buf) = "foo";
94*f6246b7fSbluhm$cs->send($msg, 0)
95*f6246b7fSbluhm    or die "Send to connect socket failed: $!";
96*f6246b7fSbluhmdefined $as->recv($buf, 100, 0)
97*f6246b7fSbluhm    or die "Recv from accept socket failed: $!";
98*f6246b7fSbluhm$msg eq $buf
99*f6246b7fSbluhm    or die "Value modified in splice chain";
100*f6246b7fSbluhm$! = geterror($as)
101*f6246b7fSbluhm    or die "No error at accept socket";
102*f6246b7fSbluhm$!{ELOOP}
103*f6246b7fSbluhm    or die "Errno at accept socket is not ELOOP: $!";
104