# Copyright (c) 2023 Yuki Kimoto
# MIT License
class Net::SSLeay {
version "0.044";
use Net::SSLeay::Constant as SSL;
use Net::SSLeay::SSL_CTX;
use Net::SSLeay::X509;
use Net::SSLeay::X509_NAME;
use Net::SSLeay::Error;
use Net::SSLeay::Error::SSL_ERROR_WANT_READ;
use Net::SSLeay::Error::SSL_ERROR_WANT_WRITE;
use Net::SSLeay::Callback::Msg;
# Class Variables
our $INSTANCES_H : Hash of Net::SSLeay;
our $MUTEX : Sync::Mutex;
INIT {
$INSTANCES_H = Hash->new;
$MUTEX = Sync::Mutex->new;
}
# Fields
has operation_error : ro int;
has msg_callback : ro Net::SSLeay::Callback::Msg;
# Class Methods
native static method new : Net::SSLeay ($ssl_ctx : Net::SSLeay::SSL_CTX);
private static method new_with_pointer : Net::SSLeay ($pointer : Address, $options : object[] = undef) {
my $self = new Net::SSLeay;
Fn->set_pointer($self, $pointer);
$self->init($options);
return $self;
}
native static method alert_desc_string_long : string ($value : int);
native static method load_client_CA_file : Net::SSLeay::X509_NAME[] ($file : string);
native static method select_next_proto : int ($out_ref : string[], $outlen_ref : byte*, $server : string, $server_len : int, $client : string, $client_len : int);
# Instance Methods
protected method init : void ($options : object[] = undef) {
$self->_init_native;
}
native private method _init_native : void ($objects : object[] = undef);
native method version : int ();
native method get_version : string ();
native method get_mode : long ();
native method set_mode : long ($mode : long);
native method clear_mode : long ($mode : long);
native method set_tlsext_host_name : int ($name : string);
native method get_servername : string ($type : int);
native method get_SSL_CTX : Net::SSLeay::SSL_CTX ();
native method set_SSL_CTX : void ($ssl_ctx : Net::SSLeay::SSL_CTX);
native method set_fd : int ($fd : int);
native method connect : int ();
native method accept : int ();
native method read : int ($buf : mutable string, $num : int = -1, $offset : int = 0);
native method write : int ($buf : string, $num : int = -1, $offset : int = 0);
native method shutdown : int ();
native method get_shutdown : int ();
native method get_cipher : string ();
native method get_certificate : Net::SSLeay::X509 ();
native method get_peer_certificate : Net::SSLeay::X509 ();
native method get_peer_cert_chain : Net::SSLeay::X509[] ();
native method get0_alpn_selected : void ($data_ref : string[], $len_ref : int*);
method get0_alpn_selected_return_string : string () {
my $data_ref = new string[1];
my $len = -1;
$self->get0_alpn_selected($data_ref, \$len);
my $protocol = (string)undef;
if ($data_ref->[0]) {
$protocol = $data_ref->[0];
Fn->shorten((mutable string)$protocol, $len);
}
return $protocol;
}
method dump_peer_certificate : string () {
my $cert = $self->get_peer_certificate;
unless ($cert) {
die "The return value of get_peer_certificate method must be defined.";
}
my $subject_name = $cert->get_subject_name->oneline;
my $issuer_name = $cert->get_issuer_name->oneline;
my $dump = "Subject Name: $subject_name\nIssuer Name: $issuer_name\n";
return $dump;
}
native method set_msg_callback : void ($cb : Net::SSLeay::Callback::Msg);
native method DESTROY : void ();
private static method GET_INSTANCE : Net::SSLeay ($address : string) {
Fn->defer(method : void () {
$MUTEX->reader_unlock;
});
$MUTEX->reader_lock;
my $self = (Net::SSLeay)$INSTANCES_H->get($address);
return $self;
}
private static method INIT_INSTANCE : void ($address : string, $self : Net::SSLeay) {
Fn->defer(method : void () {
$MUTEX->unlock;
});
$MUTEX->lock;
unless ($INSTANCES_H->exists($address)) {
$INSTANCES_H->set($address, $self);
$INSTANCES_H->weaken($address);
}
}
private static method DELETE_INSTANCE : Net::SSLeay ($address : string) {
Fn->defer(method : void () {
$MUTEX->unlock;
});
$MUTEX->lock;
my $deleted = (Net::SSLeay)$INSTANCES_H->delete($address);
return $deleted;
}
}