program project1;
{$mode objfpc}{$H+}
{$PACKRECORDS C}
{$L ./libs/libssl.so}
{$L ./libs/libcrypto.so}
//{$L ./libs/libquiche_dbg.so}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes,
Crt, SysUtils, CTypes, BaseUnix, Sockets;
type
CSsize_t = NativeInt;
PQuiche_config = ^TQuiche_config;
TQuiche_config = record
end;
PQuiche_conn = ^TQuiche_conn;
TQuiche_conn = record
end;
PSSL_METHOD = ^TSSL_METHOD;
TSSL_METHOD = record
end;
PSSL_CTX = ^TSSL_CTX;
TSSL_CTX = record
end;
PSSL = ^TSSL;
TSSL = record
end;
PQuiche_Recv_Info = ^TQuiche_Recv_Info;
TQuiche_Recv_Info = record
from : Psockaddr;
from_len : socklen_t;
&to : Psockaddr;
to_len : socklen_t;
end;
PQuiche_stats = ^TQuiche_stats;
Tquiche_stats = record
recv : size_t;
sent : size_t;
lost : size_t;
retrans : size_t;
sent_bytes : uint64;
recv_bytes : uint64;
acked_bytes : uint64;
lost_bytes : uint64;
stream_retrans_bytes : uint64;
paths_count : size_t;
reset_stream_count_local : uint64;
stopped_stream_count_local : uint64;
reset_stream_count_remote : uint64;
stopped_stream_count_remote : uint64;
end;
var
i: integer;
ch: Char;
PConfig: Pquiche_config;
Pctx: PSSL_CTX;
SSL: PSSL;
method: PSSL_METHOD;
isServer: boolean = true;
scid, odcid: array[0..15] of Byte;
Pconn: PQuiche_conn;
Stats: TQuiche_stats;
PStats: PQuiche_stats;
localAddr, peerAddr: TSockAddr;
trace_id: PByte;
trace_id_len: Csize_t;
buf: PByte;
BUF_SIZE: size_t = 8192 * 4;
recv_info: TQuiche_recv_info;
Precv_info: PQuiche_recv_info;
bytes_received: CSsize_t;
const
QUICHE_LIB = 'libquiche.so';
BORINGSSL_LIB = 'libssl.so';
CRYPTO_LIB = 'libcrypto.so';
QUICHE_PROTOCOL_VERSION = 1;
TLS1_3_VERSION = $0304; //0x0304
SSL_FILETYPE_PEM = 1;
SSL_OP_NO_RENEGOTIATION = 0;
{---------- BORINGSSL ----------}
function OpenSSL_version_num: cint; cdecl; external CRYPTO_LIB;
function TLS_method: PSSL_METHOD; cdecl; external BORINGSSL_LIB;
function SSL_CTX_new(const method: PSSL_METHOD): PSSL_CTX; cdecl; external BORINGSSL_LIB;
procedure SSL_CTX_set_min_proto_version(ctx: PSSL_CTX; version: cint); cdecl; external BORINGSSL_LIB;
procedure SSL_CTX_set_max_proto_version(ctx: PSSL_CTX; version: cint); cdecl; external BORINGSSL_LIB;
function SSL_CTX_use_certificate_file(ctx: PSSL_CTX; const filename: PChar; type_: cint): cint; cdecl; external BORINGSSL_LIB;
function SSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const filename: PChar; type_: cint): cint; cdecl; external BORINGSSL_LIB;
function SSL_CTX_check_private_key(ctx: PSSL_CTX): cint; cdecl; external BORINGSSL_LIB;
function SSL_CTX_set_options(ctx: PSSL_CTX; options: UInt32 ): UInt32; cdecl; external BORINGSSL_LIB;
function SSL_new(ctx: PSSL_CTX): PSSL; cdecl; external BORINGSSL_LIB;
{---------- QUICHE ----------}
function quiche_version: PChar; cdecl; external QUICHE_LIB;
function quiche_config_new(version: UInt32): PQuiche_config; cdecl; external QUICHE_LIB;
function quiche_config_load_cert_chain_from_pem_file(var config: TQuiche_config; path: Pansichar) : longint; cdecl; external QUICHE_LIB;
function quiche_config_load_priv_key_from_pem_file(var config: TQuiche_config; path: Pansichar): longint;cdecl;external QUICHE_LIB;
function quiche_conn_new_with_tls(const scid: PByte; scid_len: csize_t;
const odcid: PByte; odcid_len: csize_t;
const local: PSockAddr; local_len: socklen_t;
const peer: PSockAddr; peer_len: socklen_t;
const config: PQuiche_config; ssl: PSSL;
is_server: Boolean): PQuiche_conn;
cdecl; external QUICHE_LIB;
function quiche_conn_set_session(conn: PQuiche_Conn; buf:PByte; buf_len:csize_t) : cint32; cdecl; external QUICHE_LIB;
function quiche_conn_is_established(var conn: PQuiche_conn): cBool; cdecl; external QUICHE_LIB;
function quiche_conn_is_closed(var conn:PQuiche_conn): cbool; cdecl; external QUICHE_LIB;
procedure quiche_conn_trace_id(const conn: PQuiche_Conn; var out: PByte; var out_len: Csize_t); cdecl; external QUICHE_LIB;
procedure quiche_conn_source_id(const conn: PQuiche_Conn; var out: PByte; var out_len: Csize_t); cdecl; external QUICHE_LIB;
procedure quiche_conn_stats(var conn:PQuiche_conn; var &out:PQuiche_stats); cdecl; external QUICHE_LIB;
//function quiche_conn_recv(var conn:PQuiche_conn; buf:PByte; buf_len:csize_t; info:PQuiche_recv_info):cssize_t; cdecl; external QUICHE_LIB;
{H2Pas}//function quiche_conn_recv(var conn:quiche_conn; var buf:Cuint8; buf_len:Csize_t; var info:quiche_recv_info):Cssize_t;cdecl;external QUICHE_LIB name 'quiche_conn_recv';
//function quiche_conn_recv(var conn: PQuiche_Conn; buf: PByte; buf_len: CSize_t;
// var info: PQuiche_Recv_Info): CSsize_t; cdecl; external QUICHE_LIB;
{TRon} //function quiche_conn_recv(conn: pquiche_conn; buf: pcuint8; buf_len: size_t; const info: pquiche_recv_info): ssize_t; cdecl; external QUICHE_LIB;
{Fred}// function quiche_conn_recv(conn: PQuiche_Conn; buf: PByte; buf_len: CSize_t;
// var info: TQuiche_Recv_Info): CSsize_t; cdecl; external QUICHE_LIB;
{Fred2} //function quiche_conn_recv(var conn: PQuiche_Conn; var buf: PByte; var buf_len: CSize_t;
// var info: PQuiche_Recv_Info): CSsize_t; cdecl; external QUICHE_LIB;
function quiche_conn_recv(conn: PQuiche_Conn; const buf: PByte; buf_len: CSize_t;
const info: PQuiche_Recv_Info): CSsize_t; cdecl; external QUICHE_LIB;
begin
writeln('Quiche version: ', quiche_version); //returns: 0.22.0
writeln('BoringSSL version: ', Format('%d.%d.%d.%d',
[(OpenSSL_version_num shr 28) and $F,
(OpenSSL_version_num shr 20) and $F,
(OpenSSL_version_num shr 12) and $F,
(OpenSSL_version_num shr 4) and $F])); //
Pconfig := quiche_config_new(QUICHE_PROTOCOL_VERSION);
if Pconfig = nil then writeln('Failed to create QUIC configuration')
else writeln('QUIC configuration CREATED');
if quiche_config_load_cert_chain_from_pem_file(PConfig^, './keys/server.cert') = 0
then writeln('Cert OK') else writeln('Cert ERROR');
if quiche_config_load_priv_key_from_pem_file(PConfig^, './keys/server.key') = 0
then writeln('Priv_key OK') else writeln('Priv_key ERROR');
method := TLS_method;
Pctx := SSL_CTX_new(method);
if Pctx = nil then Writeln('Failed to create SSL_CTX') else Writeln('SSL_CTX CREATED!');
SSL_CTX_set_min_proto_version(Pctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(Pctx, TLS1_3_VERSION);
if SSL_CTX_use_certificate_file(Pctx, './keys/server.cert', SSL_FILETYPE_PEM) <= 0
then Writeln('SSL_CTX_use_certificate_file ERROR!')
else writeln('SSL_CTX_use_certificate_file OK!');
if SSL_CTX_use_PrivateKey_file(Pctx, './keys/server.key', SSL_FILETYPE_PEM) <= 0
then Writeln('SSL_CTX_use_PrivateKey_file ERROR!')
else Writeln('SSL_CTX_use_PrivateKey_file OK!');
if SSL_CTX_check_private_key(Pctx) <= 0 then Writeln('Private key DOES NOT match certificate')
else Writeln('Private key MATCHES certificate');
SSL_CTX_set_options(Pctx, SSL_OP_NO_RENEGOTIATION);
SSL := SSL_new(Pctx);
if SSL = nil then writeln('SSL_new ERROR')
else writeln('SSL_new OK ');
Randomize;
for i := 0 to High(scid) do scid[i] := Random(256);
for i := 0 to High(odcid) do odcid[i] := Random(256);
FillChar(localAddr, SizeOf(localAddr), 0);
localAddr.sin_family := AF_INET;
localAddr.sin_port := htons(12345);
localAddr.sin_addr := StrToNetAddr('192.168.1.4');
FillChar(peerAddr, SizeOf(peerAddr), 0);
peerAddr.sin_family := AF_INET;
peerAddr.sin_port := htons(0);
peerAddr.sin_addr.s_addr := INADDR_ANY;
Pconn := quiche_conn_new_with_tls(@scid[0], Length(scid),
@odcid[0], Length(odcid),
@localAddr, SizeOf(localAddr),
@peerAddr, SizeOf(peerAddr),
Pconfig, SSL, isServer);
Writeln('--------------------------------------------------');
if Pconn = nil then WriteLn('Failed to create QUIC connection')
else WriteLn('QUIC connection created successfully!');
if quiche_conn_is_established(Pconn)
then WriteLn('QUIC connection IS established')
else WriteLn('QUIC connection ISN''T established');
if quiche_conn_is_closed(Pconn)
then Writeln('Conn CLOSED')
else Writeln('Conn NOT CLOSED');
quiche_conn_source_id(PConn, trace_id, trace_id_len);
if (trace_id <> nil) and (trace_id_len > 0) then
begin
Writeln('Trace ID Length: ', trace_id_len);
Write('Trace ID: ');
for i := 0 to trace_id_len - 1 do Write(trace_id[i], ' ');
Writeln;
end else writeln(' trace_id = nil');
writeln('SizeOf(recv_info)=',SizeOf(recv_info));
quiche_conn_stats(Pconn, PStats);
GetMem(buf, BUF_SIZE);
// FillChar(recv_info, SizeOf(recv_info), 0);
writeln(' avant quiche_conn_set_session');
// Writeln(quiche_conn_set_session(PConn, @buf, BUF_SIZE));
FillChar(localAddr, SizeOf(localAddr), 0);
localAddr.sin_family := AF_INET;
localAddr.sin_port := htons(12345);
localAddr.sin_addr := StrToNetAddr('192.168.1.4');
FillChar(peerAddr, SizeOf(peerAddr), 0);
peerAddr.sin_family := AF_INET;
peerAddr.sin_port := htons(0);
peerAddr.sin_addr.s_addr := INADDR_ANY;
recv_info.from := @localAddr;;
recv_info.from_len := SizeOf(localAddr);
recv_info.&to := @peerAddr;;
recv_info.to_len := SizeOf(peerAddr);
Precv_info := @recv_info;
Writeln;
repeat
Writeln('bytes_received...');
{TRon} //bytes_received := quiche_conn_recv(PConn, buf, BUF_SIZE, Precv_info);
// {Fred} bytes_received := quiche_conn_recv(PConn, buf, BUF_SIZE, recv_info);
{Fred2}bytes_received := quiche_conn_recv(PConn, buf, BUF_SIZE, Precv_info);
Writeln('bytes_received = ' + inttostr(bytes_received));
Sleep(10);
if KeyPressed then ch := ReadKey;
until Ch = #13;
//TODO: cleaning
end.