Monday, May 2, 2011

Real SPDY with Eventmachine

‹prev | My Chain | next›

After an unsuccessful attempt last night, I hope to build on what I learned to get NPN SPDY working with eventmachine today. My ultimate hope is that this will allow me to build SPDY services without needing to run Chrome with the --with-spdy=ssl option (which seems to break things).

I eventually dead ended with a 64-bit openssl issue yesterday, so today I start by firing up my 32-bit Ubuntu 10.10 VM. I have yet to do much beyond installing build-essentials on that machine, so this should prove a fairly exhaustive step-by-step for getting going on Ubuntu.

Note: it was so new that I needed to install ssh, curl, git-core, and rvm.

On the VM, I stick with ruby 1.9.2 under rvm (somehow I started with 1.8.7 as my default on my laptop), and git clone the gem:
chris@chris-VirtualBox:~/repos$ git clone git://
Initialized empty Git repository in /home/chris/repos/spdy/.git/
remote: Counting objects: 275, done.
remote: Compressing objects: 100% (167/167), done.
remote: Total 275 (delta 150), reused 177 (delta 93)
Receiving objects: 100% (275/275), 32.16 KiB, done.
Resolving deltas: 100% (150/150), done.
With that, I am ready to pick back up from where I left off yesterday. Specifically, I follow along with Carson McDonald's instructions.

First, I sudo apt-get install zlib1g-dev, which is the equivalent to the Fedora zlib-devel listed in Carson's instructions. The strange next step is to install cvs (way to keep up with the times, openssl), after which I can:
chris@chris-VirtualBox:~/repos$ cvs -d co openssl
The authenticity of host ' (' can't be established.
RSA key fingerprint is 55:c1:16:04:82:09:3a:ac:88:14:27:3f:46:7c:25:e4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ',' (RSA) to the list of known hosts.
cvs server: WARNING: Read-only repository access mode selected via `cvs -R'.
Using this option to access a repository which some users write to may
cause intermittent sandbox corruption.
cvs checkout: Updating openssl
U openssl/.cvsignore
U openssl/util/pl/
U openssl/util/pl/
Next, I configure openssl to install into $HOME/local, which is where I like to install custom built binaries that would normally install into /usr/bin or /usr/local/bin:
chris@chris-VirtualBox:~/repos/openssl$ ./config --prefix=$HOME/local
Operating system: i686-whatever-linux2
Configuring for linux-elf
Configuring for linux-elf
no-ec-nistp224-64-gcc-128 [default] OPENSSL_NO_EC_NISTP224_64_GCC_128 (skip dir)
no-gmp [default] OPENSSL_NO_GMP (skip dir)
no-jpake [experimental] OPENSSL_NO_JPAKE (skip dir)
no-krb5 [krb5-flavor not specified] OPENSSL_NO_KRB5
no-md2 [default] OPENSSL_NO_MD2 (skip dir)
no-rc5 [default] OPENSSL_NO_RC5 (skip dir)
no-rfc3779 [default] OPENSSL_NO_RFC3779 (skip dir)
no-shared [default]
no-store [experimental] OPENSSL_NO_STORE (skip dir)
no-zlib [default]
no-zlib-dynamic [default]
make[1]: Leaving directory `/home/chris/repos/openssl/test'

Since you've disabled or enabled at least one algorithm, you need to do
the following before building:

make depend

Configured for linux-elf.
With that, I can make depend:
chris@chris-VirtualBox:~/repos/openssl$ make depend
making depend in crypto...
make[1]: Entering directory `/home/chris/repos/openssl/crypto'
making depend in crypto/objects...
make[2]: Entering directory `/home/chris/repos/openssl/crypto/objects'
making depend in tools...
make[1]: Entering directory `/home/chris/repos/openssl/tools'
make[1]: Nothing to be done for `depend'.
make[1]: Leaving directory `/home/chris/repos/openssl/tools'
And make install:
chris@chris-VirtualBox:~/repos/openssl$ make install
installing libcrypto.a
installing libssl.a
cp libcrypto.pc /home/chris/local/lib/pkgconfig
chmod 644 /home/chris/local/lib/pkgconfig/libcrypto.pc
cp libssl.pc /home/chris/local/lib/pkgconfig
chmod 644 /home/chris/local/lib/pkgconfig/libssl.pc
cp openssl.pc /home/chris/local/lib/pkgconfig
chmod 644 /home/chris/local/lib/pkgconfig/openssl.pc
With openssl (hopefully) compiled OK, I add the $HOME/local directory to various paths by adding this to my .bashrc:
export PATH=$HOME/local/bin/:$PATH
export LD_LIBRARY_PATH=$HOME/local/lib
export PKG_CONFIG_PATH=$HOME/local/lib/pkgconfig
export CPATH=$HOME/local/include
That should allow a newly compiled ruby to find and use the newly installed edge-openssl:
chris@chris-VirtualBox:~/repos/openssl$ rvm install 1.9.2 -C --with-openssl-dir=$HOME/local
Installing Ruby from source to: /home/chris/.rvm/rubies/ruby-1.9.2-p180, this may take a while depending on your cpu(s)...

ruby-1.9.2-p180 - #fetching
ruby-1.9.2-p180 - #extracted to /home/chris/.rvm/src/ruby-1.9.2-p180 (already extracted)
ruby-1.9.2-p180 - #configuring
ruby-1.9.2-p180 - #compiling
ruby-1.9.2-p180 - #installing
Removing old Rubygems files...
Installing rubygems dedicated to ruby-1.9.2-p180...
Installing rubygems for /home/chris/.rvm/rubies/ruby-1.9.2-p180/bin/ruby
Installation of rubygems completed successfully.
ruby-1.9.2-p180 - adjusting #shebangs for (gem irb erb ri rdoc testrb rake).
ruby-1.9.2-p180 - #importing default gemsets (/home/chris/.rvm/gemsets/)
Install of ruby-1.9.2-p180 - #complete
chris@chris-VirtualBox:~/repos$ rvm --default use 1.9.2
Using /home/chris/.rvm/gems/ruby-1.9.2-p180
I create an rvm gemset (rvm use default@spdy) for my spdy work. This is more a force of habit than a real need since I will be using this VM exclusively for SPDY work. In that gemset, I install bundler:
chris@chris-VirtualBox:~/repos/spdy$ gem install bundler
Fetching: bundler-1.0.12.gem (100%)
Successfully installed bundler-1.0.12
1 gem installed
And, per Carson's instructions, I also install rake-compiler:
chris@chris-VirtualBox:~/repos/spdy$ gem install rake-compiler
Fetching: rake-compiler-0.7.8.gem (100%)
Successfully installed rake-compiler-0.7.8
1 gem installed
And the rest of the ruby gems required by the SPDY gem (with and assist from bundler):
chris@chris-VirtualBox:~/repos/spdy$ bundle install
Fetching source index for
Using rake (0.8.7)
Installing bindata (1.3.1)
Installing diff-lcs (1.1.2)
Installing ffi (1.0.7) with native extensions
Installing ffi-zlib (0.2.0)
Installing rspec-core (2.5.1)
Installing rspec-expectations (2.5.0)
Installing rspec-mocks (2.5.0)
Installing rspec (2.5.0)
Using spdy (0.0.2) from source at /home/chris/repos/spdy
Using bundler (1.0.12)
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
Now, I install Carson's NPN-enabled eventmachine by cloning it from github:
chris@chris-VirtualBox:~/repos$ git clone git://
Initialized empty Git repository in /home/chris/repos/eventmachine/.git/
remote: Counting objects: 3792, done.
remote: Compressing objects: 100% (1263/1263), done.
Receiving objects: 100% (3792/3792), 794.81 KiB | 159 KiB/s, done.
remote: Total 3792 (delta 2702), reused 3339 (delta 2398)
Resolving deltas: 100% (2702/2702), done.
chris@chris-VirtualBox:~/repos$ cd eventmachine
chris@chris-VirtualBox:~/repos/eventmachine$ git checkout tls-npn
Branch tls-npn set up to track remote branch tls-npn from origin.
Switched to a new branch 'tls-npn'
chris@chris-VirtualBox:~/repos/eventmachine$ rake gem
(in /home/chris/repos/eventmachine)
rake-compiler must be configured first to enable cross-compilation
rake-compiler must be configured first to enable cross-compilation
rake-compiler must be configured first to enable cross-compilation
rake-compiler must be configured first to enable cross-compilation
mkdir -p pkg
Successfully built RubyGem
Name: eventmachine
Version: 1.0.0.beta.3
File: eventmachine-1.0.0.beta.3.gem
mv eventmachine-1.0.0.beta.3.gem pkg/eventmachine-1.0.0.beta.3.gem
chris@chris-VirtualBox:~/repos/eventmachine$ gem install pkg/eventmachine-1.0.0.beta.3.gem
Building native extensions. This could take a while...
Successfully installed eventmachine-1.0.0.beta.3
1 gem installed
Yay! That is progress. I could not compile yesterday so I am now officially one step further. So, does it work now?
chris@chris-VirtualBox:~/repos/spdy/examples$ ruby ./npn_spdy_server.rb
/home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/em/connection.rb:404:in `set_negotiable_protocols': undefined method `set_neg
otiable_protocols' for EventMachine:Module (NoMethodError)
from ./npn_spdy_server.rb:35:in `post_init'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/em/connection.rb:45:in `block in new'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/em/connection.rb:36:in `instance_eval'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/em/connection.rb:36:in `new'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/eventmachine.rb:1415:in `event_callback'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/eventmachine.rb:206:in `run_machine'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@spdy/gems/eventmachine-1.0.0.beta.3/lib/eventmachine.rb:206:in `run'
from ./npn_spdy_server.rb:66:in `<main>'

Luckily I determine that this is caused by a bad gem install. Specifically, I had run the eventmachine install in a separate gnu-screen window (without the local openssl in its path). I add the necessary paths, re-run the gem install, and am good to go.

Unfortunately, when I access the service from Chrome, I now see this in the eventmachine output:
chris@chris-VirtualBox:~/repos/spdy/examples$ ruby ./npn_spdy_server.rb
[:SPDY, :connection_closed]
[:SPDY, :connection_closed]
[:SPDY, :connection_closed]
And, in the browser:

Dang. This is very similar to the behavior that I was seeing when I ran Chrome without --with-spdy=ssl the other day.

Soo.... I shut down Chrome and restart with with --with-spdy=ssl. My pinned tabs and extensions break (because that option seems to affect all sites) and it still does not work.

And then I restart and try once more without any command line options to find:

Hrm... better. I wish it would have worked right away, but I will take that as a small victory. It worked (it is SPDY) and I can still access GMail and other web pages. That is definitely progress.

That will suffice as a stopping point for the day. I will pick back up tomorrow to determine how stable this is and to see if I can use ssldump to sniff packets.

Day #8

No comments:

Post a Comment