Skip to content

Commit ee21d15

Browse files
committed
create a new structure BIOStream{T<:IO} to handle BIO using IO
1 parent bfd3373 commit ee21d15

File tree

3 files changed

+152
-107
lines changed

3 files changed

+152
-107
lines changed

src/OpenSSL.jl

Lines changed: 149 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,18 @@ const BIO_TYPE_SOURCE_SINK = 0x0400
210210
#
211211
BIO_TYPE_START = 128)
212212

213+
"""
214+
These are used in the following macros and are passed to BIO_ctrl().
215+
"""
216+
#@enum(BIOFlags::Cint,
217+
#
218+
#);
219+
const BIO_FLAGS_SHOULD_RETRY = 0x08
220+
const BIO_FLAGS_READ = 0x01
221+
const BIO_FLAGS_WRITE = 0x02
222+
const BIO_FLAGS_IO_SPECIAL = 0x04
223+
224+
213225
# Some values are reserved until OpenSSL 3.0.0 because they were previously
214226
# included in SSL_OP_ALL in a 1.1.x release.
215227
@bitflag SSLOptions::Culong begin
@@ -1544,7 +1556,7 @@ mutable struct BIO
15441556
Creates a BIO object using IO stream method.
15451557
The BIO object is not registered with the finalizer.
15461558
"""
1547-
function BIO(data=nothing; finalize::Bool=true)
1559+
function BIO(io::T; finalize::Bool=true) where {T<:IO}
15481560
bio = ccall(
15491561
(:BIO_new, libcrypto),
15501562
Ptr{Cvoid},
@@ -1557,7 +1569,7 @@ mutable struct BIO
15571569
bio = new(bio)
15581570
finalize && finalizer(free, bio)
15591571

1560-
# note that `data` must be held as a reference somewhere else
1572+
# note that `io` must be held as a reference somewhere else
15611573
# since it is not referenced by the BIO directly
15621574
# e.g. in SSLStream, we keep the `io` reference that is passed to
15631575
# the read/write BIOs
@@ -1566,7 +1578,7 @@ mutable struct BIO
15661578
Cvoid,
15671579
(BIO, Ptr{Cvoid}),
15681580
bio,
1569-
data === nothing ? C_NULL : pointer_from_objref(data))
1581+
pointer_from_objref(io))
15701582

15711583
# Set BIO as non-blocking
15721584
ccall(
@@ -1577,6 +1589,7 @@ mutable struct BIO
15771589
102,
15781590
1,
15791591
C_NULL)
1592+
15801593
# Mark BIO as initalized.
15811594
ccall(
15821595
(:BIO_set_init, libcrypto),
@@ -1674,7 +1687,6 @@ end
16741687
"""
16751688
BIO write.
16761689
"""
1677-
## throw error here
16781690
function Base.unsafe_write(bio::BIO, out_buffer::Ptr{UInt8}, out_length::Int)
16791691
result = ccall(
16801692
(:BIO_write, libcrypto),
@@ -1690,6 +1702,139 @@ end
16901702

16911703
Base.write(bio::BIO, out_data) = return unsafe_write(bio, pointer(out_data), length(out_data))
16921704

1705+
"""
1706+
BIOStream.
1707+
BIO with IO.
1708+
"""
1709+
mutable struct BIOStream{T<:IO}
1710+
bio::Ptr{Cvoid}
1711+
end
1712+
1713+
function bio_stream_get_io(bio_stream::BIOStream{T})::T where {T<:IO}
1714+
data = ccall(
1715+
(:BIO_get_data, libcrypto),
1716+
Ptr{Cvoid},
1717+
(BIOStream{T},),
1718+
bio_stream)
1719+
return unsafe_pointer_to_objref(data)::T
1720+
end
1721+
1722+
"""
1723+
BIOStream callbacks.
1724+
"""
1725+
1726+
"""
1727+
Called to initialize new BIO Stream object.
1728+
"""
1729+
on_bio_stream_create(::BIOStream{T}) where {T<:IO} = Cint(1)
1730+
on_bio_stream_destroy(::BIOStream{T}) where {T<:IO} = Cint(0)
1731+
1732+
#function bio_get_data(bio::BIO)
1733+
# data = ccall(
1734+
# (:BIO_get_data, libcrypto),
1735+
# Ptr{Cvoid},
1736+
# (BIO,),
1737+
# bio)
1738+
# return unsafe_pointer_to_objref(data)
1739+
#end
1740+
1741+
function bio_set_flags(bio_stream::BIOStream{T}, flags) where {T<:IO}
1742+
return ccall(
1743+
(:BIO_set_flags, libcrypto),
1744+
Cint,
1745+
(BIOStream{T}, Cint),
1746+
bio_stream, flags)
1747+
end
1748+
1749+
bio_set_read_retry(bio_stream::BIOStream{T}) where {T<:IO} = bio_set_flags(bio_stream, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)
1750+
bio_clear_flags(bio_stream::BIOStream{T}) where {T<:IO} = bio_set_flags(bio_stream, 0x00)
1751+
1752+
"""
1753+
static int fd_read(BIO *b, char *out, int outl)
1754+
{
1755+
int ret = 0;
1756+
1757+
if (out != NULL) {
1758+
clear_sys_error();
1759+
ret = UP_read(b->num, out, outl);
1760+
BIO_clear_retry_flags(b);
1761+
if (ret <= 0) {
1762+
if (BIO_fd_should_retry(ret))
1763+
BIO_set_retry_read(b);
1764+
else if (ret == 0)
1765+
b->flags |= BIO_FLAGS_IN_EOF;
1766+
}
1767+
}
1768+
return ret;
1769+
}
1770+
"""
1771+
1772+
function on_bio_stream_read(bio_stream::BIOStream{T}, out::Ptr{Cchar}, outlen::Cint) where {T<:IO}
1773+
try
1774+
bio_clear_flags(bio_stream)
1775+
io::T = bio_stream_get_io(bio_stream)
1776+
n = bytesavailable(io)
1777+
if n == 0
1778+
eof(io)
1779+
n = bytesavailable(io)
1780+
end
1781+
1782+
if n == 0
1783+
bio_set_read_retry(bio_stream)
1784+
return Cint(0)
1785+
end
1786+
unsafe_read(io, out, min(UInt(n), outlen))
1787+
return Cint(min(n, outlen))
1788+
catch e
1789+
# we don't want to throw a Julia exception from a C callback
1790+
return Cint(-1)
1791+
end
1792+
end
1793+
1794+
function on_bio_stream_write(bio_stream::BIOStream{T}, in::Ptr{Cchar}, inlen::Cint)::Cint where {T<:IO}
1795+
try
1796+
io::T = bio_stream_get_io(bio_stream)
1797+
written = unsafe_write(io, in, inlen)
1798+
return Cint(written)
1799+
catch e
1800+
# we don't want to throw a Julia exception from a C callback
1801+
return Cint(-1)
1802+
end
1803+
end
1804+
1805+
on_bio_stream_puts(bio_stream::BIOStream{T}, in::Ptr{Cchar}) where {T<:IO} = Cint(0)
1806+
1807+
on_bio_stream_ctrl(bio_stream::BIOStream{T}, cmd::BIOCtrl, num::Clong, ptr::Ptr{Cvoid}) where {T<:IO} = Clong(1)
1808+
1809+
"""
1810+
BIO Stream callbacks.
1811+
"""
1812+
struct BIOStreamCallbacks
1813+
on_bio_create_ptr::Ptr{Nothing}
1814+
on_bio_destroy_ptr::Ptr{Nothing}
1815+
on_bio_read_ptr::Ptr{Nothing}
1816+
on_bio_write_ptr::Ptr{Nothing}
1817+
on_bio_puts_ptr::Ptr{Nothing}
1818+
on_bio_ctrl_ptr::Ptr{Nothing}
1819+
1820+
function BIOStreamCallbacks()
1821+
on_bio_create_ptr = @cfunction on_bio_stream_create Cint (BIOStream{IO},)
1822+
on_bio_destroy_ptr = @cfunction on_bio_stream_destroy Cint (BIOStream{IO},)
1823+
on_bio_read_ptr = @cfunction on_bio_stream_read Cint (BIOStream{IO}, Ptr{Cchar}, Cint)
1824+
on_bio_write_ptr = @cfunction on_bio_stream_write Cint (BIOStream{IO}, Ptr{Cchar}, Cint)
1825+
on_bio_puts_ptr = @cfunction on_bio_stream_puts Cint (BIOStream{IO}, Ptr{Cchar})
1826+
on_bio_ctrl_ptr = @cfunction on_bio_stream_ctrl Clong (BIOStream{IO}, BIOCtrl, Clong, Ptr{Cvoid})
1827+
1828+
return new(
1829+
on_bio_create_ptr,
1830+
on_bio_destroy_ptr,
1831+
on_bio_read_ptr,
1832+
on_bio_write_ptr,
1833+
on_bio_puts_ptr,
1834+
on_bio_ctrl_ptr)
1835+
end
1836+
end
1837+
16931838
"""
16941839
ASN1_TIME.
16951840
"""
@@ -2944,8 +3089,6 @@ function Base.String(x509_ext::X509Extension)
29443089
return "C_NULL"
29453090
end
29463091

2947-
io = IOBuffer()
2948-
29493092
bio = BIO(BIOMethodMemory())
29503093

29513094
_ = ccall(

src/ssl.jl

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,3 @@
1-
"""
2-
BIO Stream callbacks.
3-
"""
4-
5-
"""
6-
Called to initialize new BIO Stream object.
7-
"""
8-
on_bio_stream_create(bio::BIO) = Cint(1)
9-
on_bio_stream_destroy(bio::BIO)::Cint = Cint(0)
10-
11-
function bio_get_data(bio::BIO)
12-
data = ccall(
13-
(:BIO_get_data, libcrypto),
14-
Ptr{Cvoid},
15-
(BIO,),
16-
bio)
17-
return unsafe_pointer_to_objref(data)
18-
end
19-
20-
const BIO_FLAGS_SHOULD_RETRY = 0x08
21-
const BIO_FLAGS_READ = 0x01
22-
const BIO_FLAGS_WRITE = 0x02
23-
const BIO_FLAGS_IO_SPECIAL = 0x04
24-
25-
function bio_set_flags(bio::BIO, flags)
26-
return ccall(
27-
(:BIO_set_flags, libcrypto),
28-
Cint,
29-
(BIO, Cint),
30-
bio, flags)
31-
end
32-
33-
bio_set_read_retry(bio::BIO) = bio_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)
34-
bio_clear_flags(bio::BIO) = bio_set_flags(bio, 0x00)
35-
36-
function on_bio_stream_read(bio::BIO, out::Ptr{Cchar}, outlen::Cint)
37-
try
38-
bio_clear_flags(bio)
39-
io = bio_get_data(bio)::IO
40-
eof(io)
41-
n = bytesavailable(io)
42-
if n == 0
43-
bio_set_read_retry(bio)
44-
return Cint(0)
45-
end
46-
unsafe_read(io, out, min(UInt(n), outlen))
47-
return Cint(min(n, outlen))
48-
catch e
49-
# we don't want to throw a Julia exception from a C callback
50-
return Cint(-1)
51-
end
52-
end
53-
54-
function on_bio_stream_write(bio::BIO, in::Ptr{Cchar}, inlen::Cint)::Cint
55-
try
56-
io = bio_get_data(bio)::IO
57-
written = unsafe_write(io, in, inlen)
58-
return Cint(written)
59-
catch e
60-
# we don't want to throw a Julia exception from a C callback
61-
return Cint(-1)
62-
end
63-
end
64-
65-
on_bio_stream_puts(bio::BIO, in::Ptr{Cchar})::Cint = Cint(0)
66-
67-
on_bio_stream_ctrl(bio::BIO, cmd::BIOCtrl, num::Clong, ptr::Ptr{Cvoid}) = Clong(1)
68-
69-
"""
70-
BIO Stream callbacks.
71-
"""
72-
struct BIOStreamCallbacks
73-
on_bio_create_ptr::Ptr{Nothing}
74-
on_bio_destroy_ptr::Ptr{Nothing}
75-
on_bio_read_ptr::Ptr{Nothing}
76-
on_bio_write_ptr::Ptr{Nothing}
77-
on_bio_puts_ptr::Ptr{Nothing}
78-
on_bio_ctrl_ptr::Ptr{Nothing}
79-
80-
function BIOStreamCallbacks()
81-
on_bio_create_ptr = @cfunction on_bio_stream_create Cint (BIO,)
82-
on_bio_destroy_ptr = @cfunction on_bio_stream_destroy Cint (BIO,)
83-
on_bio_read_ptr = @cfunction on_bio_stream_read Cint (BIO, Ptr{Cchar}, Cint)
84-
on_bio_write_ptr = @cfunction on_bio_stream_write Cint (BIO, Ptr{Cchar}, Cint)
85-
on_bio_puts_ptr = @cfunction on_bio_stream_puts Cint (BIO, Ptr{Cchar})
86-
on_bio_ctrl_ptr = @cfunction on_bio_stream_ctrl Clong (BIO, BIOCtrl, Clong, Ptr{Cvoid})
87-
88-
return new(
89-
on_bio_create_ptr,
90-
on_bio_destroy_ptr,
91-
on_bio_read_ptr,
92-
on_bio_write_ptr,
93-
on_bio_puts_ptr,
94-
on_bio_ctrl_ptr)
95-
end
96-
end
97-
981
"""
992
SSLMethod.
1003
TLSClientMethod.

test/runtests.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -594,10 +594,9 @@ end
594594
@testset "SSLServer" begin
595595
server_task = @async test_server()
596596
client_task = @async test_client()
597-
if isdefined(Base, :errormonitor)
598-
errormonitor(server_task)
599-
errormonitor(client_task)
600-
end
597+
598+
wait(server_task)
599+
wait(client_task)
601600
end
602601

603602
@testset "VersionNumber" begin

0 commit comments

Comments
 (0)