48
48
import javax .net .ssl .SSLHandshakeException ;
49
49
import javax .net .ssl .SSLPeerUnverifiedException ;
50
50
51
- import org .jruby .Ruby ;
52
- import org .jruby .RubyArray ;
53
- import org .jruby .RubyClass ;
54
- import org .jruby .RubyHash ;
55
- import org .jruby .RubyIO ;
56
- import org .jruby .RubyModule ;
57
- import org .jruby .RubyNumeric ;
58
- import org .jruby .RubyObject ;
59
- import org .jruby .RubyString ;
60
- import org .jruby .RubyThread ;
51
+ import org .jruby .*;
61
52
import org .jruby .anno .JRubyMethod ;
62
53
import org .jruby .exceptions .RaiseException ;
63
54
import org .jruby .ext .openssl .x509store .X509Utils ;
64
- import org .jruby .runtime .Arity ;
65
- import org .jruby .runtime .Block ;
66
- import org .jruby .runtime .ObjectAllocator ;
67
- import org .jruby .runtime .ThreadContext ;
55
+ import org .jruby .runtime .*;
68
56
import org .jruby .runtime .builtin .IRubyObject ;
57
+ import org .jruby .runtime .callsite .FunctionalCachingCallSite ;
58
+ import org .jruby .runtime .callsite .RespondToCallSite ;
69
59
import org .jruby .util .ByteList ;
70
- import org .jruby .runtime .Visibility ;
71
60
72
61
import static org .jruby .ext .openssl .SSL .newSSLErrorWaitReadable ;
73
62
import static org .jruby .ext .openssl .SSL .newSSLErrorWaitWritable ;
@@ -86,12 +75,45 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
86
75
}
87
76
};
88
77
78
+ private enum CallSiteIndex {
79
+
80
+ // self
81
+ hostname ("hostname" ),
82
+ //sync_close("sync_close"),
83
+ //sync_close_w("sync_close="),
84
+ // io
85
+ _respond_to_nonblock_w ("nonblock=" ),
86
+ nonblock_w ("nonblock=" ),
87
+ sync ("sync" ),
88
+ sync_w ("sync=" ),
89
+ flush ("flush" ),
90
+ close ("close" ),
91
+ closed_p ("closed?" ),
92
+ // ssl_context
93
+ verify_mode ("verify_mode" );
94
+
95
+ final String method ;
96
+
97
+ CallSiteIndex (String method ) { this .method = method ; }
98
+
99
+ }
100
+
89
101
public static void createSSLSocket (final Ruby runtime , final RubyModule SSL ) { // OpenSSL::SSL
102
+ CallSiteIndex [] values = CallSiteIndex .values ();
103
+ CallSite [] extraCallSites = new CallSite [values .length ];
104
+ for (int i =0 ; i <values .length ; i ++) {
105
+ if (values [i ].name ().startsWith ("_respond_to" )) {
106
+ extraCallSites [i ] = new RespondToCallSite ();
107
+ }
108
+ else {
109
+ extraCallSites [i ] = new FunctionalCachingCallSite (values [i ].method );
110
+ }
111
+ }
112
+
113
+ RubyClass SSLSocket = runtime .defineClassUnder ("SSLSocket" , runtime .getObject (), ALLOCATOR , SSL , extraCallSites );
114
+
90
115
final ThreadContext context = runtime .getCurrentContext ();
91
- RubyClass SSLSocket = SSL .defineClassUnder ("SSLSocket" , runtime .getObject (), ALLOCATOR );
92
- // SSLSocket.addReadAttribute(context, "io");
93
- // SSLSocket.defineAlias("to_io", "io");
94
- // SSLSocket.addReadAttribute(context, "context");
116
+
95
117
SSLSocket .addReadWriteAttribute (context , "sync_close" );
96
118
SSLSocket .addReadWriteAttribute (context , "hostname" );
97
119
SSLSocket .defineAnnotatedMethods (SSLSocket .class );
@@ -123,6 +145,10 @@ private static RaiseException newSSLErrorFromHandshake(Ruby runtime, SSLHandshak
123
145
return SSL .newSSLError (runtime , cause );
124
146
}
125
147
148
+ private CallSite callSite (final CallSiteIndex index ) {
149
+ return getMetaClass ().getExtraCallSites ()[ index .ordinal () ];
150
+ }
151
+
126
152
private SSLContext sslContext ;
127
153
private SSLEngine engine ;
128
154
private RubyIO io ;
@@ -152,29 +178,36 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a
152
178
if ( ! ( args [0 ] instanceof RubyIO ) ) {
153
179
throw runtime .newTypeError ("IO expected but got " + args [0 ].getMetaClass ().getName ());
154
180
}
155
- setInstanceVariable ("@io" , this .io = (RubyIO ) args [0 ]); // compat (we do not read @io)
156
- // Ruby 2.3 : @io.nonblock = true if @io.respond_to?(:nonblock=)
157
- if (io .respondsTo ("nonblock=" )) {
158
- io .callMethod (context , "nonblock=" , runtime .getTrue ());
159
- }
160
181
setInstanceVariable ("@context" , this .sslContext ); // only compat (we do not use @context)
182
+ setInstanceVariable ("@io" , this .io = (RubyIO ) args [0 ]);
183
+ set_io_nonblock_checked (context , runtime .getTrue ());
161
184
// This is a bit of a hack: SSLSocket should share code with
162
185
// RubyBasicSocket, which always sets sync to true.
163
186
// Instead we set it here for now.
164
- this . set_sync (context , runtime .getTrue ()); // io.sync = true
165
- this . callMethod ( context , " sync_close= " , runtime .getFalse ());
187
+ set_sync (context , runtime .getTrue ()); // io.sync = true
188
+ setInstanceVariable ( "@ sync_close" , runtime .getFalse ()); // self.sync_close = false
166
189
sslContext .setup (context );
167
190
return Utils .invokeSuper (context , this , args , Block .NULL_BLOCK ); // super()
168
191
}
169
192
193
+ private IRubyObject set_io_nonblock_checked (final ThreadContext context , RubyBoolean value ) {
194
+ // @io.nonblock = true if @io.respond_to?(:nonblock=)
195
+ IRubyObject respond = callSite (CallSiteIndex ._respond_to_nonblock_w ).call (context , io , io , context .runtime .newSymbol ("nonblock=" ));
196
+ if (respond .isTrue ()) {
197
+ return callSite (CallSiteIndex .nonblock_w ).call (context , io , io , value );
198
+ }
199
+ return context .nil ;
200
+ }
201
+
170
202
private SSLEngine ossl_ssl_setup (final ThreadContext context )
171
203
throws NoSuchAlgorithmException , KeyManagementException {
172
204
SSLEngine engine = this .engine ;
173
205
if ( engine != null ) return engine ;
174
206
175
207
// Server Name Indication (SNI) RFC 3546
176
208
// SNI support will not be attempted unless hostname is explicitly set by the caller
177
- String peerHost = this .callMethod (context , "hostname" ).toString ();
209
+ IRubyObject hostname = callSite (CallSiteIndex .hostname ).call (context , this , this ); // self.hostname
210
+ String peerHost = hostname .toString ();
178
211
final int peerPort = socketChannelImpl ().getRemotePort ();
179
212
engine = sslContext .createSSLEngine (peerHost , peerPort );
180
213
@@ -199,12 +232,12 @@ private SSLEngine ossl_ssl_setup(final ThreadContext context)
199
232
200
233
@ JRubyMethod (name = "sync" )
201
234
public IRubyObject sync (final ThreadContext context ) {
202
- return this . io . callMethod (context , "sync" );
235
+ return callSite ( CallSiteIndex . sync ). call (context , io , io ); // io.sync
203
236
}
204
237
205
238
@ JRubyMethod (name = "sync=" )
206
239
public IRubyObject set_sync (final ThreadContext context , final IRubyObject sync ) {
207
- return this . io . callMethod (context , "sync=" , sync );
240
+ return callSite ( CallSiteIndex . sync_w ). call (context , io , io , sync ); // io.sync = sync
208
241
}
209
242
210
243
@ JRubyMethod
@@ -302,8 +335,8 @@ private IRubyObject acceptImpl(final ThreadContext context, final boolean blocki
302
335
if ( ! initialHandshake ) {
303
336
final SSLEngine engine = ossl_ssl_setup (context );
304
337
engine .setUseClientMode (false );
305
- final IRubyObject verify_mode = sslContext . callMethod (context , "verify_mode" );
306
- if ( ! verify_mode . isNil () ) {
338
+ final IRubyObject verify_mode = callSite ( CallSiteIndex . verify_mode ). call (context , sslContext , sslContext );
339
+ if ( verify_mode != context . nil ) {
307
340
final int verify = RubyNumeric .fix2int (verify_mode );
308
341
if ( verify == 0 ) { // VERIFY_NONE
309
342
engine .setNeedClientAuth (false );
@@ -863,7 +896,7 @@ private IRubyObject syswriteImpl(final ThreadContext context,
863
896
written = write (buff , blocking );
864
897
}
865
898
866
- this . io . callMethod (context , "flush" );
899
+ callSite ( CallSiteIndex . flush ). call (context , io , io ); // io.flush
867
900
868
901
return runtime .newFixnum (written );
869
902
}
@@ -931,17 +964,22 @@ private void close(boolean force) {
931
964
932
965
@ JRubyMethod
933
966
public IRubyObject sysclose (final ThreadContext context ) {
934
- //if ( isClosed() ) return context.runtime.getNil();
935
- if ( this .io .callMethod (context , "closed?" ).isTrue () ) {
936
- return context .runtime .getNil ();
937
- } // Ruby 2.3
967
+ if ( io_closed_p (context ).isTrue () ) return context .nil ;
968
+
938
969
// no need to try shutdown when it's a server
939
970
close ( sslContext .isProtocolForClient () );
940
971
941
- if ( this .callMethod (context , "sync_close" ).isTrue () ) {
942
- return this .io .callMethod (context , "close" );
943
- }
944
- return context .runtime .getNil ();
972
+ if ( getInstanceVariable ("@sync_close" ).isTrue () ) return io_close (context );
973
+
974
+ return context .nil ;
975
+ }
976
+
977
+ private IRubyObject io_closed_p (final ThreadContext context ) { // io.closed?
978
+ return callSite (CallSiteIndex .closed_p ).call (context , io , io );
979
+ }
980
+
981
+ private IRubyObject io_close (final ThreadContext context ) { // io.close
982
+ return callSite (CallSiteIndex .close ).call (context , io , io );
945
983
}
946
984
947
985
@ JRubyMethod
0 commit comments