@@ -40,3 +40,190 @@ ossl_membio2str(BIO *bio)
4040
4141 return ret ;
4242}
43+
44+ BIO_METHOD * ossl_bio_meth ;
45+ static int bio_state_idx , bio_errinfo_idx ;
46+
47+ static void
48+ bio_save_error (BIO * bio , int state )
49+ {
50+ VALUE errinfo = Qnil ;
51+ if (state ) {
52+ errinfo = rb_errinfo ();
53+ if (rb_obj_is_kind_of (errinfo , rb_eException ))
54+ rb_set_errinfo (Qnil );
55+ else
56+ errinfo = Qnil ;
57+ }
58+ BIO_set_ex_data (bio , bio_state_idx , (void * )(uintptr_t )state );
59+ BIO_set_ex_data (bio , bio_errinfo_idx , (void * )errinfo );
60+ }
61+
62+ int
63+ ossl_bio_restore_error (BIO * bio )
64+ {
65+ int state = (int )(uintptr_t )BIO_get_ex_data (bio , bio_state_idx );
66+ if (!state )
67+ return 0 ;
68+
69+ VALUE errinfo = (VALUE )BIO_get_ex_data (bio , bio_errinfo_idx );
70+ BIO_set_ex_data (bio , bio_state_idx , (void * )(uintptr_t )0 );
71+ BIO_set_ex_data (bio , bio_errinfo_idx , (void * )Qnil );
72+ if (!NIL_P (errinfo ))
73+ rb_set_errinfo (errinfo );
74+ return state ;
75+ }
76+
77+ struct bwrite_args {
78+ BIO * bio ;
79+ const char * data ;
80+ size_t dlen ;
81+ size_t * written ;
82+ };
83+
84+ static VALUE
85+ bio_bwrite0 (VALUE args )
86+ {
87+ struct bwrite_args * p = (void * )args ;
88+ VALUE io = (VALUE )BIO_get_data (p -> bio );
89+ BIO_clear_retry_flags (p -> bio );
90+
91+ VALUE str = rb_str_new_static (p -> data , p -> dlen );
92+ VALUE kwargs = rb_hash_new ();
93+ rb_hash_aset (kwargs , ID2SYM (rb_intern ("exception" )), Qfalse );
94+ VALUE funcallargs [] = { str , kwargs };
95+ VALUE ret = rb_funcallv_public_kw (io , rb_intern ("write_nonblock" ),
96+ 2 , funcallargs , RB_PASS_KEYWORDS );
97+
98+ if (RB_INTEGER_TYPE_P (ret )) {
99+ * p -> written = NUM2SIZET (ret );
100+ return INT2FIX (1 );
101+ }
102+ else if (ret == ID2SYM (rb_intern ("wait_readable" ))) {
103+ BIO_set_retry_read (p -> bio );
104+ return INT2FIX (0 );
105+ }
106+ else if (ret == ID2SYM (rb_intern ("wait_writable" ))) {
107+ BIO_set_retry_write (p -> bio );
108+ return INT2FIX (0 );
109+ }
110+ else {
111+ rb_raise (rb_eTypeError , "write_nonblock must return an Integer, "
112+ ":wait_readable, or :wait_writable" );
113+ }
114+ }
115+
116+ static int
117+ bio_bwrite (BIO * bio , const char * data , size_t dlen , size_t * written )
118+ {
119+ struct bwrite_args args = { bio , data , dlen , written };
120+ int state ;
121+
122+ VALUE ret = rb_protect (bio_bwrite0 , (VALUE )& args , & state );
123+ bio_save_error (bio , state );
124+ if (state )
125+ return 0 ;
126+ return FIX2INT (ret );
127+ }
128+
129+ struct bread_args {
130+ BIO * bio ;
131+ char * data ;
132+ size_t dlen ;
133+ size_t * readbytes ;
134+ };
135+
136+ static VALUE
137+ bio_bread0 (VALUE args )
138+ {
139+ struct bread_args * p = (void * )args ;
140+ VALUE io = (VALUE )BIO_get_data (p -> bio );
141+ BIO_clear_retry_flags (p -> bio );
142+
143+ VALUE kwargs = rb_hash_new ();
144+ rb_hash_aset (kwargs , ID2SYM (rb_intern ("exception" )), Qfalse );
145+ VALUE funcallargs [] = { SIZET2NUM (p -> dlen ), kwargs };
146+ VALUE ret = rb_funcallv_public_kw (io , rb_intern ("read_nonblock" ),
147+ 2 , funcallargs , RB_PASS_KEYWORDS );
148+
149+ if (RB_TYPE_P (ret , T_STRING )) {
150+ size_t len = (size_t )RSTRING_LEN (ret );
151+ if (len > p -> dlen )
152+ rb_raise (rb_eTypeError , "read_nonblock returned too much data" );
153+ memcpy (p -> data , RSTRING_PTR (ret ), len );
154+ * p -> readbytes = len ;
155+ return INT2FIX (1 );
156+ }
157+ else if (NIL_P (ret )) {
158+ BIO_set_flags (p -> bio , BIO_FLAGS_IN_EOF );
159+ return INT2FIX (0 );
160+ }
161+ else if (ret == ID2SYM (rb_intern ("wait_readable" ))) {
162+ BIO_set_retry_read (p -> bio );
163+ return INT2FIX (0 );
164+ }
165+ else if (ret == ID2SYM (rb_intern ("wait_writable" ))) {
166+ BIO_set_retry_write (p -> bio );
167+ return INT2FIX (0 );
168+ }
169+ else {
170+ rb_raise (rb_eTypeError , "write_nonblock must return an Integer, "
171+ ":wait_readable, or :wait_writable" );
172+ }
173+ }
174+
175+ static int
176+ bio_bread (BIO * bio , char * data , size_t dlen , size_t * readbytes )
177+ {
178+ struct bread_args args = { bio , data , dlen , readbytes };
179+ int state ;
180+
181+ VALUE ret = rb_protect (bio_bread0 , (VALUE )& args , & state );
182+ bio_save_error (bio , state );
183+ if (state )
184+ return 0 ;
185+ return FIX2INT (ret );
186+ }
187+
188+ static VALUE
189+ bio_flush0 (VALUE vbio )
190+ {
191+ VALUE io = (VALUE )BIO_get_data ((BIO * )vbio );
192+ return rb_funcallv_public (io , rb_intern ("flush" ), 0 , NULL );
193+ }
194+
195+ static long
196+ bio_ctrl (BIO * bio , int cmd , long larg , void * parg )
197+ {
198+ int state ;
199+
200+ switch (cmd ) {
201+ case BIO_CTRL_EOF :
202+ return BIO_test_flags (bio , BIO_FLAGS_IN_EOF );
203+ case BIO_CTRL_FLUSH :
204+ rb_protect (bio_flush0 , (VALUE )bio , & state );
205+ bio_save_error (bio , state );
206+ return !state ;
207+ default :
208+ return 0 ;
209+ }
210+ }
211+
212+ void
213+ Init_ossl_bio (void )
214+ {
215+ if ((bio_state_idx = BIO_get_ex_new_index (0 , NULL , NULL , NULL , NULL )) < 0 ||
216+ (bio_errinfo_idx = BIO_get_ex_new_index (0 , NULL , NULL , NULL , NULL )) < 0 )
217+ ossl_raise (eOSSLError , "BIO_get_ex_new_index" );
218+
219+ ossl_bio_meth = BIO_meth_new (BIO_TYPE_SOURCE_SINK , "Ruby IO-like object" );
220+ if (!ossl_bio_meth )
221+ ossl_raise (eOSSLError , "BIO_meth_new" );
222+ if (!BIO_meth_set_write_ex (ossl_bio_meth , bio_bwrite ) ||
223+ !BIO_meth_set_read_ex (ossl_bio_meth , bio_bread ) ||
224+ !BIO_meth_set_ctrl (ossl_bio_meth , bio_ctrl )) {
225+ BIO_meth_free (ossl_bio_meth );
226+ ossl_bio_meth = NULL ;
227+ ossl_raise (eOSSLError , "BIO_meth_set_*" );
228+ }
229+ }
0 commit comments