Wake up Ian.

If the client generates thread IDs, then the client can ensure uniqueness, can't he? Which means you don't have to include the controller JID in inter-document messages and IQs, do we?



Je répète

If it was simple, it would be boring.
If it wasn't elegant, it would be wrong.
That said, we must adapt to the terrain, hence all this:

OK, so the solution to the below is 3 and 4. 3 for inter-document comms, 4 for doc->JID comms. This means modifying the client-side routing to allow multiple threads per JID. No problemo, we move the JID identity check for controller JIDs from right at the top to right at the bottom of the routing decision tree. Neither is happy, both are ugly, I will replace them if I find something better.

Issue number two is kind've a funny one. Before we used to do document loading via XMPP, which was a bad idea, to put it mildly. Now, we do it via HTTP, and a namespaced element in the document tells the canvas to send a message to a JID with the URL and the generated thread ID.

This means we don't have to do queuing packets for unloaded documents, which is a bit of a relief (although I only figured this out after I rewrote the routing code to allow multiple 'routing tables' to be used in the same router, which is nice logic separation but needn't have been done.)

However, now the SVG "onload" event is triggered before the UpdateManager is started, meaning that we could be sending stanzas before we've let the server know our thread ID, which is obviously not cool. The solution to this is to move the XMPP networking code into documentLoadingCompleted(), which is called after the document is loaded and blocks the thread that triggers the ECMAScript onload/script & interpreter initialization code, which is what we want.

This means that although we won't be sending stanzas with a thread ID we haven't declared, we can now receive directives and stanzas for the document before we have the thread we should be executing the events and running the directives in.

What this means is that we need to keep the packets for this canvas to one side while we add the packet router as an UpdateManagerListener to the canvas, wait for the event to fire, walk our way back the reference tree (or keep an internal Map) and then start processing packets.

Which is basically what I was doing back when I sent and received documents over XMPP, because it's semantically equivalent to queuing packets for unloaded documents. Funny how things work out.


Annoyingly complicated conundrums.

So, the next version of Gradient is going to loosen up a bit and allow for XMPP traffic between loaded documents, as well as between documents and the server they were loaded from.

Each document is identified to the XMPP network by three things:
  • The JID contained in the namespaced XML element that specifies the "controller" for this document
  • The full URL that the document was loaded from.
  • The thread ID assigned to the document by the server.
The thread ID is basically a unique identifier for the document, and a shared secret between the client and the server. When messages or IQs meant for one document alone are sent to the client, they use the thread ID to specify which document.

So how do third parties, such as other clients, interact with documents via XMPP? Well, they have to identify the target document in their stanzas. How do they do this? Using the thread ID. Points to note:

  • Either the client or the server has to share the thread ID with the third party in order for this to happen
  • Stanzas that arrive from non-controller JIDs are treated differently than controller-originating stanzas:
    • They cannot modify the document using directives.
    • They trigger different events in the DOM environment.
If the server sends an IQ to a document, the function processIQ(elements, type) is called (if declared). If anyone else sends the document an IQ, the function processForeignIQ(from, elements, type) is called. This ensures that malicious JIDs can't mess around inside of code points/decision trees/logic meant to be used exclusively by the server, unless you explicitly allow it by doing something like this, which is brain-dead from a security point of view:

function processForeignIQ(from, elements, type) {
processIQ(elements, type);

function processIQ(elements, type) {
//now we're not just dealing with IQs from the server here!

But I digress. The point is that the thread ID is guaranteed to be unique between two JIDs (client and server) as per the RFC - any other behaviour is breaking the spec. However, the thread ID cannot be guaranteed unique across all threads with all servers - i.e. it's possible to have different conversations with two different JIDs, each with thread ID "123".

This means we cannot simply specify the target thread ID on a third-party stanza meant for a document loaded from a different JID. Thread collisions become possible.

At least three options immediately came to mind:
  1. Ignore this design flaw. A bad idea on principle.

  2. Break the spec and put the JID in the thread ID. Also a bad idea on principle, and just plain braindead. NO.

  3. Require inter-document XMPP stanzas to specify the document controller JID. This is annoyingly complicated, and precludes third-party JIDs from broadcasting stanzas to documents who ask for it, regardless of their controller.
Another problem with all the above solutions is that sharing the client-server thread ID could possibly open the model to side-channel attacks, and have other unforeseen consequences on the security model.

  1. Require the document to initiate communication to third-party JIDs, by sending a message or IQ with the new thread specified. The thread could be the same as the server-client thread, but that's up to the script running on the client.
The problem with this is that it then becomes impossible for a document to initiate a conversation with another document with identical behaviour. That limits third-party nodes to a server-like role, and prevents inter-document (i.e. p2p) communication.



Problem #1:

I enjoy coding, but for each hour spent creating, rewriting or refactoring, I have to spend another hour or two testing the changed code before I have any confidence in it.

I suspect this is why coders become software architects.

Oh well.


For the record:

  1. I re-iterate this advice.
  2. Half-life 2 does rock.
  3. The most exquisite torture device known to man is woman.
  4. Seamlessly opening arbitrary file types with the correct program in Java on Windows is stupidly annoying. This is the Mac version:
    * @author Frederik Zimmer

    public class MacOSXFileLauncher extends AbstractFileLauncher {
    public void launchFile(File file) throws IOException {
    new String[] { "open", file.getCanonicalPath() });
    And this is the Windows version, accessed via JNI:

    JNIEXPORT jint JNICALL Java_ziga_util_WindowsFileLauncher_launchFile
    (JNIEnv *pEnv, jobject, jstring filepath) {

    int length = pEnv->GetStringLength(filepath);
    const jchar* jcstr = pEnv->GetStringChars(filepath, 0);
    char* cFilepath = (char*) malloc(length*2+1);
    int size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) jcstr, length, cFilepath, (length*2+1), NULL, NULL);
    cFilepath[size] = 0;
    pEnv->ReleaseStringChars(filepath, jcstr);

    HINSTANCE returnCode = ShellExecute(NULL, "open", cFilepath, NULL, NULL, SW_SHOWNORMAL);

    return (jint) returnCode;

    I rest my case.


One two three four, I declare...

Well, that didn't take long. As usual, NTK was ahead of the crowd.

For some reason I'd been thinking more highly of Microsoft recently. Probably because they have a more human face now - I have a greater respect for Scoble and C4L than Ballmer or Allchin. Sadly it looks like I'm going to be proven wrong about the company.

On the bright side, THANK YOU POLAND! We may yet get an EU directive that embodies the principles that the Parliament voted for, instead of the 'principles' that the gentlemen at the Commision tried to present as a fait accompli.

Software patents delenda est.


Anthropology meets economics

Edward Castronova continues his good work with the study of virtual economies, and what that tells us about real people, and economies that would still exist even if people didn't have far too much spare time and money.

Money laundering though virtual economies is something that was first suggested by Rusty on K5, and I've toyed with it a little since then. The basic problem is that each universe is too small to avoid distorting markets and bell curves when washing appreciable sums at an acceptable rate. The answer to this is per-game and eBay bots, or sweatshops MMPORGers.

Running an item-generation sweatshop would be perfect cover for this kinda thing.

Aside from my nefarious musings, what I'd like to see is an inter-game object description and exchange protocol. Having a +10 Vorpal sword in a sci-fi space-combat/trading MMPORG wouldn't give you many tactical advantages against entry-level plasma cannons, but it would retain some monetary value, modulo normal item depreciation. Also, as an antique, you could decorate your office with it.

The challenges are as follows:

1) The various providers (MS, Verant, Blizzard, etc.) all have a lot of proprietary stuff locked up in their respective knowledge/skill bases, and their own way of doing things like e.g. disbursing currency.

They don't want to share the "unique" knowledge they've built up over the years, despite the redundancy of MMPORG-running/administration talent within EA, MS, Verant and Sony being a tremendous duplication of effort, and a waste of time & money, not a competitive advantage.

Every piece of code that even approaches protocol-level interop with an MMPORG is stamped on, hard, with the +5 DMCA Jackboot of Stomping. Getting these people to co-operate on something that increases fluidity for a player transitioning to a competitor would be practically impossible.

2) Each provider uses their TOS to maintain the legal fiction that in-game objects are worthless. Of course, anyone with eyes in their head can see currency, real estate and commodities being traded on eBay. If 'worthless' in-game items are not being traded on eBay, then the game is dead in the water, doomed, lifeless.

The providers force this acceptance of worthlessness on users for two reasons.

2.a) They don't want to become liable for inventory, or for in-game fraud, etc. If $1M worth of imaginary items are being traded every day in EQ, a day's downtime suddenly becomes roughly as important as disruption to a small stockmarket. They'd get sued for dupeing bugs. If God was a legal entity, just like a large corporation, then lawyers would be suing him on behalf of people who think they got a bad deal out of real life, unless he asked each newborn baby to click yes on an EULA.

2.b) An acknowledgment of value for in-game cash means that there's a legal requirement that it be regulated like any other "non-cash means of payment". See the proposed EU directive, which almost definitely has UN and DoJ equivalents, and which would have been applicable to MMPORG currencies regardless in one of the early drafts, before someone fixed that.

3) Blizzard is no more likely to allow a WoW user to transition to EQ2 than MS would allow a Passport-totin' MSN IM user to transition to AIM.

Lock-in is still a fact of life in MMPORGs as it is in IM and other areas in IT, because established players have no interest in becoming the infrastructure and platform upon which a next-generation of players can disrupt or destroy markets at their expense.

What I mean is this: imagine that you could move your character between MMPORGs, or sell real-estate in UO to characters in EQ. Imagine that the money/credits you earn or make or win in your game could be kept in banks unafilliated with any in-game universe, or invested in shares of clans or guilds in other games, or used to play on the Forex markets with gold pieces and beryllium credits, or whatever.

This is the kinda thing that could happen if MMPORG providers loosened up a bit, and let money and property flow in between these systems. MS, Verant and Blizzard could find themselves running a confederation of systems hosting virtual worlds whose 'populace' would have a GDP comparable to that of a normal western country, instead of the half-dozen equivalents to Namibia that they have right now. That's a license to print money, compared to which owning a casino would be small change.

Lock-in prevents this from happening.

Other reasons this remains a distant dream are the real-world hurdles. For example, there's nobody who can get all these players at the same table. Also, as soon as virtual currencies become big enough, governments will insist on them being regulated just like normal currencies, and therefore declared and taxed, even if the user signs the "worthless" TOS.

Despite all this, I still think that contiguous 3D net-based realities are more likely to grow out of MMPORGs than anywhere else. We shall see.


To re-iterate:

I've said it before, I'll say it again: John Perry Barlow is very smart, and a bit nuts, and has a triple-A grade blog.

Must. Code.



I recommend:

SomaFM. Beat Blender, in particular.

Thought of the day: I discovered a remote SQL-injection/XSS bug in a product I work with this week. (Not related to the below story, I assure you.) What surprises me in retrospect is that (a) I should have seen this 2 years ago, (b) the speed at which it was fixed - (2 days to patch - impressive!) , and (c) It was so obvious. It was hiding in plain sight.

Other stuff: GoogleBrowser is incredible. And, everywhere displays should, if there's any justice in the world, catch on like wildfire.

How dumb can you GET?

A co-worker told me about a site he came across that executed SQL select clauses that were passed as parameters to an HTTP request. We now have an answer to the question posed above.

The webmonkey who did that was quite obviously as thick as a post. No head between his shoulders. A few chunks short of a transfer. A 206, who 408's on everything you put to him. Accept: text/html; q=0.1, text/sql; q=0.1.

And has hardly any security considerations.

(OK, I'll stop now.)


Yay, new server

So now I go through the whole init.d thing, re-fiddle with mail servers etc. etc. It seems to me you can have: cheap, reliable and flexible, but a pain to administer (Linux, even with Webmin), or: expensive, PIA, single-vendor, a breeze to "administer", (Windows).

Sigh. I'm not sure I have time for this.