Skip to content

Instantly share code, notes, and snippets.

@knewter
Last active December 18, 2015 17:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knewter/5818005 to your computer and use it in GitHub Desktop.
Save knewter/5818005 to your computer and use it in GitHub Desktop.
Simultaneous Read Write hanging with sslsocket in celluloid-io in jruby
rvm jruby-1.7.4@celluloid_jruby_ssl_repro --create
#rvm ruby-1.9.3@celluloid_jruby_ssl_repro --create

Bug repro in JRuby

This exposes a bug in JRuby w/r/t socket reads hanging in certain conditions.

Expected behaviour:

Run the server. Connect with a client. Get a pong. Send 2 chars from the client. Read them one at a time successfully from the server.

Actual behaviour:

In celluloid-io master, works as expected. In this branch, first readpartial(1) succeeds. Second hangs indefinitely.

Steps to reproduce:

Make sure this branch is active in the Gemfile.

bundle
bundle exec ruby ssl.rb

In another console, run:

openssl s_client -ssl3 -connect localhost:11443

See the pong from the client. Type "GE"

From the pry console that opens in the server, type:

socket.readpartial(1)
# => "G"
$lolflag = true # So my binding.pry in celluloid-io triggers
socket.readpartial(1)
# Enters pry, after which:
#     Kernel.select([@io])
# HANGS INDEFINITELY
# but...
#     @io.read_nonblock(1)
# returns "E" as expected
source 'https://rubygems.org'
gem 'celluloid', github: 'celluloid/celluloid'
gem 'celluloid-io', github: 'knewter/celluloid-io', branch: 'simultaneous-read-write-debug'
#gem 'celluloid-io', github: 'celluloid/celluloid-io', branch: 'simultaneous-read-write'
#gem 'celluloid-io', github: 'celluloid/celluloid-io'
gem 'pry'
GIT
remote: git://github.com/celluloid/celluloid.git
revision: 106dc021492802627fb2a731781fe89e413a33ab
specs:
celluloid (0.15.0.pre)
timers (>= 1.0.0)
GIT
remote: git://github.com/knewter/celluloid-io.git
revision: 19fc51823303ba39d10f120e74fde9b678d1b0a7
branch: simultaneous-read-write-debug
specs:
celluloid-io (0.15.0.pre)
celluloid (>= 0.13.0)
nio4r (>= 0.4.5)
GEM
remote: https://rubygems.org/
specs:
coderay (1.0.9)
ffi (1.9.0)
ffi (1.9.0-java)
method_source (0.8.1)
nio4r (0.4.6)
nio4r (0.4.6-java)
pry (0.9.12.2)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
pry (0.9.12.2-java)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
spoon (~> 0.0)
slop (3.4.5)
spoon (0.0.4)
ffi
timers (1.1.0)
PLATFORMS
java
ruby
DEPENDENCIES
celluloid!
celluloid-io!
pry
require 'celluloid'
require 'celluloid/io'
require 'pry'
class Server
include Celluloid
include Celluloid::IO
include Celluloid::Logger
def initialize
tcp_server = TCPServer.new('127.0.0.1', 11443)
cert_str = "-----BEGIN CERTIFICATE-----
MIIDmjCCAoICCQD+dJ16wNIKnzANBgkqhkiG9w0BAQUFADCBjjELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
EjAQBgNVBAoTCUNlbGx1bG9pZDEbMBkGA1UEAxMSc2VydmVyLmV4YW1wbGUuY29t
MSEwHwYJKoZIhvcNAQkBFhJzZXJ2ZXJAZXhhbXBsZS5jb20wHhcNMTIxMTI1MTkx
NjAwWhcNMjIxMTIzMTkxNjAwWjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh
bGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoTCUNlbGx1
bG9pZDEbMBkGA1UEAxMSc2VydmVyLmV4YW1wbGUuY29tMSEwHwYJKoZIhvcNAQkB
FhJzZXJ2ZXJAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCpLs3Xg00RtoG4+SKaaNfw6Dve9d0Kkg0CNfU8AsxOgTIU1Qu8s+bzKkqe
66NfCa6T8VPpk9VbIlF2ONdgY4o8muV1q+mS6j2HDAtWPiDjP+9YOwGf/DT3LhSb
g8k+alL2cqe7B1XNUsNFEvQ+yQLlj9MWKb7nbYDM8aqdv46KGoDj9v9rfm4QiKwI
B6u/KoQG22YF7sT4O44jU/u20xcm3rV1Elg0gC/UP/YqnuMPCZYcK/Z9vYGtDJ6G
8OYDcPZSZBdkqlffhYBssSj3R7sTCqoh4ms08ukcGycbvUO+cWrPKnmySsGaCYtG
kp7QsH1ec7QGA01hZL2yL8CuJMUbAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBABE4
gYVSdC87NhpA49k0vcLLU7v7mU3a3no/vu1CIqQxzx8/xh26Qi3aGb1s9MgHpF2Z
NiB1irXER2tyz/F3qCi8OCo7eNsndmDjj4GnkBjEPTtqRxH9imRWw4bJyqwqFHcu
1kczCZa+2VFQFEL4ErGycPFKM59ppTcJ0IxbK7PCGzO75TRQoAl52+3Aob+oejPP
qFbiqNlV1T3EKa5yLdvOC5sLrEcfm3iMxmOtNVzp9OBhjXfm8Q1zgYs4VyJXzLMK
wf956w2YEbpTAAzNc53zly/Jhr4MnFsa9Mn1oYp9Rfjzw/qJtXw+a3PtEKrO4XNe
TsKHsAkj8XvUrhliiNQ=
-----END CERTIFICATE-----"
key_str = "-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAqS7N14NNEbaBuPkimmjX8Og73vXdCpINAjX1PALMToEyFNUL
vLPm8ypKnuujXwmuk/FT6ZPVWyJRdjjXYGOKPJrldavpkuo9hwwLVj4g4z/vWDsB
n/w09y4Um4PJPmpS9nKnuwdVzVLDRRL0PskC5Y/TFim+522AzPGqnb+OihqA4/b/
a35uEIisCAervyqEBttmBe7E+DuOI1P7ttMXJt61dRJYNIAv1D/2Kp7jDwmWHCv2
fb2BrQyehvDmA3D2UmQXZKpX34WAbLEo90e7EwqqIeJrNPLpHBsnG71DvnFqzyp5
skrBmgmLRpKe0LB9XnO0BgNNYWS9si/AriTFGwIDAQABAoIBAGKRoV4p4rIqOiQy
CuYZpY53T8KUToeFFk0ucMXY/33RqgMXKTJ1Ql50SmuS8GlDs9IALZqOBiWFth6B
+YHwHK84s+2+DmUJUnWnH8fMhM7CBknKfyTeBWHqGBmPS6WwvstVe8HtASGSUbCh
3WnjJWvoQtzLz6z4UK2XM4ea/ooY+hlcw6DM+jZuTstzLFE/9BPoHueaW8UemjaH
ZUXMKm3+I3iIjHszUUWM59bS9pOBn/YvIJbVE5wMIVCP2YXDCgfpV2Z4nDiAHppn
fnha2TzHzlPMgwhBpz06r6G8X+A6gJl98TDSK41nIMyXqiZ2aoALL3UOssAMfUHr
2y9CGdECgYEA27F1IyUW3JgqCeqZ7eCeT4emhAvyohzM5pzWI7C8ZosF14zFRpek
TgmjdTGMQ1EZVVkyj85RyvMm3MkcKOHetc5g2jJg3EkxvAV+PMs7yjpqg3itEjC6
vIhXLoXdq+FuruA2h4O0hi6yuf1FCQYtpNLTe49qetjsaWzwwowHwlMCgYEAxSRo
k+AdpoNXblnIhd0EaKjGAsHFrC039o7JqQe/mKAiXaGiidIDk5Vt/ChT6Qa6fiLq
cdysCn+tSCt/DdRrELZohc0ipuy5/agQmJgWoW7oay8ldzxHP9VevWo4UuqVudW9
evhKe0a9uXCrSimvZ5PJk91lmBx92FBeP6Y+qRkCgYAXQsvPQ88O3kGdOSzBJgY9
D3TPCGDRT1FWnYaC0uSvysp8jxgYKFgqNxUKhIuAWSbghYg397VrUqFrwRNtNLUa
9NYGZE0jJdDRQpeiIjaba+H5N57DjUtISPtKHrxgxYatl2nOoWBM0Mb1sF5N3UyZ
5gSkUYQJq8wkQXegcakkpwKBgEdvvgV3vMbN6SyvlB4NzL8wCTCOjtapPBI4A5Mg
n6jqvgk3vPI8C9e62jP5WQ6jxYhXlqTT1fOn+F6ihFO6mWFg99ckUl4ygeMMt5bT
5b9xtP7CAs2GJjtXUhFJIEfLgZ3pedPJjRPGupEr5qXlHQ5nWzAdlebczC1KUhy2
XRZhAoGAGA3SAAF79PK3c3+bOOviXxDFuH5TCBmbtEpJ+/jCbwR6Z8fMRswZJ3Gc
l8eNMsB+Kfif+806xAgLxsyhYuyvF6rE/V34GKjW22T1gwk6gY/rOgFn42jo8lwl
HFbSB+IG0+Go0m+0QmyRh7SyPvDNtyYzBFFdl9U8JYYGM0Nfgd0=
-----END RSA PRIVATE KEY-----"
server_cert = OpenSSL::X509::Certificate.new cert_str
server_key = OpenSSL::PKey::RSA.new key_str
ssl_context = OpenSSL::SSL::SSLContext.new.tap do |context|
context.cert = server_cert
context.key = server_key
end
@server = SSLServer.new(tcp_server, ssl_context)
async.run
end
def run
info "Server started"
loop { async.handle_connection2 @server.accept }
end
def handle_connection2(socket)
socket << 'pong'
binding.pry
socket.close
end
end
if __FILE__ == $0
Server.new
sleep
end
require 'celluloid'
require 'celluloid/io'
class Server
include Celluloid
include Celluloid::IO
include Celluloid::Logger
def initialize
@server = TCPServer.new('127.0.0.1', 11443)
async.run
end
def run
info "Server started"
loop { async.handle_connection @server.accept }
end
def handle_connection(socket)
socket << 'pong'
socket.close
end
end
if __FILE__ == $0
Server.new
sleep
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment