Last active
January 11, 2017 03:44
-
-
Save tagomoris/3cbd5ccbe77d83c86db2756c096b227f to your computer and use it in GitHub Desktop.
Trying to use SSLSocket for servers on Cool.io
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ruby hoge.rb | |
{:here=>"creating socket"} | |
{:here=>"creating sslsocket"} | |
:here=>"socket.new"} | |
{:here=>"connecting"} | |
{:here=>"calling super"} | |
{:here=>"super called"} | |
{:here=>"on_connect"} | |
{:here=>"trying accept", :accepted=>false} | |
{:here=>"failed to nonblock accept", :error=>OpenSSL::SSL::SSLErrorWaitReadable, :msg=>"read would block"} | |
{:here=>"trying accept", :accepted=>false} | |
{:here=>"successfully accepted"} | |
:here=>"connected"} | |
{:here=>"writing data"} | |
{:here=>"reading data"} | |
:here=>"on_data", :accepted=>true, :data=>"yaaaaaaaaaaaaaaaay\n"} | |
{:here=>"writing response"} | |
{:here=>"write done, detaching"} | |
{:here=>"closing socket"} | |
{:here=>"detached"} | |
{:here=>"data", :data=>"yaaaaaaaaaaaaaaaay\n"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'cool.io' | |
require 'fcntl' | |
require 'openssl' | |
loop = Coolio::Loop.new | |
sock = TCPServer.new("127.0.0.1", 12101) | |
sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) | |
class SSLHandler < Coolio::Socket | |
def initialize(sock) | |
p(here: "socket.new") | |
@sslsock = OpenSSL::SSL::SSLSocket.new(sock, create_ssl_context) | |
@write_buffer = ''.force_encoding('ascii-8bit') | |
@accepted = false | |
p(here: "calling super") | |
super(@sslsock) | |
p(here: "super called") | |
rescue => e | |
p(here: "rescue in initialize", error: e.class, msg: e.message) | |
end | |
def create_ssl_context | |
opts = { | |
private_key_length: 2048, | |
country: 'US', | |
state: 'CA', | |
locality: 'Mountain View', | |
common_name: 'localhost', | |
} | |
key = OpenSSL::PKey::RSA.generate(opts[:private_key_length]) | |
issuer = subject = OpenSSL::X509::Name.new | |
subject.add_entry('C', opts[:country]) | |
subject.add_entry('ST', opts[:state]) | |
subject.add_entry('L', opts[:locality]) | |
subject.add_entry('CN', opts[:common_name]) | |
digest = OpenSSL::Digest::SHA1.new | |
cert = OpenSSL::X509::Certificate.new | |
cert.not_before = Time.at(0) | |
cert.not_after = Time.now + 5 * 365 * 86400 # 5 years after | |
cert.public_key = key | |
cert.serial = 1 | |
cert.issuer = issuer | |
cert.subject = subject | |
cert.sign(key, digest) | |
# cert, key | |
ctx = OpenSSL::SSL::SSLContext.new('TLSv1_2') | |
ctx.cert = cert | |
ctx.key = key | |
ctx | |
end | |
def try_accept | |
p(here: "trying accept", accepted: @accepted) | |
return if @accepted | |
begin | |
@sslsock.accept_nonblock | |
p(here: "successfully accepted") | |
@accepted = true | |
rescue IO::WaitReadable, IO::WaitWritable => e | |
# wait for next try | |
p(here: "failed to nonblock accept", error: e.class, msg: e.message) | |
# p(here: "trying blocking accept") | |
# @sslsock.accept | |
# p(here: "succeeded to accept in blocking mode") | |
# @accepted = true | |
rescue OpenSSL::SSL::SSLError | |
# varification error or something else | |
p(here: "failed to nonblock accept", error: e.class, msg: e.message) | |
p(here: "going to close this socket...") | |
# TODO: disconnect | |
begin | |
self.detach | |
rescue => e | |
p(here: "unexpected error while closing unverified connection", error: e.class, msg: e.message) | |
end | |
end | |
end | |
def on_connect # tcp connection | |
p(here: "on_connect") | |
# try_accept | |
end | |
def on_readable | |
if @accepted | |
super | |
else | |
try_accept | |
end | |
end | |
def on_read(data) | |
p(here: "on_data", accepted: @accepted, data: data) | |
if @accepted | |
p(here: "writing response") | |
write(data) | |
else | |
try_accept | |
end | |
end | |
def write(data) | |
@write_buffer << data | |
schedule_write | |
data.size | |
end | |
def on_writable # overwrite Coolio#on_writable | |
begin | |
# @_write_buffer.write_to(@_io) | |
size = @sslsock.write_nonblock(@write_buffer) | |
@write_buffer.slice!(0, size) | |
rescue IO::WaitWritable, IO::WaitReadable | |
return | |
rescue Errno::EINTR | |
return | |
# SystemCallError catches Errno::EPIPE & Errno::ECONNRESET amongst others. | |
rescue SystemCallError, IOError, SocketError | |
return close | |
end | |
if @write_buffer.empty? | |
disable_write_watcher | |
on_write_complete | |
end | |
end | |
def on_write_complete | |
p(here: "write done, detaching") | |
close # detaches @_io if attached | |
p(here: "detached") | |
end | |
def close | |
p(here: "closing socket") | |
super | |
end | |
end | |
server = Coolio::TCPServer.new(sock, nil, SSLHandler) | |
loop.attach(server) | |
main = Thread.new{ loop.run } | |
sleep 1 | |
p(here: "creating socket") | |
sock = TCPSocket.new("127.0.0.1", 12101) | |
p(here: "creating sslsocket") | |
conn = OpenSSL::SSL::SSLSocket.new(sock) | |
p(here: "connecting") | |
conn.connect | |
p(here: "connected") | |
p(here: "writing data") | |
conn.write "yaaaaaaaaaaaaaaaay\n" | |
p(here: "reading data") | |
data = conn.read | |
p(here: "data", data: data) | |
conn.close | |
server.detach |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment