Archive for the ‘Development’ Category

Dominical update

Sunday, March 30th, 2008

9 out of 10 open-source experts advocate frequent releases. We, the simple people, don’t know better and should listen to the experts. Sadly, we simpletons still don’t know how to read and so the fine print eludes us. While we all may be good and obedient developers, the users don’t care for our frequent releases squashing our colossus bugs and featuring our shiny new toys. As frequent our releases are as frequent the reports of bugs long ago fixed and features that shined and sparkled at ancient times but are now filled with rust.

Ghost versions of the past haunt us daily while users refuse to upgrade. Our innovative forefathers, suffering immensely from this plague, had uncovered the great potential of automatic updates. No longer is the user able to flee his ordained destiny. Fate shall pop-up and fulfill itself even with the absence of user interaction.

But even this sparsely applied method carries its own set of fine prints. Boiler plate implementation includes a web server containing the latest version number or even a server-side script that ever so nicely checks for the user whether his version is expectedly old. As with everything else, here too success brings failure. As faithful users gather their masses around our monthly-polished releases, the web server begins to break down. Most web servers, especially those that poor open-source developers can afford, do not offer load balancing and will easily succumb to the sheer amount of bandwidth generated by thousands of users performing even the simplest of GET requests.

Enter DNS. The Domain Name System is a distributed and globally cached system that basically maps domain names such as nsis.latest-version.org into numbers such as 2.36.0.0. And it gets even better — foreign sources report there are free DNS servers out there, waiting to be used. Services such as dyndns.org offer a simple HTTP based API that sets new IP to a free domain name. Creating a new version notification service is as simple as creating a new free domain, updating it every time a new version is released, calling inet_addr when the client-side loads and comparing the result to the current version.

This free and simple solution provides many advantages over conventional HTTP based version check.

  • Automatic load balancing with servers all over the world.
  • Simple code with no need for complex HTTP libraries.
  • No need for relatively heavy HTTP operations for both client and server.
  • HTTP proxies do not get in the way.
  • Firewalls and the entire security fiasco usually overlook DNS.

And as always, there are disadvantages.

  • Updates take time to propagate.
  • Only 3 bytes of information.

Make sure you set the first byte to 127 to make sure the IP associated with your update domain is invalid. This way, whoever is at 2.36.0.0 won’t get any unwelcome traffic.

I am probably not the first to think of this, but it is a cool idea nonetheless. I’m so going to implement this for the next version of NSIS! :)

Atomic codes

Saturday, June 16th, 2007

I had some fun today trying to figure out why Banner likes to hang around with .NET so much so it wouldn’t even leave. I found out that while being destroyed, something tries to send messages to the main dialog. But the main dialog is busy with destroying the banner. I added exactly two iterations of the famous win32 message loop and everything started working. I still don’t know why those messages are sent or why it’s so important they’ll be answered before the banner is destroyed or even why it happens just with the .NET installer. And don’t even ask about different synchronization methods that make it tick. So far, I’ve found only smoke signals and the fire extinguisher won’t last much longer.

Of all the signals, I liked the message loop the most. It actually points to something I’ve done wrong. I’ve starved the main dialog’s thread while creating a modeless dialog as its child. That’s why I dug in further into those two iterations of the loop and those two messages that it processes. It turns out both of them had the same identifier - 0xc0c3. Now that’s no regular WM_ message… That’s a message registered with RegisterWindowMessage. But which message is it? That’s where the fun starts. There’s no GetRegisteredWindowMessage API available and nothing on the topic comes out on Google.

So with no leads to follow I started digging. Normally, to give a certain string a specific value in Windows, an atom is created. And indeed, 0xc0c3 is in the range of named atoms. To make things even simpler, in WINE, RegisterWindowMessage simply calls GlobalAddAtom, casts ATOM to UINT and returns. Great, then GetAtomName or GlobalGetAtomName should do the trick. Only reality isn’t as bright as WINE would like us to think. It turns out RegisterWindowMessage uses a different atom table for its messages. But which atom table and how can you even specify a table with GetAtomName?

To specify a table, a low-level access to RtlLookupAtomInAtomTable is required. But that function is deep inside ntoskrnl.exe. So, up one level and you get NtUserGetAtomName which uses the same atom table as NtUserAddAtom which is the function RegisterWindowMessage calls. But that’s inside win32k.sys… Luckily, user32.dll already handles that. It has a stub that calls NtUserGetAtomName at 0×7E41FA8E. Some playing around with the second parameter which turns out to be UNICODE_STRING and the atomic table is in hands’ reach.

Engines off, coding fingers down, digging complete and the message name is MSUIM.Msg.Private. That too gets little to none results on Google, but who cares… Debugging is fun :)

For any of you who’d ever want to convert a registered message into a readable name, here’s the NSIS code. Replace 0xc0c3 with the message identifier and 0×7E41FA8E with user32!NtUserGetAtomName and you’re good to go.

# the atom
StrCpy $2 0xc0c3
;System::Call user32::RegisterWindowMessage(t'test_message')i.r2
# create UNICODE_STRING
System::Alloc 1008
Pop $R0
StrCpy $R1 0
StrCpy $R2 1000
IntOp $R3 $R0 + 8
System::Call *$R0(&i2R1,&i2R2,iR3)
# call NtUserGetAtomName
System::Call ::0x7E41FA8E(ir2,iR0)i.r1?e
# parse UNICODE_STRING
System::Call *$R0(&i2.r4,&i2.r3,w.r0)
# print details
DetailPrint "user atom's name is $0"
DetailPrint "length is $4 (???)"
DetailPrint "NtUserGetAtomName returned $1"
Pop $1
DetailPrint "GetLastError() = $1"
# done
System::Free $R0