Oscon 2008 Day One report
Outbound: Spotted at least two OSCON attendees at Dulles Airport. One carrying a dynamic OLED keyboard (Optimus Maximus) that can display different character set imaginable (well, 113 different ones at least), another hard at work on her OLPC XO. I’m sure there were others, but better camouflaged. The flight was late, and cramped, and I was keenly aware of United’s 33-inch seat pitch versus the 33 inches one gets on Frontier Airlines.
The keyboard bearer was one convivial Jacob coming in from http://www.thinkgeek.com, and we together figured out the Max light rail in towards the convention center.
Monday: At breakfast I got an inkling that OSCON attendees are more sociable than their USENIX/SAGE counterparts. At least it wasn’t pulling teeth to engage in a conversation. Joel Noble of Caring Family described his group’s project to bring social networking to the elderly via simple pen & paper interfaces. Fred Meyer of USA Today was from my neck of the woods, and a fellow bike commuter, and we ended up walking Portland in the evening. As for the sessions….
Mastering Perl: brian d foy got down to some essentials of his book of the same name. Takeaways: Profiling can be useful, Benchmarking is less useful than one thinks (unless done correctly). Configuration is good. As is logging and persistence.
I then succumbed to my passions instead of my rational side—and jumped into the Arduino tutorial “Making Things Blink”. What a trip! Michael Dory, Adam Simon, and Scott Varland took us on a whirlwind introduction of the remarkably intuitive Arduino microcontroller system. Their kit included the Arduino Diecimila board, a interface shield, microbreadboard, LEDs, potentiometers, wiring, and force transducers. Oh, and a copy of “Making Things Talk” by Tom Igoe. Soon I was tweaking their circuit and code examples to implement my own riffs on their tutorial project, and by the end I had completed their digital ‘Etch-a-Sketch’ project
I’m excited to do more—and not for any practical reason. It’s just somehow exciting to get back to hardware, real transistors, resistors and diodes, after a generation of computing advances have made hardware less and less accessible at any level beyond swapping out whole components.
Peter out.
This American Life and Amazon Web Services
Dear Ira Glass and Elizabeth Meister,
Today I was listening to your “This American Life” podcast and the prelude included a fund campaign to support your podcasts. Being a dutiful listener, and more than that, a fan committed enough to attend a live TAL show, I’m going to go beyond making a $5 donation, and help you save $70,000 per year.
Today you said that on average you support 400,000 download of your podcast per week (or 1.73 million a month) at a bandwith cost of $152,000 per year (or $12670 per month). That’s a situation not unlike the one we faced at EchoDitto when Rosie O’Donnell, or most prominent client, had b/w charges going through the roof when her podcasts were in the news last year. Our solution then was to move using media hosting through Amazon’s Web Services’ (AWS) Simple Storage Service (S3). Before we get into implementation, let’s look at cost for using S3:
STORAGE and UPLOAD:
- Typical podcast size: 28M
- Podcast storage for one year’s worth of podcasts (approx. 40 new podcasts per year): 1.1Gb
- Monthly cost for 1 year’s podcast storage with S3 (1.1.Gb * $0.15 per GB per month): 16¬¢
- Monthly upload costs (10¢ per Gb): 1¢
- Subtotal storage and upload per month: 11¢
- or, effectively nothing.
DOWNLOAD:
- Bandwidth: 400,000 downloads per week of 28Mb podcasts: 10937 Gb/week, or ~50 Tb/Month
- Requests: 400,000 * 4.33 : 1,732,000 GETs per month
And here I fall back on the AWS monthly calculator to come up $6912 per month, or $83,000 per year, an annual savings or $69,000
Implementation
- Sign up for AWS with your WBEZ credit card
- Sign up for S3, and get your AWS_ACCESS_KEY_ID and your AWS_SECRET_ACCESS_KEY
- Download and install S3Fox for Firefox, and configure S3Fox with the keys from the step above
- Use S3Fox to create a bucket called, say, media.thisamericanlife.org
- Use S3fox to upload a podcast with an object key, say, ‘podcast/332.mp3’
- In DNS, create a CNAME
media CNAME media.thisamericanlife.org.s3.amazonaws.com - Link to your podcast at @http://media.thisamericanlife.org/podcast/332.mp3’
That’s it. To learn more read Scalable Media Hosting with Amazon S3
What about streamguys.com?
Continue to use them for streaming. There no reason you can’t split the hosting for your downloadable podcasts vs. your streaming media.
Downsides
I can’t think of any. There’s no upfront cost, no commitment. You could even use it for a handful of your podcasts to make sure your happy. And give everyone on staff a raise!
RPM building
It seems that most resources on the Internet about building RPMs are woefully out of date. If you want to unpack and work on RPM source packages in, say your home directory, most documentation points you to settings for your $HOME/.rpmrc file
Then you get errors like this:
error: bad option 'topdir' at /home/burkholp/.rpmrc:1
The use of .rpmrc is obsolete. Instead you’ll want a .rpmmacros file like the following:
%_topdir %( echo ${HOME}/rpmbuild )
%_tmppath %{_topdir}/tmp
%packager Peter Burkholder <pburkholder@pobox.com>
Tornado (but only an EF1)
On Sunday, April 20, our family joined some friends at a local indoor splash pool. We were expecting nothing but rain, rain, and more rain, and needed to get the kids good and worn out.
The boys had a great time, and had finally gotten up the gumption to go through the giant slide that started up near the facility ceiling, did a figure 8 outside, and landed with a splash into the bottom pool. We were waiting in line for our third run when I commented to Shannen that it looked like it was raining buckets outside. Just then we could see the weather going crazy, with sheets of rain slashing horizontally and the trees doing a crazy dance. I shouted to Shannen to take cover, and we were running down the stairs each with one boy when the lifeguards starting blowing on their whistles to clear the pool.
What I thought was just a severe thunderstorm was an EF1 tornado that missed us by 150 feet.
Here’s a link to local TV report on the Maryland weather. Skip the first half of the story to get to the part about the Chillum, Maryland tornado.
NATIONAL WEATHER SERVICE REPORT
MY GOOGLE MAP—I went to the splash park today to map this out. Because we left on Sunday through the front, we didn’t see what had happened out on the back parking lot. If you zoom in, you can see the outside loop of the blue tube slide:
Since we were just a few feet below the roof, I shudder to think what would’ve come of us had it been our roof that came off instead.
Apache and "shared memory" issues on Linux 2
This morning I was having trouble getting Apache (2.0.X) to restart. I was getting these error messages:
[Thu Apr 10 08:32:49 2008] [crit] (17)File exists: unable to create scoreboard "/var/private/logs/apache_runtime_status" (name-based shared memory failure)
and I kept deleting the offending file, and making sure that permissions all along the path were correct. No dice.
So I restarted Apache again running strace:
strace /usr/sbin/httpd2-prefork -X -Dprivate '-CPidFile /var/run/apache2.private.pid' -f /etc/apache2/httpd.conf
and saw output like this:
unlink("/var/private/logs/apache_runtime_status") = -1 ENOENT (No such file or directory)
open("/var/private/logs/apache_runtime_status", O_WRONLY|O_CREAT|O_EXCL, 0666) = 9
stat("/var/private/logs/apache_runtime_status", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
shmget(16908303, 40824, IPC_CREAT|IPC_EXCL|0600) = -1 EEXIST (File exists)
write(2, "[Thu Apr 10 08:18:46 2008] [crit"..., 168) = 168
Red Herring
Turns out that worrying about the filesystem was a distraction. The real issue is that the previous Apache had left behind shared memory segments that it couldn’t access anymore. Now I won’t pretend that I understand the ins and outs of shared memory on Linux, but a bit of Googling led me, fortunately to Sven Vermeulen’s blog, where he shared a similar experience on Solaris. I would’ve left nice comments on his blog, but as he doesn’t take comments, I’ll give a shout out to him here.
Anyhow, the ipcs and ipcrm commands come to the rescue:
# ipcs -a
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x0102000f 99942402 root 600 40824 0
------ Semaphore Arrays --------
key semid owner perms nsems
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00001f58 0 root 600 0 0
Ah-ha—there’s shmid at 99942402. Let’s rm that:
# ipcrm -m 99942402
# ipcs -a
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
------ Semaphore Arrays --------
key semid owner perms nsems
------ Message Queues --------
key msqid owner perms used-bytes messages
0x00001f58 0 root 600 0 0
And apache started right up. Yea.
P.S. One find out more about a shared memory segment with something like: ipcs -m -i 99942402, which will report:
Shared memory Segment shmid=99942402
uid=0 gid=0 cuid=0 cgid=0
mode=0600 access_perms=0600
bytes=40824 lpid=6987 cpid=6987 nattch=0
att_time=Thu Apr 10 08:20:48 2008
det_time=Thu Apr 10 08:21:55 2008
change_time=Thu Apr 10 08:20:48 2008
Looking up IPs with mDNS and dns-sd on Mac OS X 10.4 1
I forgot the IP address of my printer on my local area network at home.
And my Mac quite cleverly only had the mdns name in the DeviceURI, but for setting up an older Windows system I really wanted the IP. Here’s how:
- Browse for printers:
dns-sd -B _printers._tcp.. :Timestamp A/R Flags if Domain Service Type Instance Name 21:56:43.972 Add 2 7 local. _printer._tcp. Brother HL-2070N series - Lookup the service info for the printer you’ve found:
dns-sd -L "Brother HL-2070N series" _printer._tcp:21:58:30.695 Brother\032HL-2070N\032series._printer._tcp.local. can be reached at BRN-7E6301.local.:515 ... - Query on the domain name:
dns-sd -Q BRN-7E6301.local.:Timestamp A/R Flags if Name T C Rdata 21:59:52.553 Add 2 7 BRN-7E6301.local. 1 1 192.168.15.103
The reason to bother documenting this? Because the Mac Os X man page for dns-sd doesn’t document the use of the -Q switch.
Grrrrrrrrr.
Processing gzipped files with Perl IO:Uncompress 2
Idiom of the day:
use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
foreach $host ( "foo", "bar", "dev", "teset") {
foreach $site ( "public", "private" ) {
foreach $date ( "20071223", "20071224", "20071225", "20071226", "20071227", "20071228", "20071229", "20071230", "20071231", "20080101" ) {
$input="/web/$host/$site/logs/access-$date.gz";
next unless -f $input;
my $z = new IO::Uncompress::Gunzip $input or die "IO::Uncompress::Gunzip failed: $GunzipError\n";
while (<$z>) {
next unless / 200 /;
@F=split;
($URI, $therest) = split(/\?/, $F[6], 2);
# perl regex operation on the URI
}
}
}
}
Set phasers on kill
The first time I ever used a computer was the Friday after Thanksgiving, 1978, when I got to use the DEC PDP 11/70 system on the campus of Goshen College, where my Dad taught. I was immediately entranced by the power and mystery of the digital computer, and quickly hooked on trek
Today, 29 years later, I’ve found that Trek lives on, and I could obtain C-code for Mac OS X that provided an experience akin to my first experience long ago, without having to bike two miles into campus. It took me about 40 minutes to gain enough competence to win my first game by destroying four enemies.

Ruby epoch2localtime 4
I love it when 82 characters do a ton of work for me.
Today I’m trying to debug Courier-IMAP ssl errors that are reported in the log file as “DEBUG: Unexpected SSL connection shutdown”. We’re using QMail so the times in the log file are in tai64, and I’m using Eric Rescorla’s SSLDump:”http://www.rtfm.com/ssldump/” to debug the SSL traffic, which reports time in epoch seconds. I’d like to correlate the SSL traffic with the logged errors. Here’s how:
In window 1, I monitor the QMail logs with:
tail -f /var/log/qmail/imap4-ssl/current | tail64nlocal
which gives output like:
2007-10-30 06:26:02.322254500 tcpserver: status: 30/40
2007-10-30 06:26:02.322255500 tcpserver: pid 9635 from 1.2.3.4
2007-10-30 06:26:02.322257500 tcpserver: ok 9635 buzz.example.net:10.1.1.20:993 :216.220.209.17::57693
2007-10-30 06:26:02.439369500 DEBUG: Connection, ip=[1.2.3.4]
In window 2, I monitor the SSL traffic with:
sudo ssldump -e -k imap.example.com.pem port 993 | ~/bin/epoch2local.rb
where the script @epoch2local.rb is:
#!/usr/bin/ruby -p
$_.sub!(/1\d{9}/) { |t| Time.at(t.to_f).strftime("%Y-%m-%d %H:%M:%S") }
A quick dissection:
ruby -pplaces your code in awhile gest; ....; print; endloop$_is the current line.sub!does in place substitution, changing the value of$_sub!(pattern) { |match| block }the string mattingpatternis passed into the {} block as the variablematch. The result from the block is substituted for the original string/1\d{9}/: assume that a 10-digit number starting with 1 is the epoch time (true for another 30 years or so)|t| Time.at(t.to_f).strftime("%Y-%m-%d %H:%M:%S"): PFM. No, not really. Pass the match into the block ast. Convert to a float, then a Time value, then format as%Y-%m-%d %H:%M:%S
I then get SSLDump out put as:
23 21 2007-10-30 06:41:19.1945 (0.1309) C>S application_data
24 3 2007-10-30 06:41:19.2474 (0.1185) S>C Handshake
Certificate
24 4 2007-10-30 06:41:19.2474 (0.0000) S>C Handshake
ServerHelloDone
And I can match up the times with the QMail logs. Fini (although I still have the original question to resolve)
Forensic Server Project (FSP) on Unix/Macosx 5
I’ve been working with the security incident response tools on the Helix CD, and been intrigued by Harvey Carlan’s Forensic Server Project
However, the Sourceforge files for the FSP server don’t run on MacOSX or other Unix-style machines because it uses the Win32::GetCwd and Win32::SetCwd modules. The simple patch, below, can be saved as, say, “fspc.patch” in the same directory as the unzipped FSP files. To patch, run:
patch -p0 < fscp.patch
Here’s the patch:
--- fspc.pl.orig 2007-10-24 15:40:22.000000000 -0400
+++ fspc.pl 2007-10-24 16:18:09.000000000 -0400
@@ -18,6 +18,7 @@
use Digest::MD5;
use Digest::SHA1;
use Getopt::Long;
+use Cwd;
#--------------------------------------------------------------------------
# Globals
@@ -39,7 +40,7 @@
exit 1;
}
-$setup{basedir} = Win32::GetCwd();
+$setup{basedir} = getcwd();
$setup{casedir} = $config{casedir} || "cases";
$setup{casename} = $config{casename};
$setup{port} = $config{port} || 7070;
@@ -296,14 +297,14 @@
#------------------------------------------
sub _setup {
# clean up the directory names
- $setup{basedir} = $setup{basedir}."\\" unless ($setup{basedir} =~ m/\\$/);
- $setup{casedir} = $setup{casedir}."\\" unless ($setup{casedir} =~ m/\\$/);
- $setup{casename} = $setup{casename}."\\" unless ($setup{casename} =~ m/\\$/);
+ $setup{basedir} = $setup{basedir}."/" unless ($setup{basedir} =~ m/\/$/);
+ $setup{casedir} = $setup{casedir}."/" unless ($setup{casedir} =~ m/\/$/);
+ $setup{casename} = $setup{casename}."/" unless ($setup{casename} =~ m/\/$/);
my $casedir = $setup{basedir}.$setup{casedir};
mkdir $casedir if (! -e $casedir && ! -d $casedir);
my $curr_case = $casedir.$setup{casename};
- mkdir $curr_case if (! -e $curr_case && ! -d $curr_case);
- Win32::SetCwd($curr_case);
+ mkdir $curr_case if (! -e $curr_case && ! -d $curr_case);
+ chdir($curr_case);
print "Setup complete.\n" if ($config{verbose});
}
@@ -312,5 +313,5 @@
# clears setup data so it can be renewed
#------------------------------------------
sub _reset {
- Win32::SetCwd($setup{basedir});
+ chdir($setup{basedir});
}