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