1ed8ee42cSDaniel P. Berrange /*
2ed8ee42cSDaniel P. Berrange * QEMU I/O channels TLS driver
3ed8ee42cSDaniel P. Berrange *
4ed8ee42cSDaniel P. Berrange * Copyright (c) 2015 Red Hat, Inc.
5ed8ee42cSDaniel P. Berrange *
6ed8ee42cSDaniel P. Berrange * This library is free software; you can redistribute it and/or
7ed8ee42cSDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
8ed8ee42cSDaniel P. Berrange * License as published by the Free Software Foundation; either
9c8198bd5SChetan Pant * version 2.1 of the License, or (at your option) any later version.
10ed8ee42cSDaniel P. Berrange *
11ed8ee42cSDaniel P. Berrange * This library is distributed in the hope that it will be useful,
12ed8ee42cSDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
13ed8ee42cSDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14ed8ee42cSDaniel P. Berrange * Lesser General Public License for more details.
15ed8ee42cSDaniel P. Berrange *
16ed8ee42cSDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
17ed8ee42cSDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18ed8ee42cSDaniel P. Berrange *
19ed8ee42cSDaniel P. Berrange */
20ed8ee42cSDaniel P. Berrange
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
22da34e65cSMarkus Armbruster #include "qapi/error.h"
230b8fa32fSMarkus Armbruster #include "qemu/module.h"
24ed8ee42cSDaniel P. Berrange #include "io/channel-tls.h"
25ed8ee42cSDaniel P. Berrange #include "trace.h"
26e4d2bfb1SLukas Straub #include "qemu/atomic.h"
27ed8ee42cSDaniel P. Berrange
28ed8ee42cSDaniel P. Berrange
qio_channel_tls_write_handler(const char * buf,size_t len,void * opaque,Error ** errp)29ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_write_handler(const char *buf,
30ed8ee42cSDaniel P. Berrange size_t len,
31*97f7bf11SDaniel P. Berrangé void *opaque,
32*97f7bf11SDaniel P. Berrangé Error **errp)
33ed8ee42cSDaniel P. Berrange {
34ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
35ed8ee42cSDaniel P. Berrange ssize_t ret;
36ed8ee42cSDaniel P. Berrange
37*97f7bf11SDaniel P. Berrangé ret = qio_channel_write(tioc->master, buf, len, errp);
38ed8ee42cSDaniel P. Berrange if (ret == QIO_CHANNEL_ERR_BLOCK) {
39*97f7bf11SDaniel P. Berrangé return QCRYPTO_TLS_SESSION_ERR_BLOCK;
40ed8ee42cSDaniel P. Berrange } else if (ret < 0) {
41ed8ee42cSDaniel P. Berrange return -1;
42ed8ee42cSDaniel P. Berrange }
43ed8ee42cSDaniel P. Berrange return ret;
44ed8ee42cSDaniel P. Berrange }
45ed8ee42cSDaniel P. Berrange
qio_channel_tls_read_handler(char * buf,size_t len,void * opaque,Error ** errp)46ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_read_handler(char *buf,
47ed8ee42cSDaniel P. Berrange size_t len,
48*97f7bf11SDaniel P. Berrangé void *opaque,
49*97f7bf11SDaniel P. Berrangé Error **errp)
50ed8ee42cSDaniel P. Berrange {
51ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
52ed8ee42cSDaniel P. Berrange ssize_t ret;
53ed8ee42cSDaniel P. Berrange
54*97f7bf11SDaniel P. Berrangé ret = qio_channel_read(tioc->master, buf, len, errp);
55ed8ee42cSDaniel P. Berrange if (ret == QIO_CHANNEL_ERR_BLOCK) {
56*97f7bf11SDaniel P. Berrangé return QCRYPTO_TLS_SESSION_ERR_BLOCK;
57ed8ee42cSDaniel P. Berrange } else if (ret < 0) {
58ed8ee42cSDaniel P. Berrange return -1;
59ed8ee42cSDaniel P. Berrange }
60ed8ee42cSDaniel P. Berrange return ret;
61ed8ee42cSDaniel P. Berrange }
62ed8ee42cSDaniel P. Berrange
63ed8ee42cSDaniel P. Berrange
64ed8ee42cSDaniel P. Berrange QIOChannelTLS *
qio_channel_tls_new_server(QIOChannel * master,QCryptoTLSCreds * creds,const char * aclname,Error ** errp)65ed8ee42cSDaniel P. Berrange qio_channel_tls_new_server(QIOChannel *master,
66ed8ee42cSDaniel P. Berrange QCryptoTLSCreds *creds,
67ed8ee42cSDaniel P. Berrange const char *aclname,
68ed8ee42cSDaniel P. Berrange Error **errp)
69ed8ee42cSDaniel P. Berrange {
70199e84deSEric Blake QIOChannelTLS *tioc;
71199e84deSEric Blake QIOChannel *ioc;
72ed8ee42cSDaniel P. Berrange
73199e84deSEric Blake tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
74199e84deSEric Blake ioc = QIO_CHANNEL(tioc);
75ed8ee42cSDaniel P. Berrange
76199e84deSEric Blake tioc->master = master;
77199e84deSEric Blake ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
7886d063faSPeter Xu if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
79199e84deSEric Blake qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
8086d063faSPeter Xu }
81ed8ee42cSDaniel P. Berrange object_ref(OBJECT(master));
82ed8ee42cSDaniel P. Berrange
83199e84deSEric Blake tioc->session = qcrypto_tls_session_new(
84ed8ee42cSDaniel P. Berrange creds,
85ed8ee42cSDaniel P. Berrange NULL,
86ed8ee42cSDaniel P. Berrange aclname,
87ed8ee42cSDaniel P. Berrange QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
88ed8ee42cSDaniel P. Berrange errp);
89199e84deSEric Blake if (!tioc->session) {
90ed8ee42cSDaniel P. Berrange goto error;
91ed8ee42cSDaniel P. Berrange }
92ed8ee42cSDaniel P. Berrange
93ed8ee42cSDaniel P. Berrange qcrypto_tls_session_set_callbacks(
94199e84deSEric Blake tioc->session,
95ed8ee42cSDaniel P. Berrange qio_channel_tls_write_handler,
96ed8ee42cSDaniel P. Berrange qio_channel_tls_read_handler,
97199e84deSEric Blake tioc);
98ed8ee42cSDaniel P. Berrange
99199e84deSEric Blake trace_qio_channel_tls_new_server(tioc, master, creds, aclname);
100199e84deSEric Blake return tioc;
101ed8ee42cSDaniel P. Berrange
102ed8ee42cSDaniel P. Berrange error:
103199e84deSEric Blake object_unref(OBJECT(tioc));
104ed8ee42cSDaniel P. Berrange return NULL;
105ed8ee42cSDaniel P. Berrange }
106ed8ee42cSDaniel P. Berrange
107ed8ee42cSDaniel P. Berrange QIOChannelTLS *
qio_channel_tls_new_client(QIOChannel * master,QCryptoTLSCreds * creds,const char * hostname,Error ** errp)108ed8ee42cSDaniel P. Berrange qio_channel_tls_new_client(QIOChannel *master,
109ed8ee42cSDaniel P. Berrange QCryptoTLSCreds *creds,
110ed8ee42cSDaniel P. Berrange const char *hostname,
111ed8ee42cSDaniel P. Berrange Error **errp)
112ed8ee42cSDaniel P. Berrange {
113ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc;
114ed8ee42cSDaniel P. Berrange QIOChannel *ioc;
115ed8ee42cSDaniel P. Berrange
116ed8ee42cSDaniel P. Berrange tioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
117ed8ee42cSDaniel P. Berrange ioc = QIO_CHANNEL(tioc);
118ed8ee42cSDaniel P. Berrange
119ed8ee42cSDaniel P. Berrange tioc->master = master;
120199e84deSEric Blake ioc->follow_coroutine_ctx = master->follow_coroutine_ctx;
121e413ae0cSFelipe Franciosi if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
122d8d3c7ccSFelipe Franciosi qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
123ed8ee42cSDaniel P. Berrange }
124ed8ee42cSDaniel P. Berrange object_ref(OBJECT(master));
125ed8ee42cSDaniel P. Berrange
126ed8ee42cSDaniel P. Berrange tioc->session = qcrypto_tls_session_new(
127ed8ee42cSDaniel P. Berrange creds,
128ed8ee42cSDaniel P. Berrange hostname,
129ed8ee42cSDaniel P. Berrange NULL,
130ed8ee42cSDaniel P. Berrange QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
131ed8ee42cSDaniel P. Berrange errp);
132ed8ee42cSDaniel P. Berrange if (!tioc->session) {
133ed8ee42cSDaniel P. Berrange goto error;
134ed8ee42cSDaniel P. Berrange }
135ed8ee42cSDaniel P. Berrange
136ed8ee42cSDaniel P. Berrange qcrypto_tls_session_set_callbacks(
137ed8ee42cSDaniel P. Berrange tioc->session,
138ed8ee42cSDaniel P. Berrange qio_channel_tls_write_handler,
139ed8ee42cSDaniel P. Berrange qio_channel_tls_read_handler,
140ed8ee42cSDaniel P. Berrange tioc);
141ed8ee42cSDaniel P. Berrange
142ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_new_client(tioc, master, creds, hostname);
143ed8ee42cSDaniel P. Berrange return tioc;
144ed8ee42cSDaniel P. Berrange
145ed8ee42cSDaniel P. Berrange error:
146ed8ee42cSDaniel P. Berrange object_unref(OBJECT(tioc));
147ed8ee42cSDaniel P. Berrange return NULL;
148ed8ee42cSDaniel P. Berrange }
149ed8ee42cSDaniel P. Berrange
1501939ccdaSPeter Xu struct QIOChannelTLSData {
1511939ccdaSPeter Xu QIOTask *task;
1521939ccdaSPeter Xu GMainContext *context;
1531939ccdaSPeter Xu };
1541939ccdaSPeter Xu typedef struct QIOChannelTLSData QIOChannelTLSData;
155ed8ee42cSDaniel P. Berrange
156ed8ee42cSDaniel P. Berrange static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
157ed8ee42cSDaniel P. Berrange GIOCondition condition,
158ed8ee42cSDaniel P. Berrange gpointer user_data);
159ed8ee42cSDaniel P. Berrange
qio_channel_tls_handshake_task(QIOChannelTLS * ioc,QIOTask * task,GMainContext * context)160ed8ee42cSDaniel P. Berrange static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
1611939ccdaSPeter Xu QIOTask *task,
1621939ccdaSPeter Xu GMainContext *context)
163ed8ee42cSDaniel P. Berrange {
164ed8ee42cSDaniel P. Berrange Error *err = NULL;
165ed8ee42cSDaniel P. Berrange QCryptoTLSSessionHandshakeStatus status;
166ed8ee42cSDaniel P. Berrange
167ed8ee42cSDaniel P. Berrange if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
168ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_handshake_fail(ioc);
16960e705c5SDaniel P. Berrange qio_task_set_error(task, err);
17060e705c5SDaniel P. Berrange qio_task_complete(task);
17160e705c5SDaniel P. Berrange return;
172ed8ee42cSDaniel P. Berrange }
173ed8ee42cSDaniel P. Berrange
174ed8ee42cSDaniel P. Berrange status = qcrypto_tls_session_get_handshake_status(ioc->session);
175ed8ee42cSDaniel P. Berrange if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
176ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_handshake_complete(ioc);
177ed8ee42cSDaniel P. Berrange if (qcrypto_tls_session_check_credentials(ioc->session,
178ed8ee42cSDaniel P. Berrange &err) < 0) {
179ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_credentials_deny(ioc);
18060e705c5SDaniel P. Berrange qio_task_set_error(task, err);
18160e705c5SDaniel P. Berrange } else {
182ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_credentials_allow(ioc);
18360e705c5SDaniel P. Berrange }
184ed8ee42cSDaniel P. Berrange qio_task_complete(task);
185ed8ee42cSDaniel P. Berrange } else {
186ed8ee42cSDaniel P. Berrange GIOCondition condition;
1871939ccdaSPeter Xu QIOChannelTLSData *data = g_new0(typeof(*data), 1);
1881939ccdaSPeter Xu
1891939ccdaSPeter Xu data->task = task;
1901939ccdaSPeter Xu data->context = context;
1911939ccdaSPeter Xu
1921939ccdaSPeter Xu if (context) {
1931939ccdaSPeter Xu g_main_context_ref(context);
1941939ccdaSPeter Xu }
1951939ccdaSPeter Xu
196ed8ee42cSDaniel P. Berrange if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
197ed8ee42cSDaniel P. Berrange condition = G_IO_OUT;
198ed8ee42cSDaniel P. Berrange } else {
199ed8ee42cSDaniel P. Berrange condition = G_IO_IN;
200ed8ee42cSDaniel P. Berrange }
201ed8ee42cSDaniel P. Berrange
202ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_handshake_pending(ioc, status);
20310be627dSDaniel P. Berrangé ioc->hs_ioc_tag =
2041939ccdaSPeter Xu qio_channel_add_watch_full(ioc->master,
205ed8ee42cSDaniel P. Berrange condition,
206ed8ee42cSDaniel P. Berrange qio_channel_tls_handshake_io,
2071939ccdaSPeter Xu data,
2081939ccdaSPeter Xu NULL,
2091939ccdaSPeter Xu context);
210ed8ee42cSDaniel P. Berrange }
211ed8ee42cSDaniel P. Berrange }
212ed8ee42cSDaniel P. Berrange
213ed8ee42cSDaniel P. Berrange
qio_channel_tls_handshake_io(QIOChannel * ioc,GIOCondition condition,gpointer user_data)214ed8ee42cSDaniel P. Berrange static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
215ed8ee42cSDaniel P. Berrange GIOCondition condition,
216ed8ee42cSDaniel P. Berrange gpointer user_data)
217ed8ee42cSDaniel P. Berrange {
2181939ccdaSPeter Xu QIOChannelTLSData *data = user_data;
2191939ccdaSPeter Xu QIOTask *task = data->task;
2201939ccdaSPeter Xu GMainContext *context = data->context;
221ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
222ed8ee42cSDaniel P. Berrange qio_task_get_source(task));
223ed8ee42cSDaniel P. Berrange
22410be627dSDaniel P. Berrangé tioc->hs_ioc_tag = 0;
2251939ccdaSPeter Xu g_free(data);
2261939ccdaSPeter Xu qio_channel_tls_handshake_task(tioc, task, context);
2271939ccdaSPeter Xu
2281939ccdaSPeter Xu if (context) {
2291939ccdaSPeter Xu g_main_context_unref(context);
2301939ccdaSPeter Xu }
231ed8ee42cSDaniel P. Berrange
232ed8ee42cSDaniel P. Berrange return FALSE;
233ed8ee42cSDaniel P. Berrange }
234ed8ee42cSDaniel P. Berrange
qio_channel_tls_handshake(QIOChannelTLS * ioc,QIOTaskFunc func,gpointer opaque,GDestroyNotify destroy,GMainContext * context)235ed8ee42cSDaniel P. Berrange void qio_channel_tls_handshake(QIOChannelTLS *ioc,
236ed8ee42cSDaniel P. Berrange QIOTaskFunc func,
237ed8ee42cSDaniel P. Berrange gpointer opaque,
2381939ccdaSPeter Xu GDestroyNotify destroy,
2391939ccdaSPeter Xu GMainContext *context)
240ed8ee42cSDaniel P. Berrange {
241ed8ee42cSDaniel P. Berrange QIOTask *task;
242ed8ee42cSDaniel P. Berrange
243ed8ee42cSDaniel P. Berrange task = qio_task_new(OBJECT(ioc),
244ed8ee42cSDaniel P. Berrange func, opaque, destroy);
245ed8ee42cSDaniel P. Berrange
246ed8ee42cSDaniel P. Berrange trace_qio_channel_tls_handshake_start(ioc);
2471939ccdaSPeter Xu qio_channel_tls_handshake_task(ioc, task, context);
248ed8ee42cSDaniel P. Berrange }
249ed8ee42cSDaniel P. Berrange
250ed8ee42cSDaniel P. Berrange
qio_channel_tls_init(Object * obj G_GNUC_UNUSED)251ed8ee42cSDaniel P. Berrange static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
252ed8ee42cSDaniel P. Berrange {
253ed8ee42cSDaniel P. Berrange }
254ed8ee42cSDaniel P. Berrange
255ed8ee42cSDaniel P. Berrange
qio_channel_tls_finalize(Object * obj)256ed8ee42cSDaniel P. Berrange static void qio_channel_tls_finalize(Object *obj)
257ed8ee42cSDaniel P. Berrange {
258ed8ee42cSDaniel P. Berrange QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
259ed8ee42cSDaniel P. Berrange
260ed8ee42cSDaniel P. Berrange object_unref(OBJECT(ioc->master));
261ed8ee42cSDaniel P. Berrange qcrypto_tls_session_free(ioc->session);
262ed8ee42cSDaniel P. Berrange }
263ed8ee42cSDaniel P. Berrange
264ed8ee42cSDaniel P. Berrange
qio_channel_tls_readv(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,int flags,Error ** errp)265ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
266ed8ee42cSDaniel P. Berrange const struct iovec *iov,
267ed8ee42cSDaniel P. Berrange size_t niov,
268ed8ee42cSDaniel P. Berrange int **fds,
269ed8ee42cSDaniel P. Berrange size_t *nfds,
27084615a19Smanish.mishra int flags,
271ed8ee42cSDaniel P. Berrange Error **errp)
272ed8ee42cSDaniel P. Berrange {
273ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
274ed8ee42cSDaniel P. Berrange size_t i;
275ed8ee42cSDaniel P. Berrange ssize_t got = 0;
276ed8ee42cSDaniel P. Berrange
277ed8ee42cSDaniel P. Berrange for (i = 0 ; i < niov ; i++) {
27857941c9cSDaniel P. Berrangé ssize_t ret = qcrypto_tls_session_read(
27957941c9cSDaniel P. Berrangé tioc->session,
280ed8ee42cSDaniel P. Berrange iov[i].iov_base,
28157941c9cSDaniel P. Berrangé iov[i].iov_len,
28257941c9cSDaniel P. Berrangé qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
28357941c9cSDaniel P. Berrangé errp);
28457941c9cSDaniel P. Berrangé if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
285ed8ee42cSDaniel P. Berrange if (got) {
286ed8ee42cSDaniel P. Berrange return got;
287ed8ee42cSDaniel P. Berrange } else {
288ed8ee42cSDaniel P. Berrange return QIO_CHANNEL_ERR_BLOCK;
289ed8ee42cSDaniel P. Berrange }
29057941c9cSDaniel P. Berrangé } else if (ret < 0) {
291ed8ee42cSDaniel P. Berrange return -1;
292ed8ee42cSDaniel P. Berrange }
293ed8ee42cSDaniel P. Berrange got += ret;
294ed8ee42cSDaniel P. Berrange if (ret < iov[i].iov_len) {
295ed8ee42cSDaniel P. Berrange break;
296ed8ee42cSDaniel P. Berrange }
297ed8ee42cSDaniel P. Berrange }
298ed8ee42cSDaniel P. Berrange return got;
299ed8ee42cSDaniel P. Berrange }
300ed8ee42cSDaniel P. Berrange
301ed8ee42cSDaniel P. Berrange
qio_channel_tls_writev(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)302ed8ee42cSDaniel P. Berrange static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
303ed8ee42cSDaniel P. Berrange const struct iovec *iov,
304ed8ee42cSDaniel P. Berrange size_t niov,
305ed8ee42cSDaniel P. Berrange int *fds,
306ed8ee42cSDaniel P. Berrange size_t nfds,
307b88651cbSLeonardo Bras int flags,
308ed8ee42cSDaniel P. Berrange Error **errp)
309ed8ee42cSDaniel P. Berrange {
310ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
311ed8ee42cSDaniel P. Berrange size_t i;
312ed8ee42cSDaniel P. Berrange ssize_t done = 0;
313ed8ee42cSDaniel P. Berrange
314ed8ee42cSDaniel P. Berrange for (i = 0 ; i < niov ; i++) {
315ed8ee42cSDaniel P. Berrange ssize_t ret = qcrypto_tls_session_write(tioc->session,
316ed8ee42cSDaniel P. Berrange iov[i].iov_base,
31757941c9cSDaniel P. Berrangé iov[i].iov_len,
31857941c9cSDaniel P. Berrangé errp);
31957941c9cSDaniel P. Berrangé if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
320ed8ee42cSDaniel P. Berrange if (done) {
321ed8ee42cSDaniel P. Berrange return done;
322ed8ee42cSDaniel P. Berrange } else {
323ed8ee42cSDaniel P. Berrange return QIO_CHANNEL_ERR_BLOCK;
324ed8ee42cSDaniel P. Berrange }
32557941c9cSDaniel P. Berrangé } else if (ret < 0) {
326ed8ee42cSDaniel P. Berrange return -1;
327ed8ee42cSDaniel P. Berrange }
328ed8ee42cSDaniel P. Berrange done += ret;
329ed8ee42cSDaniel P. Berrange if (ret < iov[i].iov_len) {
330ed8ee42cSDaniel P. Berrange break;
331ed8ee42cSDaniel P. Berrange }
332ed8ee42cSDaniel P. Berrange }
333ed8ee42cSDaniel P. Berrange return done;
334ed8ee42cSDaniel P. Berrange }
335ed8ee42cSDaniel P. Berrange
qio_channel_tls_set_blocking(QIOChannel * ioc,bool enabled,Error ** errp)336ed8ee42cSDaniel P. Berrange static int qio_channel_tls_set_blocking(QIOChannel *ioc,
337ed8ee42cSDaniel P. Berrange bool enabled,
338ed8ee42cSDaniel P. Berrange Error **errp)
339ed8ee42cSDaniel P. Berrange {
340ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
341ed8ee42cSDaniel P. Berrange
342ed8ee42cSDaniel P. Berrange return qio_channel_set_blocking(tioc->master, enabled, errp);
343ed8ee42cSDaniel P. Berrange }
344ed8ee42cSDaniel P. Berrange
qio_channel_tls_set_delay(QIOChannel * ioc,bool enabled)345ed8ee42cSDaniel P. Berrange static void qio_channel_tls_set_delay(QIOChannel *ioc,
346ed8ee42cSDaniel P. Berrange bool enabled)
347ed8ee42cSDaniel P. Berrange {
348ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
349ed8ee42cSDaniel P. Berrange
350ed8ee42cSDaniel P. Berrange qio_channel_set_delay(tioc->master, enabled);
351ed8ee42cSDaniel P. Berrange }
352ed8ee42cSDaniel P. Berrange
qio_channel_tls_set_cork(QIOChannel * ioc,bool enabled)353ed8ee42cSDaniel P. Berrange static void qio_channel_tls_set_cork(QIOChannel *ioc,
354ed8ee42cSDaniel P. Berrange bool enabled)
355ed8ee42cSDaniel P. Berrange {
356ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
357ed8ee42cSDaniel P. Berrange
358ed8ee42cSDaniel P. Berrange qio_channel_set_cork(tioc->master, enabled);
359ed8ee42cSDaniel P. Berrange }
360ed8ee42cSDaniel P. Berrange
qio_channel_tls_shutdown(QIOChannel * ioc,QIOChannelShutdown how,Error ** errp)361ed8ee42cSDaniel P. Berrange static int qio_channel_tls_shutdown(QIOChannel *ioc,
362ed8ee42cSDaniel P. Berrange QIOChannelShutdown how,
363ed8ee42cSDaniel P. Berrange Error **errp)
364ed8ee42cSDaniel P. Berrange {
365ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
366ed8ee42cSDaniel P. Berrange
367e4d2bfb1SLukas Straub qatomic_or(&tioc->shutdown, how);
368a2458b6fSDaniel P. Berrangé
369ed8ee42cSDaniel P. Berrange return qio_channel_shutdown(tioc->master, how, errp);
370ed8ee42cSDaniel P. Berrange }
371ed8ee42cSDaniel P. Berrange
qio_channel_tls_close(QIOChannel * ioc,Error ** errp)372ed8ee42cSDaniel P. Berrange static int qio_channel_tls_close(QIOChannel *ioc,
373ed8ee42cSDaniel P. Berrange Error **errp)
374ed8ee42cSDaniel P. Berrange {
375ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
376ed8ee42cSDaniel P. Berrange
37710be627dSDaniel P. Berrangé if (tioc->hs_ioc_tag) {
378003f1536SDaniel P. Berrangé trace_qio_channel_tls_handshake_cancel(ioc);
37910be627dSDaniel P. Berrangé g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
38010be627dSDaniel P. Berrangé }
38110be627dSDaniel P. Berrangé
382ed8ee42cSDaniel P. Berrange return qio_channel_close(tioc->master, errp);
383ed8ee42cSDaniel P. Berrange }
384ed8ee42cSDaniel P. Berrange
qio_channel_tls_set_aio_fd_handler(QIOChannel * ioc,AioContext * read_ctx,IOHandler * io_read,AioContext * write_ctx,IOHandler * io_write,void * opaque)385bf88c124SPaolo Bonzini static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
38606e0f098SStefan Hajnoczi AioContext *read_ctx,
387bf88c124SPaolo Bonzini IOHandler *io_read,
38806e0f098SStefan Hajnoczi AioContext *write_ctx,
389bf88c124SPaolo Bonzini IOHandler *io_write,
390bf88c124SPaolo Bonzini void *opaque)
391bf88c124SPaolo Bonzini {
392bf88c124SPaolo Bonzini QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
393bf88c124SPaolo Bonzini
39406e0f098SStefan Hajnoczi qio_channel_set_aio_fd_handler(tioc->master, read_ctx, io_read,
39506e0f098SStefan Hajnoczi write_ctx, io_write, opaque);
396bf88c124SPaolo Bonzini }
397bf88c124SPaolo Bonzini
398ffda5db6SAntoine Damhet typedef struct QIOChannelTLSSource QIOChannelTLSSource;
399ffda5db6SAntoine Damhet struct QIOChannelTLSSource {
400ffda5db6SAntoine Damhet GSource parent;
401ffda5db6SAntoine Damhet QIOChannelTLS *tioc;
402ffda5db6SAntoine Damhet };
403ffda5db6SAntoine Damhet
404ffda5db6SAntoine Damhet static gboolean
qio_channel_tls_source_check(GSource * source)405ffda5db6SAntoine Damhet qio_channel_tls_source_check(GSource *source)
406ffda5db6SAntoine Damhet {
407ffda5db6SAntoine Damhet QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
408ffda5db6SAntoine Damhet
409ffda5db6SAntoine Damhet return qcrypto_tls_session_check_pending(tsource->tioc->session) > 0;
410ffda5db6SAntoine Damhet }
411ffda5db6SAntoine Damhet
412ffda5db6SAntoine Damhet static gboolean
qio_channel_tls_source_prepare(GSource * source,gint * timeout)413ffda5db6SAntoine Damhet qio_channel_tls_source_prepare(GSource *source, gint *timeout)
414ffda5db6SAntoine Damhet {
415ffda5db6SAntoine Damhet *timeout = -1;
416ffda5db6SAntoine Damhet return qio_channel_tls_source_check(source);
417ffda5db6SAntoine Damhet }
418ffda5db6SAntoine Damhet
419ffda5db6SAntoine Damhet static gboolean
qio_channel_tls_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)420ffda5db6SAntoine Damhet qio_channel_tls_source_dispatch(GSource *source, GSourceFunc callback,
421ffda5db6SAntoine Damhet gpointer user_data)
422ffda5db6SAntoine Damhet {
423ffda5db6SAntoine Damhet return G_SOURCE_CONTINUE;
424ffda5db6SAntoine Damhet }
425ffda5db6SAntoine Damhet
426ffda5db6SAntoine Damhet static void
qio_channel_tls_source_finalize(GSource * source)427ffda5db6SAntoine Damhet qio_channel_tls_source_finalize(GSource *source)
428ffda5db6SAntoine Damhet {
429ffda5db6SAntoine Damhet QIOChannelTLSSource *tsource = (QIOChannelTLSSource *)source;
430ffda5db6SAntoine Damhet
431ffda5db6SAntoine Damhet object_unref(OBJECT(tsource->tioc));
432ffda5db6SAntoine Damhet }
433ffda5db6SAntoine Damhet
434ffda5db6SAntoine Damhet static GSourceFuncs qio_channel_tls_source_funcs = {
435ffda5db6SAntoine Damhet qio_channel_tls_source_prepare,
436ffda5db6SAntoine Damhet qio_channel_tls_source_check,
437ffda5db6SAntoine Damhet qio_channel_tls_source_dispatch,
438ffda5db6SAntoine Damhet qio_channel_tls_source_finalize
439ffda5db6SAntoine Damhet };
440ffda5db6SAntoine Damhet
441ffda5db6SAntoine Damhet static void
qio_channel_tls_read_watch(QIOChannelTLS * tioc,GSource * source)442ffda5db6SAntoine Damhet qio_channel_tls_read_watch(QIOChannelTLS *tioc, GSource *source)
443ffda5db6SAntoine Damhet {
444ffda5db6SAntoine Damhet GSource *child;
445ffda5db6SAntoine Damhet QIOChannelTLSSource *tlssource;
446ffda5db6SAntoine Damhet
447ffda5db6SAntoine Damhet child = g_source_new(&qio_channel_tls_source_funcs,
448ffda5db6SAntoine Damhet sizeof(QIOChannelTLSSource));
449ffda5db6SAntoine Damhet tlssource = (QIOChannelTLSSource *)child;
450ffda5db6SAntoine Damhet
451ffda5db6SAntoine Damhet tlssource->tioc = tioc;
452ffda5db6SAntoine Damhet object_ref(OBJECT(tioc));
453ffda5db6SAntoine Damhet
454ffda5db6SAntoine Damhet g_source_add_child_source(source, child);
455c3a2c84aSMatheus Tavares Bernardino g_source_unref(child);
456ffda5db6SAntoine Damhet }
457ffda5db6SAntoine Damhet
qio_channel_tls_create_watch(QIOChannel * ioc,GIOCondition condition)458ed8ee42cSDaniel P. Berrange static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
459ed8ee42cSDaniel P. Berrange GIOCondition condition)
460ed8ee42cSDaniel P. Berrange {
461ed8ee42cSDaniel P. Berrange QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
462ffda5db6SAntoine Damhet GSource *source = qio_channel_create_watch(tioc->master, condition);
463ed8ee42cSDaniel P. Berrange
464ffda5db6SAntoine Damhet if (condition & G_IO_IN) {
465ffda5db6SAntoine Damhet qio_channel_tls_read_watch(tioc, source);
466ffda5db6SAntoine Damhet }
467ffda5db6SAntoine Damhet
468ffda5db6SAntoine Damhet return source;
469ed8ee42cSDaniel P. Berrange }
470ed8ee42cSDaniel P. Berrange
471ed8ee42cSDaniel P. Berrange QCryptoTLSSession *
qio_channel_tls_get_session(QIOChannelTLS * ioc)472ed8ee42cSDaniel P. Berrange qio_channel_tls_get_session(QIOChannelTLS *ioc)
473ed8ee42cSDaniel P. Berrange {
474ed8ee42cSDaniel P. Berrange return ioc->session;
475ed8ee42cSDaniel P. Berrange }
476ed8ee42cSDaniel P. Berrange
qio_channel_tls_class_init(ObjectClass * klass,void * class_data G_GNUC_UNUSED)477ed8ee42cSDaniel P. Berrange static void qio_channel_tls_class_init(ObjectClass *klass,
478ed8ee42cSDaniel P. Berrange void *class_data G_GNUC_UNUSED)
479ed8ee42cSDaniel P. Berrange {
480ed8ee42cSDaniel P. Berrange QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
481ed8ee42cSDaniel P. Berrange
482ed8ee42cSDaniel P. Berrange ioc_klass->io_writev = qio_channel_tls_writev;
483ed8ee42cSDaniel P. Berrange ioc_klass->io_readv = qio_channel_tls_readv;
484ed8ee42cSDaniel P. Berrange ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
485ed8ee42cSDaniel P. Berrange ioc_klass->io_set_delay = qio_channel_tls_set_delay;
486ed8ee42cSDaniel P. Berrange ioc_klass->io_set_cork = qio_channel_tls_set_cork;
487ed8ee42cSDaniel P. Berrange ioc_klass->io_close = qio_channel_tls_close;
488ed8ee42cSDaniel P. Berrange ioc_klass->io_shutdown = qio_channel_tls_shutdown;
489ed8ee42cSDaniel P. Berrange ioc_klass->io_create_watch = qio_channel_tls_create_watch;
490bf88c124SPaolo Bonzini ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
491ed8ee42cSDaniel P. Berrange }
492ed8ee42cSDaniel P. Berrange
493ed8ee42cSDaniel P. Berrange static const TypeInfo qio_channel_tls_info = {
494ed8ee42cSDaniel P. Berrange .parent = TYPE_QIO_CHANNEL,
495ed8ee42cSDaniel P. Berrange .name = TYPE_QIO_CHANNEL_TLS,
496ed8ee42cSDaniel P. Berrange .instance_size = sizeof(QIOChannelTLS),
497ed8ee42cSDaniel P. Berrange .instance_init = qio_channel_tls_init,
498ed8ee42cSDaniel P. Berrange .instance_finalize = qio_channel_tls_finalize,
499ed8ee42cSDaniel P. Berrange .class_init = qio_channel_tls_class_init,
500ed8ee42cSDaniel P. Berrange };
501ed8ee42cSDaniel P. Berrange
qio_channel_tls_register_types(void)502ed8ee42cSDaniel P. Berrange static void qio_channel_tls_register_types(void)
503ed8ee42cSDaniel P. Berrange {
504ed8ee42cSDaniel P. Berrange type_register_static(&qio_channel_tls_info);
505ed8ee42cSDaniel P. Berrange }
506ed8ee42cSDaniel P. Berrange
507ed8ee42cSDaniel P. Berrange type_init(qio_channel_tls_register_types);
508