1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 Copyright (C) 2012 Red Hat, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "config.h"
19
20 #include <string.h>
21 #include <glib.h>
22
23 #include "spice-util.h"
24 #include "bio-gio.h"
25
26 #if OPENSSL_VERSION_NUMBER < 0x10100000 || \
27 (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000)
28 static BIO_METHOD one_static_bio;
29
BIO_meth_set_read(BIO_METHOD * biom,int (* bread)(BIO *,char *,int))30 static int BIO_meth_set_read(BIO_METHOD *biom,
31 int (*bread) (BIO *, char *, int))
32 {
33 biom->bread = bread;
34 return 1;
35 }
36
BIO_meth_set_write(BIO_METHOD * biom,int (* bwrite)(BIO *,const char *,int))37 static int BIO_meth_set_write(BIO_METHOD *biom,
38 int (*bwrite) (BIO *, const char *, int))
39 {
40 biom->bwrite = bwrite;
41 return 1;
42 }
43
BIO_meth_set_puts(BIO_METHOD * biom,int (* bputs)(BIO *,const char *))44 static int BIO_meth_set_puts(BIO_METHOD *biom,
45 int (*bputs) (BIO *, const char *))
46 {
47 biom->bputs = bputs;
48 return 1;
49 }
50
BIO_meth_set_ctrl(BIO_METHOD * biom,long (* ctrl)(BIO *,int,long,void *))51 static int BIO_meth_set_ctrl(BIO_METHOD *biom,
52 long (*ctrl) (BIO *, int, long, void *))
53 {
54 biom->ctrl = ctrl;
55 return 1;
56 }
57
58 #define BIO_TYPE_START 128
59
BIO_get_new_index(void)60 static int BIO_get_new_index(void)
61 {
62 static int bio_index = BIO_TYPE_START;
63 return bio_index++;
64 }
65
BIO_set_init(BIO * a,int init)66 static void BIO_set_init(BIO *a, int init)
67 {
68 a->init = init;
69 }
70
BIO_set_data(BIO * a,void * ptr)71 static void BIO_set_data(BIO *a, void *ptr)
72 {
73 a->ptr = ptr;
74 }
75
BIO_get_data(BIO * a)76 static void *BIO_get_data(BIO *a)
77 {
78 return a->ptr;
79 }
80
BIO_meth_new(int type,const char * name)81 static BIO_METHOD *BIO_meth_new(int type, const char *name)
82 {
83 BIO_METHOD *biom = &one_static_bio;
84
85 biom->type = type;
86 biom->name = name;
87 return biom;
88 }
89
BIO_meth_free(BIO_METHOD * biom)90 static void BIO_meth_free(BIO_METHOD *biom)
91 {
92 }
93
94 #endif
95
bio_gio_ctrl(G_GNUC_UNUSED BIO * b,int cmd,G_GNUC_UNUSED long num,G_GNUC_UNUSED void * ptr)96 static long bio_gio_ctrl(G_GNUC_UNUSED BIO *b,
97 int cmd,
98 G_GNUC_UNUSED long num,
99 G_GNUC_UNUSED void *ptr)
100 {
101 return (cmd == BIO_CTRL_FLUSH);
102 }
103
bio_gio_write(BIO * bio,const char * in,int inl)104 static int bio_gio_write(BIO *bio, const char *in, int inl)
105 {
106 GOutputStream *stream;
107 gssize ret;
108 GError *error = NULL;
109
110 stream = g_io_stream_get_output_stream(BIO_get_data(bio));
111 ret = g_pollable_output_stream_write_nonblocking(G_POLLABLE_OUTPUT_STREAM(stream),
112 in, inl, NULL, &error);
113 BIO_clear_retry_flags(bio);
114
115 if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
116 BIO_set_retry_write(bio);
117 if (error != NULL) {
118 g_warning("%s", error->message);
119 g_clear_error(&error);
120 }
121
122 return ret;
123 }
124
bio_gio_read(BIO * bio,char * out,int outl)125 static int bio_gio_read(BIO *bio, char *out, int outl)
126 {
127 GInputStream *stream;
128 gssize ret;
129 GError *error = NULL;
130
131 stream = g_io_stream_get_input_stream(BIO_get_data(bio));
132 ret = g_pollable_input_stream_read_nonblocking(G_POLLABLE_INPUT_STREAM(stream),
133 out, outl, NULL, &error);
134 BIO_clear_retry_flags(bio);
135
136 if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
137 BIO_set_retry_read(bio);
138 else if (error != NULL)
139 g_warning("%s", error->message);
140
141 g_clear_error(&error);
142
143 return ret;
144 }
145
bio_gio_puts(BIO * bio,const char * str)146 static int bio_gio_puts(BIO *bio, const char *str)
147 {
148 int n, ret;
149
150 n = strlen(str);
151 ret = bio_gio_write(bio, str, n);
152
153 return ret;
154 }
155
156 static BIO_METHOD *bio_gio_method;
157
158 G_GNUC_INTERNAL
bio_new_giostream(GIOStream * stream)159 BIO* bio_new_giostream(GIOStream *stream)
160 {
161 BIO *bio;
162
163 if (!bio_gio_method) {
164 bio_gio_method = BIO_meth_new(BIO_get_new_index() |
165 BIO_TYPE_SOURCE_SINK,
166 "gio stream");
167 if (!bio_gio_method)
168 return NULL;
169
170 if (!BIO_meth_set_write(bio_gio_method, bio_gio_write) ||
171 !BIO_meth_set_read(bio_gio_method, bio_gio_read) ||
172 !BIO_meth_set_puts(bio_gio_method, bio_gio_puts) ||
173 !BIO_meth_set_ctrl(bio_gio_method, bio_gio_ctrl)) {
174 BIO_meth_free(bio_gio_method);
175 bio_gio_method = NULL;
176 return NULL;
177 }
178 }
179
180 bio = BIO_new(bio_gio_method);
181 if (!bio)
182 return NULL;
183
184 BIO_set_init(bio, 1);
185 BIO_set_data(bio, stream);
186 return bio;
187 }
188