Sunday, May 25, 2008

Home, Sweet New Home

Throughout the last 7 years or so, I've been living in a small apartment approx. 40 minutes by feet from downtown Linz. Several months ago, I was fortunate enough to find a more spacious replacement right in downtown Linz, only minutes away from (almost) everything you can think of. Additionally, it's situated next to a gas station that's open for business on a 24/7 basis, a rare comfort in European countries. So, should my supply of Red Bull (I can't help myself) come to an end at 4:46am in the course of a programming spree, I can resort to my backup next door :)

After two weeks of moving essentials and most other things, it's finally done. I'm positive that my new home will give me a a general boost, definitely so. It might also help me to establish a routine morning run before work, a nice 6 km waterside course only meters away is waiting to be challenged...

The living room is not ready yet. Nonetheless, being a technology enthusiast, indispensable subtle technology references are already in place ;)



P.S.: The UNIX license plate can be obtained from The Open Group online store. I once owned a Digital UNIX / Compaq Tru64 UNIX plate, an adaption of the original. At that time I was an Alpha / Tru64 advocate and user. As always, nothing can replace the original...

Saturday, May 3, 2008

Cisco VPN Client on Leopard 10.5.2

Just a quick note for those of you struggling with Cisco's VPN client on Leopard, Mac OS X 10.5.2. My initial attempt was based on client version 4.9.0.0.50. The result was the following error message indicating that no active network interfaces are available:

Error 51: Unable to communicate with the VPN subsystem.
Please make sure that you have at least one network interface that is currently active and has an IP address and start this application again.


Needless to say, that was a false statement. So I updated to 4.9.0.1.80, that didn't fix the issue. What fixed it was a minor upgrade to build 100, version 4.9.0.1.100, the VPN connection has become fully functional from there.

The essence is: With Leopard 10.5.2, use 4.9.0.1.100.

How do you share your runs? Do you?

I don't. My current solution for logging runs is a Windows-based software called SportsTracks. It supports the basic set of per-workout metadata as well as input from devices such as a heart rate monitor or GPS receiver. I use Garmin's Forerunner 305 to record workaround duration, distance, heart rate and course, the import works like a charm. Additionally, SportsTracks provides you with an extensive toolkit for analyzing individual workouts by means of statistics and interactive charts, and generating reports covering multiple workouts. What I love about workouts is the logging ritual. Logging a new run after a hard workout and browsing through the data that was silently recorded throughout the last minutes or more likely hours, that's something I really enjoy. I'm obsessed with my distance totals too ;) That left aside this facility serves as kind of a virtual trainer that can actually provide objective feedback...

I have two problems with my current solution. One, SportsTracks is Windows-based and will probably never run on Linux or Mac OS X. My current system runs on Mac OS X, so I have to fall back to a Windows system to import my new workouts and analyze my progress. SportsTracks used .NET, thus, the chances of a Linux or Mac OS X version are practically non-existent. I don't want to go the virtual machine route, not for one application.

Two, and more importantly, there's no easy way to share all data of my past runs via the internet. Yes, I know - not true. What you can do is export maps and workout data as HTML, an automatic upload via FTP can be triggered as well. Right, my idea of sharing my runs though is to provide visitors with an experience that is similar to SportsTracks. For example, with every new run, I can easily check new distance totals in SportsTracks. In the case of per-workout exports, these totals are not available. Another aspect is interactivity with tables and charts, static images are of course limited to a single view of data.

I guess, I'm looking for some kind of service that provides runners with an easy way of sharing workout data and visitors with a clean yet feature-rich interface for browsing through the shared data. Nike+ provides a nice interface that goes into the right direction. Understandably, it only supports Nike+ input (which is why I had to manually migrate run-by-run from Nike+ to SportsTracks when I switched to the Forerunner :/ ). It fails in respect to sharing though, there's no way I know of to share all runs as opposed to a single selected run.

So, my fellow runners: How do you share your runs? Do you share them at all?

Sunday, April 27, 2008

A first: 26.2 km

I'm not yet sure about my next race goal - half-marathon or marathon - but I still decided to try a new distance which can be helpful in either case (thinking overdistance training). Before yesterday, my longest run had been the half-marathon distance, around 21 km. After the first 11 km of my run, I committed to a distance of 26 km, which required me to turn around after the initial 13 km (I toyed with a goal of 28 km, didn't want to push too hard though).

The first 21 km had been relatively easy, the last 5 km however were very difficult and continually prompted me to give up and be satisfied with the half-marathon distance. The energy was still there, my legs were killing me though, I already saw cramps coming (although that never happened). After 26.2 km and around 3 hours of non-stop running (or jogging), I finished the workaround and managed to reach the goal of completing 26 km, quite satisfying indeed :)

This workout provided me with a foretaste of what to expect throughout a marathon and definitely made me appreciate the challenge of 1) finishing a marathon and 2) doing so in a reasonable time, more than ever before. I knew it wouldn't be easy, but quite frankly I didn't expect 5 km more to become much of a problem.

My previous training strategy was to run new distances for as long as they represent a major obstacle, so I'll do more 26 km workouts throughout the next weeks until I can safely say that I master the distance.
Thereafter, the next milestone might be the dreaded 32 km mark - where a marathon is said to begin and work against the runner. We'll see about that :)


Sunday, April 13, 2008

OMV Linz Marathon 2008

I've been running for more than a year now, with around 1,100 completed kilometers. I don't know why I had decided to start running in the first place, what I do know is that this was one of the best decisions of my life. Being a stressed-out software engineer, I enjoy the relaxation and energy boost running brings along, it's also the simplest (run anytime, anywhere) and least expensive workout possible.

My racing debut was the "Linzer Sparkassen Citylauf 2007", a half-marathon. In contrast to today, I was less prepared for the race as well as the pace required to complete it in a satisfying time, the result was 02:16:46. I completed the first 10k in around 57 minutes, however, I was forced to slow down during the second half because my energy depot was practically empty. 

Today, 6 month after my HM debut, I participated in the "OMV Linz Marathon 2008", my competition of choice was once again the half-marathon. I was unsure about participation because f a foot injury I contracted one week ago during training. During a 5k test run yesterday, the injury was fine during the beginning, but was clearly noticeable in the end. Today morning, one hour before the race, I was in doubt about participating as my foot got worse. Nevertheless, I decided to pull through!

At 9:15 am, the raced started on a freeway bridge with around 14,000 participants. My intention was to finish before the two-hour mark, my training was based on a plan from Herbert Steffny for 1:59:00. To ensure a steady and adequate pace, I was using the Garmin Forerunner 305, which not only records the course via GPS, it also provides an instant pace average that is accurate enough for relying on it during the race.




The first 19k were comparably easy, way easier than last time as well as during training runs and way faster than ever before. I completed the 10k in around 57 minutes and still had a chance to easily finish within the first 2 hours. Between 19k and 21k, I increased my pace to make sure I wouldn't miss my goal. The "hammer-man" tried to intervene at that point, however, I managed to maintain the pace (around 5:00) while heading towards the finish line. It's true, the cheering audience does help quite a lot. I passed the finish line with an official net time of 01:57:35, slightly better than expected and with relatively little effort during the first 19k. I was very satisfied with the result, particularly considering my injury, which could have completely thwarted my plans!

Paricipating in a race amongst 14,000 fellow runners was a fantastic experience, finishing in 01:57:35 was excellent and exceeded my expectations for the day. In contrast to last year, I took carbo-loading seriously this time. On a retrospective note, I think the full depot of carbo-hydrates enabled my effortless run until the 19k mark, it clearly showed.

It's always interesting to analyze the race by means of the data recorded by Forerunner. My average pace was 05:30. While I did not plan for it, I managed a negative split - the second half page average was slightly higher than the first. Here's a chart covering pace and heart rate during the race:


The following image shows the course based on GPS data:


The OMV Linz Marathon was excellent, I thoroughly enjoyed every second (well, almost ;) ) and will take part again next year unless another, more interesting event turns up.

Only one open question remains for the next event:
new half-marathon goal OR marathon?

Thursday, April 10, 2008

Don't throw your Macbook Air out just yet, let there be silence

I've been waiting for my personal Macbook Air for around two weeks and could not wait to get hold of that machine extraordinaire. I expected to receive a notebook that is well-manufactured and manages to combine a minimalistic and elegant design with a solid level of performance.

I loved my new main computer - my Air - from the very beginning (yes, m-a-i-n computer, I know I'm crazy ;) ). Unfortunately, my enthusiasm faded after 1 hour of working with the default OS X installation. A Macbook Air is a beautiful machine, but I also expected it to be beautifully silent during "normal use". Well, much to my regret, it was not! Whenever the CPU load increased moderately (e.g. due to watching a YouTube video) and lasted for longer periods of time, the Air increased the fan speed to the factory maximum of 6200 rpm. At 6200, the buzz of the Air's fan can be incredibly annoying, particularly if you're sensitive to fan noise. At 2500 rpm, the fan is practically unnoticeable - the Air's pretty aggressive about cooling though, so, these low levels are rare in the non-idle-case.

My research lead me to believe that this NOT an issue affecting my Air in particular, it's behavior by design. Lots of Air owners seem to be annoyed by the fan noise, none of them have found satisfying workarounds and some even returned their Airs or got them replaced in hope for a "working" unit.

Rather than returning the Air or requesting a replacement to fix the issue, I investigated further and tried various ways to bring silence to the otherwise flawless and fascinating Air experience. I experimented with different energy saving configurations, software for controlling the fan rpm minimum as well as CPU voltage and frequency and also changed OS X kernel module configurations to alter the fan behavior. While all of these had noticeable effects on the situation, none of them prevented the fan controller from increasing revolutions to the maximum of 6200.
The fan is controlled by the so-called System Management Controller (SMC). Software allows you to modify the rpm minimum, that however could not solve the issue. Apple now provides an SMC firmware update that affects fan control. According to the release notes, this update could potentially worsen the situation because it apparently tries to lower CPU temperature further to avoid hangs and unexpected shutdown (of a single core and/or the whole system). I tried the update, it didn't have any noticeable effect in either direction.

Despite the 6200 rpm targeted by SMC, CPU temperature levels remain in a perfectly safe region (60 - 70 °C) at all times. So, knowing that the rpm increase is unjustified in respect to temperature levels, I changed the rpm minimum to 4500 and 6200. In respect to CPU temperature at 100% CPU utilization, the temperature diff between 4500 (maximum acceptable level that can be considered comfortable) and 6200 rpm is pretty much insignificant. Knowing that, my goal was to redefine the rpm maximum to fully address the issue at stake. I was unable to find any way to do that during the first round of research. Most utilities, including SMC Fan Control, merely allow you to change the minimum. As it turns out though, that software package provides a console application smc that can be used to changed all writable SMC parameters, not just the rpm minimum. With the help of the source of a Linux kernel driver controlling the fan via SMC, I identified the key representing the SMC parameter controlling the rpm maximum and gave the new maximum a try by executing smc as follows:

smc -k -F0Mx -w $(python -c 'print hex(4500 << 2)[:2]')

Additionally, I reset the minimum to 1500 to conserve the fan at CPU idle levels:

smc -k -F0Mn -w $(python -c 'print hex(1500 << 2)[:2]')

These commands only change minimum and maximum, revolutions still remain in control of SMC. The results have been fantastic, the Air has been quiet and cool ever since enforcing the new limits. Execute these commands in a startup item to make changes permanent (for the sleep / wakeup case, use SleepWatcher).


Now, I can finally say that it is a real pleasure to work with this elegant and capable notebook, I enjoy every minute of doing so. I strongly encourage you to give this workaround a try before throwing the Air out (at your own risk), you definitely miss something!

Monday, May 14, 2007

Getting Subversion (neon) to work with Kerberos on SLES10

Just in case you were wondering why Subversion fails to authenticate against an Apache-based, Kerberos-enabled Subversion repository on SuSE Linux Enterprise Server 10...

$ svn info https://host/path/to/repository
svn: PROPFIND request failed on '/path/to/repository'
svn: PROPFIND of '/path/to/repository': authorization failed (https://host)

For one, SuSE packages a build of neon, the HTTP / WebDAV library the Subversion client uses, that was not configured with Kerberos support:

$ ldd /usr/lib64/libneon.so.24.0.7
libssl.so.0.9.8 => /usr/lib64/libssl.so.0.9.8 (0x00002b5f0548b000)
libcrypto.so.0.9.8 => /usr/lib64/libcrypto.so.0.9.8 (0x00002b5f055d1000)
libz.so.1 => /lib64/libz.so.1 (0x00002b5f05834000)
libexpat.so.1 => /usr/lib64/libexpat.so.1 (0x00002b5f05949000)
libc.so.6 => /lib64/libc.so.6 (0x00002b5f05a6c000)
libdl.so.2 => /lib64/libdl.so.2 (0x00002b5f05c9c000)
/lib64/ld-linux-x86-64.so.2 (0x0000555555554000)

So, by installing the neon source RPM, krb5-devel-1.4.3-19.10.3 and rebuilding the RPM using rpmbuild -bb SPECS/krb5.spec, problem #1 can be solved. Wait, the story isn't over yet.

The situation remains unchanged despite a Kerberos-enabled build:

$ svn info https://host/path/to/repository
svn: PROPFIND request failed on '/path/to/repository'
svn: PROPFIND of '/path/to/repository': authorization failed (https://host)

By enabling neon tracing (by modifying the Subversion 'servers' configuration) and adding additional traces, I found out that gss_init_sec_context fails with GSSAPI major and minor:

No context has been established. Validation error

I checked the Kerberos source:

/usr/src/packages/SOURCES/krb5-1.4.3/src/lib/gssapi/krb5/duplicate_name.c:

...
static OM_uint32
mutual_auth(
OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
gss_name_t target_name,
gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_OID *actual_mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
krb5_context context)
{
...
/* validate the context handle */
/*SUPPRESS 29*/
if (! kg_validate_ctx_id(*context_handle)) {
*minor_status = (OM_uint32) G_VALIDATE_FAILED;
return(GSS_S_NO_CONTEXT);
}


There's the problem. gss_init_sec_context validates the input context handle, the validation fails. Looking at the neon source, the bug is obvious:

/usr/src/packages/SOURCES/neon-0.24.7/src/ne_auth.c:

static int
gssapi_challenge(auth_session *sess, struct auth_challenge *parms)
{
...
gss_ctx_id_t context;
gss_name_t server_name;
unsigned int major_status, minor_status;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

clean_session(sess);


if (get_gss_name(&server_name, sess))
return -1;

major_status = gss_init_sec_context(&minor_status,
GSS_C_NO_CREDENTIAL,
&context,
server_name,
GSS_C_NO_OID,
0,
GSS_C_INDEFINITE,
GSS_C_NO_CHANNEL_BINDINGS,
&input_token,
NULL,
&output_token,
NULL,
NULL);

The neon developers forgot to initialize the local variable context with GSS_C_NO_CONTEXT, d'oh...
Apply the following patch to address this:

neon-0.24.7-krb5-auth.patch:

--- neon-0.24.7/src/ne_auth.c 2004-07-05 11:45:42.000000000 +0200
+++ neon-0.24.7-dev/src/ne_auth.c 2007-05-11 22:45:28.000000000 +0200
@@ -343,7 +343,7 @@
static int
gssapi_challenge(auth_session *sess, struct auth_challenge *parms)
{
- gss_ctx_id_t context;
+ gss_ctx_id_t context = GSS_C_NO_CONTEXT;
gss_name_t server_name;
unsigned int major_status, minor_status;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
@@ -924,15 +924,13 @@
success = 0;

#ifdef HAVE_GSSAPI

Quick Summary:

rpm -ihv neon-devel-0.24.7-20.2..rpm
rpm -ihv krb5-devel-1.4.3-19.2..rpm
Apply the aforementioned patch using patch -p1

It's official: nobody's using Kerberos. OK, just the SLES QA guys ain't... ;)

Nobody's in need of a re-entrant Kerberos 5, why?

IMHO, the Kerberos protocol is the solution for implementing Single-Sign-On (SSO), at least in the context of corporate intranets. Kerberos is practically the only solution available for SSO in a heterogenous computing environment comprised of different operating systems including UNIX variants and Windows. The only time a user ever has to provide a password is during the initial logon on a workstation. The credentials obtained can be passed to specific services and, more importantly, Kerberos allows delegation so that user credentials can be passed from the workstation via service A to service B, for example. Sure, several other SSO implementations exist but, to my knowledge, none of then can offer of the level of transparency and platform-coverage Kerberos can.

There's a catch however, Kerberos 5 implementations available for Linux / UNIX are not re-entrant and thus cannot be used in multi-threaded applications without serializing all code paths accessing the Kerberos API. The main Kerberos implementation I primarily refer to here is MIT Kerberos, the original implementation, Heimdal and friends shouldn't make any difference here however when it comes to a thread-safe implementation. Thinking about it, I haven't reviewed the Java GSSAPI source yet but my guess is that calls are serialized in the JNI part of the library to make sure that Java clients can safely use it across threads.

It might be hard to believe but, for once, Microsoft has managed to create something that is superior to Linux / UNIX equivalents (to be fair, there are other exceptions as well): The Microsoft Windows Kerberos implementation is fully re-entrant. Doesn't come as a surprise to me because Microsoft simply couldn't afford to provide an API that isn't - at last, Windows itself and practically all applications and services are inherently multi-threaded. In my opinion, that is exactly the reason why there's no re-entrant MIT Kerberos available on Linux / UNIX: Except for most GUI applications, common daemons are single-threaded and use a process model instead that often is fork(2) driven:

  • sendmail
  • pop3d / imapd variants
  • sshd
  • ntpd
  • Samba
  • PostgreSQL
  • Apache 1.3 and earlier
  • ...
So, in most cases, the lack of a re-entrant Kerberos implementation is not at all an issue. As a result, the current demand for it doesn't cause that issue to land on the project's TODO list. New implementations and more modern service implementations like Apache 2.0 and later (MPM = {worker|event}) and MySQL are fully multi-threaded, and, once Kerberos support comes into play, would have a problem or at least would need more time to implement Kerberos support (because of the locking business).

Granted, the number of installations dealing with multi-threaded applications (a small subset already) as well as Kerberos (in most cases, it's only an issue for medium to large-scale installations) is not exactly substantial - not substantial enough for supporting the refactoring of existing implementations towards re-entrance. This is a strong case of a minority being discriminated against, please spread the word to make a difference ;)

Seriously, in the Linux / UNIX world, there's currently no satisfactory solution available because even those saying that serialization solves it all are mistaken. Consider a large-scale Kerberos-enabled application using Apache as an interface to application users. In each application module, Kerberos may be used and calls must be synchronized. However, that's easier said than done because that synchronization must include all modules, it must span the whole process to solve this issue. If modules originate from more than one project or vendor, you've lost already - process-wide synchronization would require an agreement across all modules on the means of synchronization. If all modules are controlled by a single project or vendor and/or the source is available for those that are controlled by a different group, re-entrance can be established using a consistent locking protocol (e.g. by providing access to a single, process-wide mutex that is owned by a module all other modules have access to). Otherwise, there's practically no way to work around the lack of re-entrance (except for maybe preloading a library implementing Kerberos symbols that basically wraps all externals and serializes access or rolling your own release based on an open source Kerberos implementation).

You see, this dilemma is nerve-wracking because there's no satisfactory solution. Most likely, several more years will have to pass (where more multi-threaded daemons can emerge and require multi-threaded Kerberos implementations) until this problem will be solved with the availability of a re-entrant implementation...

How do you cope with Kerberos and thread-safety on Linux / UNIX platforms?

Sunday, May 13, 2007

Panting for air on the 4th floor - not anymore

When you go to work, walk up the stairs to the 4th floor and end up panting for air, then, at the latest, you know that the workout comprised of writing lines of code throughout the day - I'm a software developer - is not enough, much to my surprise :) Ever since day 1 of my existence, I've never gone in for sports, the exception being mandatory sports classes during high school, which hardly count. April 2nd, I started to run out of the blue, I simply felt like running - run Horst, run...

Of course, I couldn't have done it without some sort of interesting equipment. For one, I am running in Nike Free's. I bought my first pair around a year ago and the experience was mind-blowing, at least for me. It is said to be like walking or running barefoot. Certainly, it isn't but it comes close. That is what makes the Free a perfect (though expensive) shoe for everyday use, that's what I've been using it before April 2nd. When running, the special properties are particularly beneficial.
Second, I am using my iPod (including Nike+iPod) to record my runs (pace, distance, duration, ...) and keep me entertained. The first aspect is very convenient because the training log writes itself and always contains relatively accurate information on the individual runs (for example, I don't have to estimate the distance myself using Google Maps). More on that later...

So far, I haven't stopped, I'm trying to gradually increase distance and frequency. Since April 2nd, I've been running 155.73 km (you know, that crazy unit equally crazy Europeans are known to think in). It's quite easy to keep going, even for a software developer, because these workouts tend to become addictive (just like hacking the Linux Kernel, but that's a different story ;) ).

As for "panting for air on the 4th floor", well, it's getting much easier already but it's only been 1 1/2 months so far, so there's loads of room for improvement...