Skip to content

Commit 3cd3e74

Browse files
committed
MDEV-22992 Refactor VIO into layered transports and filters
Replace the function-pointer VIO implementation with an abstract C++ interface while retaining the procedural C entry points. Implement socket and named-pipe transports and composable filters for client read-ahead, Windows thread-pool prefetch, and TLS. OpenSSL uses a custom BIO, while wolfSSL uses callbacks that perform I/O through the VIO below the TLS filter. This keeps waits and timeouts in the transport layer. Keep sockets nonblocking and implement timed I/O with transport waits. Named pipes use overlapped I/O for timeout-aware waits and report blocking waits through the same scheduler callbacks as sockets. Semi-sync temporarily changes the real VIO read timeout instead of copying VIO state. Hide transport and TLS implementation state behind accessors. Expose the TLS handle opaquely and update callers that previously accessed VIO fields directly. Compile the VIO implementations as C++ and retain PSI memory accounting for VIO allocations. Adapt Windows thread-pool pre-read to a Prefetched_vio filter inserted above the transport so both plain and TLS connections consume prefetched bytes through the same layered VIO path.
1 parent ff09eef commit 3cd3e74

36 files changed

Lines changed: 1884 additions & 1465 deletions

include/ssl_compat.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
along with this program; if not, write to the Free Software
1515
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
1616

17+
#pragma once
18+
19+
#include <openssl/ssl.h>
20+
#include <openssl/err.h>
1721
#include <openssl/opensslv.h>
1822

1923
/* OpenSSL version specific definitions */

include/vio.h

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/* Copyright (c) 2026, MariaDB Corporation.
2+
3+
This program is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; version 2 of the License.
6+
7+
This program is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License
13+
along with this program; if not, write to the Free Software
14+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
15+
16+
#pragma once
17+
18+
#include <new>
19+
#include <violite.h>
20+
21+
/*
22+
C++ VIO interface. C translation units see only the incomplete
23+
struct tag and operate on it through the API declared in violite.h.
24+
*/
25+
struct st_vio
26+
{
27+
public:
28+
st_vio()= default;
29+
st_vio(const st_vio &)= delete;
30+
st_vio &operator=(const st_vio &)= delete;
31+
virtual ~st_vio()= default;
32+
33+
/*
34+
VIO allocations go through my_malloc() so they are accounted with
35+
key_memory_vio. VIO objects are allocated with new (std::nothrow).
36+
*/
37+
static void *operator new(size_t size, const std::nothrow_t&) noexcept;
38+
static void operator delete(void *ptr, const std::nothrow_t&) noexcept;
39+
static void operator delete(void *ptr) noexcept;
40+
41+
/* Last error in errno/GetLastError() form. */
42+
virtual int error() const= 0;
43+
/* Read bytes; returns bytes read, 0 on EOF, or (size_t)-1 on error. */
44+
virtual size_t read(uchar *buf, size_t size)= 0;
45+
/* Write bytes; returns bytes written or (size_t)-1 on error. */
46+
virtual size_t write(const uchar *buf, size_t size)= 0;
47+
/* Set a read (which=0) or write (which=1) timeout in milliseconds. */
48+
virtual int set_timeout(uint which, int timeout_ms)= 0;
49+
/* Close the underlying transport. */
50+
virtual int close()= 0;
51+
/* True if the VIO still refers to a live connection. */
52+
virtual my_bool is_connected()= 0;
53+
/* Shut down reading and/or writing. */
54+
virtual int shutdown(int how)= 0;
55+
/* True if data can be read without blocking. */
56+
virtual my_bool has_data() const= 0;
57+
/* Bytes available without blocking, or -1 on error. */
58+
virtual ssize_t pending()= 0;
59+
/* Wait for an I/O event or timeout. */
60+
virtual int io_wait(enum_vio_io_event event, int timeout)= 0;
61+
/* VIO_TYPE_* of this layer. */
62+
virtual enum enum_vio_type type() const= 0;
63+
/* Current lifecycle state. */
64+
virtual enum enum_vio_state state() const= 0;
65+
/* Short human-readable description. */
66+
virtual const char *description() const= 0;
67+
/* Socket descriptor, or INVALID_SOCKET for other transports. */
68+
virtual my_socket fd() const= 0;
69+
/* Read (which=0) or write (which=1) timeout in milliseconds. */
70+
virtual int get_timeout(uint which) const= 0;
71+
/* True if the peer is local. */
72+
virtual my_bool is_local() const= 0;
73+
/* Wrapped VIO, or nullptr for a transport. */
74+
virtual st_vio *underlying() const= 0;
75+
/* Opaque SSL state, castable to SSL*. */
76+
virtual void *ssl_handle() const= 0;
77+
#ifdef _WIN32
78+
/* Underlying Windows socket or named-pipe handle. */
79+
virtual HANDLE handle() const= 0;
80+
#endif
81+
};
82+
83+
/* Base for VIO layers that delegate to an underlying VIO. */
84+
class Vio_filter : public Vio
85+
{
86+
friend Vio *vio_wrap(Vio *, Vio_filter *);
87+
friend Vio *vio_wrap_transport(Vio *, Vio_filter *);
88+
89+
protected:
90+
/* Owned: destroyed by ~Vio_filter(). */
91+
Vio *m_underlying;
92+
93+
explicit Vio_filter(Vio *underlying= nullptr)
94+
: m_underlying(underlying)
95+
{
96+
}
97+
98+
public:
99+
~Vio_filter() override;
100+
101+
/* VIO this filter wraps. */
102+
Vio *underlying() const override
103+
{
104+
return m_underlying;
105+
}
106+
107+
int error() const override
108+
{
109+
return m_underlying->error();
110+
}
111+
112+
size_t read(uchar *buf, size_t size) override
113+
{
114+
return m_underlying->read(buf, size);
115+
}
116+
117+
size_t write(const uchar *buf, size_t size) override
118+
{
119+
return m_underlying->write(buf, size);
120+
}
121+
122+
int set_timeout(uint which, int timeout_ms) override
123+
{
124+
return m_underlying->set_timeout(which, timeout_ms);
125+
}
126+
127+
int close() override
128+
{
129+
return m_underlying->close();
130+
}
131+
132+
my_bool is_connected() override
133+
{
134+
return m_underlying->is_connected();
135+
}
136+
137+
int shutdown(int how) override
138+
{
139+
return m_underlying->shutdown(how);
140+
}
141+
142+
my_bool has_data() const override
143+
{
144+
return m_underlying->has_data();
145+
}
146+
147+
ssize_t pending() override
148+
{
149+
return m_underlying->pending();
150+
}
151+
152+
int io_wait(enum_vio_io_event event, int timeout) override
153+
{
154+
return m_underlying->io_wait(event, timeout);
155+
}
156+
157+
enum enum_vio_type type() const override
158+
{
159+
return m_underlying->type();
160+
}
161+
162+
enum enum_vio_state state() const override
163+
{
164+
return m_underlying->state();
165+
}
166+
167+
const char *description() const override
168+
{
169+
return m_underlying->description();
170+
}
171+
172+
my_socket fd() const override
173+
{
174+
return m_underlying->fd();
175+
}
176+
177+
int get_timeout(uint which) const override
178+
{
179+
return m_underlying->get_timeout(which);
180+
}
181+
182+
my_bool is_local() const override
183+
{
184+
return m_underlying->is_local();
185+
}
186+
187+
void *ssl_handle() const override
188+
{
189+
return m_underlying->ssl_handle();
190+
}
191+
#ifdef _WIN32
192+
HANDLE handle() const override
193+
{
194+
return m_underlying->handle();
195+
}
196+
#endif
197+
};
198+
199+
/*
200+
Make filter the outermost layer above vio.
201+
202+
Takes ownership of both objects and returns filter.
203+
*/
204+
Vio *vio_wrap(Vio *vio, Vio_filter *filter);
205+
206+
/* Terminal transport at the bottom of the VIO stack. */
207+
Vio *vio_get_transport(Vio *vio);
208+
const Vio *vio_get_transport(const Vio *vio);
209+
210+
/*
211+
Insert filter immediately above the terminal transport in vio.
212+
213+
Takes ownership of filter and preserves the existing outer layers.
214+
*/
215+
Vio *vio_wrap_transport(Vio *vio, Vio_filter *filter);

0 commit comments

Comments
 (0)