1 //
2 //  btls-bio.c
3 //  MonoBtls
4 //
5 //  Created by Martin Baulig on 14/11/15.
6 //  Copyright (c) 2015 Xamarin. All rights reserved.
7 //
8 
9 #include <btls-ssl.h>
10 #include <btls-bio.h>
11 #include <errno.h>
12 
13 struct MonoBtlsBio {
14 	const void *instance;
15 	MonoBtlsReadFunc read_func;
16 	MonoBtlsWriteFunc write_func;
17 	MonoBtlsControlFunc control_func;
18 };
19 
20 #if 0
21 static void
22 mono_debug (const char *message)
23 {
24 	BIO *bio_err;
25 	bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
26 	fprintf (stderr, "DEBUG: %s\n", message);
27 	ERR_print_errors (bio_err);
28 }
29 #endif
30 
31 static int
mono_read(BIO * bio,char * out,int outl)32 mono_read (BIO *bio, char *out, int outl)
33 {
34 	MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
35 	int ret, wantMore;
36 
37 	if (!mono)
38 		return -1;
39 
40 	ret = mono->read_func (mono->instance, out, outl, &wantMore);
41 
42 	if (ret < 0) {
43 		errno = EIO;
44 		return -1;
45 	}
46 	if (ret > 0)
47 		return ret;
48 
49 	if (wantMore) {
50 		errno = EAGAIN;
51 		BIO_set_retry_read (bio);
52 		return -1;
53 	}
54 
55 	return 0;
56 }
57 
58 static int
mono_write(BIO * bio,const char * in,int inl)59 mono_write (BIO *bio, const char *in, int inl)
60 {
61 	MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
62 
63 	if (!mono)
64 		return -1;
65 
66 	return mono->write_func (mono->instance, in, inl);
67 }
68 
69 static long
mono_ctrl(BIO * bio,int cmd,long num,void * ptr)70 mono_ctrl (BIO *bio, int cmd, long num, void *ptr)
71 {
72 	MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
73 
74 	if (!mono)
75 		return -1;
76 
77 	// fprintf (stderr, "mono_ctrl: %x - %lx - %p\n", cmd, num, ptr);
78 	switch (cmd) {
79 		case BIO_CTRL_FLUSH:
80 			return mono->control_func (mono->instance, MONO_BTLS_CONTROL_COMMAND_FLUSH, 0);
81 		default:
82 			return -1;
83 	}
84 	return -1;
85 }
86 
87 static int
mono_new(BIO * bio)88 mono_new (BIO *bio)
89 {
90 	// mono_debug("mono_new!\n");
91 	bio->init = 0;
92 	bio->num = -1;
93 	bio->flags = 0;
94 	return 1;
95 }
96 
97 static int
mono_free(BIO * bio)98 mono_free (BIO *bio)
99 {
100 	// mono_debug ("mono_free!\n");
101 	if (bio->ptr) {
102 		MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
103 
104 		bio->ptr = NULL;
105 		mono->instance = NULL;
106 		mono->read_func = NULL;
107 		mono->write_func = NULL;
108 		mono->control_func = NULL;
109 		free (mono);
110 	}
111 	return 1;
112 }
113 
114 static const BIO_METHOD mono_method = {
115 	BIO_TYPE_NONE, "mono", mono_write, mono_read,
116 	NULL, NULL, mono_ctrl, mono_new, mono_free, NULL
117 };
118 
119 MONO_API BIO *
mono_btls_bio_mono_new(void)120 mono_btls_bio_mono_new (void)
121 {
122 	BIO *bio;
123 	MonoBtlsBio *monoBio;
124 
125 	bio = BIO_new (&mono_method);
126 	if (!bio)
127 		return NULL;
128 
129 	monoBio = calloc (1, sizeof (MonoBtlsBio));
130 	if (!monoBio) {
131 		BIO_free (bio);
132 		return NULL;
133 	}
134 
135 	bio->ptr = monoBio;
136 	bio->init = 0;
137 
138 	return bio;
139 }
140 
141 MONO_API void
mono_btls_bio_mono_initialize(BIO * bio,const void * instance,MonoBtlsReadFunc read_func,MonoBtlsWriteFunc write_func,MonoBtlsControlFunc control_func)142 mono_btls_bio_mono_initialize (BIO *bio, const void *instance,
143 			      MonoBtlsReadFunc read_func, MonoBtlsWriteFunc write_func,
144 			      MonoBtlsControlFunc control_func)
145 {
146 	MonoBtlsBio *monoBio = bio->ptr;
147 
148 	monoBio->instance = instance;
149 	monoBio->read_func = read_func;
150 	monoBio->write_func = write_func;
151 	monoBio->control_func = control_func;
152 
153 	bio->init = 1;
154 }
155 
156 MONO_API int
mono_btls_bio_read(BIO * bio,void * data,int len)157 mono_btls_bio_read (BIO *bio, void *data, int len)
158 {
159 	return BIO_read (bio, data, len);
160 }
161 
162 MONO_API int
mono_btls_bio_write(BIO * bio,const void * data,int len)163 mono_btls_bio_write (BIO *bio, const void *data, int len)
164 {
165 	return BIO_write (bio, data, len);
166 }
167 
168 MONO_API int
mono_btls_bio_flush(BIO * bio)169 mono_btls_bio_flush (BIO *bio)
170 {
171 	return BIO_flush (bio);
172 }
173 
174 MONO_API int
mono_btls_bio_indent(BIO * bio,unsigned indent,unsigned max_indent)175 mono_btls_bio_indent (BIO *bio, unsigned indent, unsigned max_indent)
176 {
177 	return BIO_indent (bio, indent, max_indent);
178 }
179 
180 MONO_API int
mono_btls_bio_hexdump(BIO * bio,const uint8_t * data,int len,unsigned indent)181 mono_btls_bio_hexdump (BIO *bio, const uint8_t *data, int len, unsigned indent)
182 {
183 	return BIO_hexdump (bio, data, len, indent);
184 }
185 
186 MONO_API void
mono_btls_bio_print_errors(BIO * bio)187 mono_btls_bio_print_errors (BIO *bio)
188 {
189 	BIO_print_errors (bio);
190 }
191 
192 MONO_API void
mono_btls_bio_free(BIO * bio)193 mono_btls_bio_free (BIO *bio)
194 {
195 	BIO_free (bio);
196 }
197 
198 MONO_API BIO *
mono_btls_bio_mem_new(void)199 mono_btls_bio_mem_new (void)
200 {
201 	return BIO_new (BIO_s_mem ());
202 }
203 
204 MONO_API int
mono_btls_bio_mem_get_data(BIO * bio,void ** data)205 mono_btls_bio_mem_get_data (BIO *bio, void **data)
206 {
207 	return (int)BIO_get_mem_data (bio, (char**)data);
208 }
209