Some notes on NDs

The other "funny" thing that we haven't yet talked about when it comes to message passing is this whole business of a "node descriptor" or just "ND" for short.

Recall that we used symbolic node names, like /net/wintermute in our examples. Under QNX 4 (the previous version of the OS before Neutrino), native networking was based on the concept of a node ID, a small integer that was unique on the network. Thus, we'd talk about "node 61," or "node 1," and this was reflected in the function calls.

Under Neutrino, all nodes are internally referred to by a 32-bit quantity, but it's not network unique! What I mean by that is that wintermute might think of spud as node descriptor number "7," while spud might think of magenta as node descriptor number "7" as well. Let me expand that to give you a better picture. This table shows some sample node descriptors that might be used by three nodes, wintermute, spud, and foobar:

Node wintermute spud foobar
wintermute 0 7 4
spud 4 0 6
foobar 5 7 0

Notice how each node's node descriptor for itself is zero. Also notice how wintermute's node descriptor for spud is "7," as is foobar's node descriptor for spud. But wintermute's node descriptor for foobar is "4" while spud's node descriptor for foobar is "6." As I said, they're not unique across the network, although they are unique on each node. You can effectively think of them as file descriptors — two processes might have the same file descriptor if they access the same file, but they might not; it just depends on who opened which file when.

Fortunately, you don't have to worry about node descriptors, for a number of reasons:

  1. Most of the off-node message passing you'll typically be doing will be through higher-level function calls (such as open(), as shown in the example above).
  2. Node descriptors are not to be cached—if you get one, you're supposed to use it immediately and then forget about it.
  3. There are library calls to convert a pathname (like /net/magenta) to a node descriptor.

To work with node descriptors, you'll want to include the file <sys/netmgr.h> because it includes a bunch of netmgr_*() functions.

You'd use the function netmgr_strtond() to convert a string into a node descriptor. Once you have this node descriptor, you'd use it immediately in the ConnectAttach() function call. Specifically, you shouldn't ever cache it in a data structure! The reason is that the native networking manager may decide to reuse it once all connections to that particular node are disconnected. So, if you got a node descriptor of "7" for /net/magenta, and you connected to it, sent a message, and then disconnected, there's a possibility that the native networking manager will return a node descriptor of "7" again for a different node.

Since node descriptors aren't unique per network, the question that arises is, "How do you pass these things around the network?" Obviously, magenta's view of what node descriptor "7" is will be radically different from wintermute's. There are two solutions here:

The first is a good general-purpose solution. The second solution is reasonably simple to use:

int
netmgr_remote_nd (int remote_nd, int local_nd);

This function takes two parameters: the remote_nd is the node descriptor of the target machine, and local_nd is the node descriptor (from the local machine's point of view) to be translated to the remote machine's point of view. The result is the node descriptor that is valid from the remote machine's point of view.

For example, let's say wintermute is our local machine. We have a node descriptor of "7" that is valid on our local machine and points to magenta. What we'd like to find out is what node descriptor magenta uses to talk to us:

int     remote_nd;
int     magenta_nd;

magenta_nd = netmgr_strtond ("/net/magenta", NULL);
printf ("Magenta's ND is %d\n", magenta_nd);
remote_nd = netmgr_remote_nd (magenta_nd, ND_LOCAL_NODE);
printf ("From magenta's point of view, we're ND %d\n",
        remote_nd);

This might print something similar to:

Magenta's ND is 7
From magenta's point of view, we're ND 4

This says that on magenta, the node descriptor "4" refers to our node. (Notice the use of the special constant ND_LOCAL_NODE, which is really zero, to indicate "this node.")

Now, recall that we said (in "Who sent the message?") that the struct _msg_info contains, among other things, two node descriptors:

struct _msg_info
{
    int     nd;
    int     srcnd;
    ...
};

We stated in the description for those two fields that:

So, for our example above, where wintermute is the local node and magenta is the remote node, when magenta sends a message to us (wintermute), we'd expect that: