txspdy: Day 4: frames and streams oh my

Last night was light on hacking time. Did a lot of reading of the twisted.web code. What I would like to end up way to create a duel https/spdy exposing the same Resource instance tree. Unfortunately it seems like the Site class is a subclass of a HTTPFactory where it would be better for this if it had a ref to that factory.

I used some code from nbhttp to parse the frames and frame headers for a single request. Next up is creating the headers and response frame. Then we'll have enough for a "hello world".

Feb. 11, 2012 (3 months, 1 week ago) | Tags: txspdy | loading comment count...

txspdy: Day 3: pyopenssl done... now to python code

I don't know where to start talking about the problems with building your own copy of Openssl. Ubuntu has added a few patches, one of which adds symbol versioning to the openssl shared libraries. Sounds great, but it means you can't build a new version of openssl from upstream and install it system wide without problems, like say your openssh server dies because of it and you can't login. I have a monitoring system, icinga, that noticed this and sent emails/txt msgs about it so I fixed the problem before finding myself locked out of the system.

Once that was settled I got the three new methods added to pyopenssl and made a test as well. I've sent it upstream to get merged. You can see it (at LaunchPad)[https://code.launchpad.net/~myers-1/pyopenssl/npn].

Now I'm writing a twisted protocol that will parse SPDY frames. The frames build to multiple streams, and I'm not sure how to deal with those. Maybe there is some other multiplexing protocol like this already in twisted.

Feb. 10, 2012 (3 months, 1 week ago) | Tags: txspdy | loading comment count...

txspdy: Day 2

Fighting with C. You hate loving it. You love hating it. But like water, it's good to know how to swim in it because 3/4 of the computing infrastructure is built on it.

I needed to build the openssl-1.0.1-beta2, then make a mod of pyopenssl to add in the NPN feature. Both of these went fine, and I got to a point that I had a clean compile. Trying to run a unit test showed me that something was segfaulting. Backing my changes to pyopenssl out I discovered it still happened without any of my new code. So... does pyopenssl not work with the new beta? I doubted it. Installed valgrind and run the test under that it showed somehow a shared library of crypto.so was getting loaded. dpkg -S showed that was part of the openssl package. Huh.

Puzzled about this for a while, but ldd /usr/bin/python showed that it's was dynamically linked to openssl. Ahh... so pyopenssl was built with a static link to the new openssl, but python was also dynamically linking in the old one, there's your segfaults. The two versions had overwrote each others symbols (unsure why it wasn't all one or the other)

Then I worked on building openssl to be shared and be in /usr/local/lib so that they override the system ssl. I used stow as a way to put all the openssl files in their own place (/usr/local/stow/openssl-1.0.1-beta2) and then have stow symlink them to the right place.

Then I get this:

python: /usr/local/lib/libcrypto.so.1.0.0: no version information available (required by python)
python: /usr/local/lib/libssl.so.1.0.0: no version information available (required by python)

openssl out of the box doesn't put versioning info on it's .so's, So I borrowed a patch from the debian package and applied it. Now openssl is failing to build some things.

And that's where I need to stop for the night. :(

Here is a patch for pyopenssl that might add NPN to it, or it might cause your mouth to taste of metal for the rest of your life.

Feb. 8, 2012 (3 months, 1 week ago) | Tags: python,txspdy | loading comment count...

Project: txsdpy

A ShRUG this week someone mentioned a guy who was working a project every night and blogging about the progress he was making. He was up to 200+ days of this. I thought I'd try to do the same.

So first project: txspdy - a python twisted implementation of a SPDY server.

Why?

  1. knowing http has helped in my day job and protocols are fun. XMPP hacking was a lot of fun.
  2. new shiny
  3. websockets over spdy sounds awesome. I've used websockets to build a app UI for a DirectConnect client I've written.

Why hasn't anyone else done this yet?

There is a python prototype linked off the SDPY page, but it's doesn't use twisted. I will, no doubt, be reading over that code. The fun thing is that no one knows if SDPY will take off.

First problem:

SPDY uses a new SSL extension to tell connecting clients what protocols the server can speak. OpenSSL has a beta version that implements this extension, but you can't use it via pyopenssl. So I've checked that out and started hacking on the C code for it.

I wanted to test that I could get Chrome to talk SPDY to a test server before I went much further. First thing you need are some real ssl certs. I had some from StartCom. I used the openssl binary like this:

/usr/local/ssl/bin/openssl s_server -key server.key \
   -cert server.crt -accept 9000 -www -nextprotoneg spdy/2,http/1.1 -debug

My first attempts with a self signed cert resulted in Chrome connecting and stopping the ssl handshake 3 times then using http/1.1 even thought I had spdy listed too. Not sure what the purpose of that was.

Feb. 8, 2012 (3 months, 1 week ago) | Tags: txspdy | loading comment count...

From 802.11g to 802.11n

File Transfer speed:

802.11g: 98MB 2.1MB/s 00:47

802.11n: 98MB 4.7MB/s 00:21

May 26, 2010 (1 year, 11 months ago) | Tags: wifi | loading comment count...

Beware of ECS A740GM-M and 4+ GB of ram

My ZFS storage server needed more ram so that I could get the VM's running on it a bit more elbow room. I got a pair of 4GB 240 Ram chips and they were a no go on the ECS A740GM-M motherboard I have. Seems that the BIOS screen needs to have the option to remap memory, which it does not. Too bad the manufactures page for it says it supports up to 16GB

April 14, 2010 (2 years, 1 month ago) | loading comment count...

Updating GCD Data

So you have loaded the Grand Comicbook Database into a local postgresql instance and wrote some code that makes use of the data... They just did a new data dump... Now how do you update your copy of the data?

Prep the data

Do the steps in "create mysql clean up script" and "dump data to tab separated value files" steps.

Now copy this python script:

#!/usr/bin/env python

"""
update gcd data that's prep'ed in /tmp/gcd_dump
"""

import os, glob
from pprint import pprint
import psycopg2, psycopg2.extras

table_names = [os.path.splitext(os.path.basename(fp))[0] for fp in glob.glob('/tmp/gcd_dump/*.txt')]

conn = psycopg2.connect("dbname='gcd' user='postgres'")
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

def sql_logger(sql):
    print sql
    cur.execute(sql)

constraints = []
for ii in table_names:
    sql_logger("""
select t.constraint_name, t.table_name, t.constraint_type,
  c.table_name as c_table_name, c.column_name as c_column_name, k.column_name as k_column_name
from information_schema.table_constraints t,
  information_schema.constraint_column_usage c,
  information_schema.key_column_usage k

  where t.constraint_name = c.constraint_name
    and t.constraint_name = k.constraint_name
    and t.constraint_type = 'FOREIGN KEY'
    and c.table_name = '%s'
  """ % ii)
    for row in cur:
        constraints.append(dict(row))

sql_logger('begin')
for ii in constraints:
    sql_logger('alter table %s drop constraint %s;' % (ii['table_name'], ii['constraint_name'],))

for table_name in table_names:
    sql_logger("DELETE FROM %(table_name)s" % locals())
    sql_logger("COPY %(table_name)s FROM '/tmp/gcd_dump/%(table_name)s.txt'" % locals())

for ii in constraints:
    sql_logger("""
ALTER TABLE ONLY %(table_name)s 
  ADD CONSTRAINT %(constraint_name)s 
    FOREIGN KEY (%(k_column_name)s) REFERENCES %(c_table_name)s(%(c_column_name)s) DEFERRABLE INITIALLY DEFERRED;
""" % ii)

sql_logger('commit')

You'll have to run this as the postgres user just as before. It records the FOREIGN KEY CONSTRAINT, drops them, deletes the old data, copies in the new, and recreates the constraints, all in one transaction! Eat that MySQL.

Feb. 2, 2010 (2 years, 3 months ago) | Tags: django,python | loading comment count...

django_loader.py

I got tired of putting

import os, sys
sys.path.append(<django project parent dir>)
sys.path.append(<django project dir>)
os.environ['DJANGO_SETTINGS_MODULE']='<django project name>.settings'

at the top of all my scripts that do command line things with my django models. So I share with you 'django_loader.py'. Note the use of traceback to figure out what file is importing 'django_loader.py'.

""" 
Put this in your python path.  At the top of your script put 'import
django_loader'.  This will start with the directory your file is in and
search through it and it's parent directories until it finds a file named
'settings.py'.  It will then add that directory and it's parent to your
sys.path, and set DJANGO_SETTINGS env var.  
"""

import os, sys, traceback

class CouldNotFindSettings(StandardError):
    pass
def find_settings(current_dir):
    if current_dir == '/':
        raise CouldNotFindSettings
    if 'settings.py' in os.listdir(current_dir):
        return current_dir
    return find_settings(os.path.dirname(current_dir))
def load(filepath):
    django_project_dir = find_settings(os.path.dirname(filepath))
    django_project_name = os.path.basename(django_project_dir)

    sys.path.append(os.path.dirname(django_project_dir))
    sys.path.append(django_project_dir)
    os.environ['DJANGO_SETTINGS_MODULE']='%s.settings' % (django_project_name,)

current_filepath = os.path.normpath(os.path.join(os.getcwd(), traceback.extract_stack(limit=2)[0][0]))
load(current_filepath)

Jan. 21, 2010 (2 years, 3 months ago) | Tags: django,python | loading comment count...

Now playing in 2010

XBox 360

  • Dead Rising - I've been playing this off and on since 2008. This last weekend I made a huge amount of progress, but I might have to start over due to saving when I was almost out of time for a mission. Punishing difficulty, but it's more fun that way.
  • Dragon Age - There's no way I'll finish before Mass Effect 2 comes out this month, and I like the Mass Effect story more. I suspect this one will be around for a while.
  • Left 4 Dead 2 - It's intense, but difficult to get the right people for a good game at expert. Clearly I need a second TV and xbox to put in the family room.

D&D

Just finished a 3 year once a week campaign. My character destroyed the universe. Sorry about that guys.

Started a new campaign as a Binder/Bard based way too closely on Eddie Riggs from BrĂ¼tal Legend. I know it's cheep to copy, but it's fun. Since the world he lives in looks more like the a heavy metal cover from this world his album covers will have folks in offices, staring at computers.

Jan. 11, 2010 (2 years, 4 months ago) | Tags: video-games | loading comment count...

Why Django? Why Postgres?

I use Django and Postgres at home, because I use Rails and MySQL all day at work. Working in totally different solutions to the same problem keeps you fresh.

Jan. 11, 2010 (2 years, 4 months ago) | loading comment count...

How to convert data in a MySQL database to Postgresql

To do this you need both mysql and postgresql running on a local computer. You probably want this to be a local workstation that you have superuser access to. We are going to use features in mysql and postgres that makes the database daemon read and write to local files.

We'll use django's schema format deal with the difference between postgresql and mysql. We'll use tab separated value (TSV) data files as the interchange format between databases. Mysql has a different idea of how to escape newlines and carriage returns than Postgresql so we'll use a quick and dirty python script to clean that up.

While this should work in many different OS's, I did this on a Ubuntu, so the details might be a bit different.

Let's start with the most recent data dump from the Grand Comicbook Database

load data into mysql

mysqladmin -uroot create gcd
mysql -uroot gcd < pub_dec21_schema_innodb.sql
unzip pub_dec21_data.zip
mysql -uroot gcd < pub_dec21_data.sql

create django project

django-admin.py startproject grandcomicdb
cd grandcomicdb
chmod +x manage.py
./manage.py startapp gcd
# edit settings.py to add gcd to INSTALLED_APPS
# edit settings.py to set up connection to mysql
./manage.py inspectdb > gcd/models.py
# edit gcd/models.py to make the fk quoted, and add relative_name's

create mysql clean up script

cat >> fix_mysql_tsv.py << EOF
#!/usr/bin/env python

# this will not work for very big files.

import sys
ff = open(sys.argv[1], 'r').read()
ff = ff.replace('\r', '\\r')
ff = ff.replace('\\\n', '\\n')

open(sys.argv[1], 'w').write(ff)
EOF
chmod +x fix_mysql_tsv.py

dump data to tab separated value files

mkdir /tmp/gcd_dump
chmod 777 /tmp/gcd_dump
mysqldump -uroot -t --tab /tmp/gcd_dump gcd
find /tmp/gcd_dump -type f -exec ~/web/grandcomicsdb/fix_mysql_tsv.py \{\} \;

create postgres database with schema derived from the mysql database

sudo -s -u postgres
createuser gcd --pwprompt --no-createrole --no-createdb
createdb gcd -O gcd
exit
# edit settings.py to set up connection to postgresql
./manage syncdb

create postgres database and load data

sudo -s -u postgres
psql
BEGIN;
COPY gcd_language FROM '/tmp/gcd_dump/gcd_language.txt';
COPY gcd_country FROM '/tmp/gcd_dump/gcd_country.txt';
COPY gcd_brand FROM '/tmp/gcd_dump/gcd_brand.txt';
COPY gcd_publisher FROM '/tmp/gcd_dump/gcd_publisher.txt';
COPY gcd_indicia_publisher FROM '/tmp/gcd_dump/gcd_indicia_publisher.txt';
COPY gcd_story_type FROM '/tmp/gcd_dump/gcd_story_type.txt';
COPY gcd_series FROM '/tmp/gcd_dump/gcd_series.txt';
COPY gcd_issue FROM '/tmp/gcd_dump/gcd_issue.txt';
COPY gcd_story FROM '/tmp/gcd_dump/gcd_story.txt';
COMMIT;

Jan. 11, 2010 (2 years, 4 months ago) | Tags: django,python | loading comment count...

Using Ruby's SVN bindings

I couldn't find the simplest example of using Ruby's SVN bindings. Here's something simple, get the info on some file in a local working directory.

require 'svn/client'

ctx = Svn::Client::Context.new
ctx.add_simple_provider
ctx.info('some file in your svn working dir') do |path,info|
  p path
  p info.last_changed_rev
end

This page is also useful.

Sept. 25, 2008 (3 years, 7 months ago) | Tags: ruby | loading comment count...

Rosetta Stone Project Caribbean

This should give you an idea of what it’s like to work at Rosetta Stone… the CEO just emailed this to everyone:

Sept. 20, 2008 (3 years, 8 months ago) | loading comment count...

Currently Playing

Like you care…

XBox 360

  • Dead Rising (love it)
  • GTA IV
  • Mass Effect
  • Beautiful Katamari
  • Half Life 2 (replaying for the achievements)
  • Castle Crashers (need to try online coop)
  • Braid (hurting my brain)

PS2

  • Champions of Norrath 2 (waiting to visit Jason and hack our way thru)
  • God of War (suck in that room of blades on a grid that needs timing that I can’t do)

Wii

  • Mario Galaxy

Sept. 12, 2008 (3 years, 8 months ago) | Tags: video-games | loading comment count...

Validing with an XSD in ruby

    xml = generate_xml
    require 'xml'
    Tempfile.open(self.class.to_s) do |tmp|
      tmp.write(xml)
      tmp.close
      document = XML::Document.file(tmp.path)
      schema_doc = XML::Document.file("some.xsd")
      schema = XML::Schema.document(schema_doc)
      assert document.validate(schema), "the xml isn't valid.  look above for error."
    end

Sept. 6, 2008 (3 years, 8 months ago) | loading comment count...