our
@EXPORT
=
qw(client server check_tls)
;
sub
check_tls {
my
(
%opts
) =
@_
;
return
exists
$opts
{npn} ?
exists
&Net::SSLeay::P_next_proto_negotiated
:
exists
$opts
{alpn} ?
exists
&Net::SSLeay::P_alpn_selected
: 1;
}
sub
server {
my
(
%h
) =
@_
;
my
$cb
=
delete
$h
{test_cb} or croak
"no servers test_cb"
;
my
$port
=
delete
$h
{port} or croak
"no port available"
;
my
$host
=
delete
$h
{host};
my
$tls_crt
=
delete
$h
{
"tls_crt"
};
my
$tls_key
=
delete
$h
{
"tls_key"
};
my
$w
= AnyEvent->condvar;
tcp_server
$host
,
$port
,
sub
{
my
(
$fh
,
$host
,
$port
) =
@_
;
my
$handle
;
my
$tls
;
if
( !
$h
{upgrade} && (
$h
{npn} ||
$h
{alpn} ) ) {
eval
{
$tls
= AnyEvent::TLS->new(
cert_file
=>
$tls_crt
,
key_file
=>
$tls_key
,
);
if
(
$h
{npn} ) {
Net::SSLeay::CTX_set_next_protos_advertised_cb(
$tls
->ctx,
[Protocol::HTTP2::ident_tls] );
}
if
(
$h
{alpn} ) {
Net::SSLeay::CTX_set_alpn_select_cb(
$tls
->ctx,
[Protocol::HTTP2::ident_tls] );
}
};
if
($@) {
croak
"Some problem with SSL CTX: $@"
. Net::SSLeay::print_errs();
}
}
$handle
= AnyEvent::Handle->new(
fh
=>
$fh
,
autocork
=> 1,
defined
$tls
? (
tls
=>
"accept"
,
tls_ctx
=>
$tls
)
: (),
on_error
=>
sub
{
$_
[0]->destroy;
print
STDERR
"connection error: $_[2]: $!\n"
;
},
on_eof
=>
sub
{
$handle
->destroy;
}
);
my
$server
= Protocol::HTTP2::Server->new(
%h
);
$cb
->(
$server
);
while
(
my
$frame
=
$server
->next_frame ) {
$handle
->push_write(
$frame
);
}
$handle
->on_read(
sub
{
my
$handle
=
shift
;
$server
->feed(
$handle
->{rbuf} );
$handle
->{rbuf} =
undef
;
while
(
my
$frame
=
$server
->next_frame ) {
$handle
->push_write(
$frame
);
}
$handle
->push_shutdown
if
$server
->
shutdown
;
}
);
};
my
$res
=
$w
->
recv
;
croak(
"error occurred\n"
)
unless
$res
;
}
sub
client {
my
(
%h
) =
@_
;
my
$port
=
delete
$h
{port} or croak
"no port available"
;
my
$tls
;
my
$host
=
delete
$h
{host};
if
(
delete
$h
{upgrade} ) {
$h
{upgrade} = 1;
}
elsif
(
$h
{npn} ||
$h
{alpn} ) {
eval
{
$tls
= AnyEvent::TLS->new();
if
(
delete
$h
{npn} ) {
Net::SSLeay::CTX_set_next_proto_select_cb(
$tls
->ctx,
[Protocol::HTTP2::ident_tls] );
}
if
(
delete
$h
{alpn} ) {
Net::SSLeay::CTX_set_alpn_protos(
$tls
->ctx,
[Protocol::HTTP2::ident_tls] );
}
};
if
($@) {
croak
"Some problem with SSL CTX: $@\n"
;
}
}
my
$cb
=
delete
$h
{test_cb} or croak
"no clients test_cb"
;
my
$client
= Protocol::HTTP2::Client->new(
%h
);
$cb
->(
$client
);
my
$w
= AnyEvent->condvar;
tcp_connect
$host
,
$port
,
sub
{
my
(
$fh
) =
@_
or
do
{
print
"connection failed: $!\n"
;
$w
->
send
(0);
return
;
};
my
$handle
;
$handle
= AnyEvent::Handle->new(
fh
=>
$fh
,
defined
$tls
? (
tls
=>
"connect"
,
tls_ctx
=>
$tls
,
)
: (),
autocork
=> 1,
on_error
=>
sub
{
$_
[0]->destroy;
print
STDERR
"connection error: $_[2]: $!\n"
;
$w
->
send
(0);
},
on_eof
=>
sub
{
$handle
->destroy;
$w
->
send
(1);
}
);
while
(
my
$frame
=
$client
->next_frame ) {
$handle
->push_write(
$frame
);
}
$handle
->on_read(
sub
{
my
$handle
=
shift
;
$client
->feed(
$handle
->{rbuf} );
$handle
->{rbuf} =
undef
;
while
(
my
$frame
=
$client
->next_frame ) {
$handle
->push_write(
$frame
);
}
$handle
->push_shutdown
if
$client
->
shutdown
;
}
);
};
my
$res
=
$w
->
recv
;
croak(
"error occurred\n"
)
unless
$res
;
}
1;