next up previous contents
Next: References Up: More Example Protocols Previous: Purely Synchronous Protocol

Virtual Protocols

 

In the x-kernel, we sometimes implement modules called virtual protocols. Virtual protocols are configured into a protocol graph just like any other protocol, but they are different from regular protocols in that they do not add a header to messages; i.e., they do not directly communicate with their peer on the other machine. Instead, virtual protocols serve to ``route messages'' through the protocol graph. For example, the virtual protocol VSIZE is configured on top of some number of low-level protocols (usually two). VSIZE takes a message from some high-level protocol, and based on how big the message is (this can be determined using the x-kernel's msgLength operation), decides which of the two low-level protocols to pass the message on to. For example, VSIZE might be configured into the protocol graph to route large messages (those greater than 1KB) to BLAST, and small messages (those less than or equal to 1KB) to IP. The advantage of using a protocol like VSIZE is that it allows messages that are too small to need fragmenting from incurring the overhead of yet another protocol layer.

The following shows VSIZE's open routine. The main thing to notice about vsizeOpen is that it passes the hlpType it was given from above as the hlpType to the protocol below it, rather than using self. This is because VSIZE wants to intercept all of the higher-level protocol's messages, and it has no header of its own to stick this protocol's demux key in.

static Sessn
vsizeOpen(Protl self, Protl hlp, Protl hlpType, Part *p)
{
    Sessn  s;
    Sessn  lls[VSIZEMAXDOWN];
    Part   savedPart[3];
    PSTATE *pstate = (PSTATE *)self->state;
    int    plen;
    int    i,j;

    /*
     * Save the original participants before opening since we need to
     * use it in both opens and it will get munged in the first open
     */
    plen = partLength(p) * sizeof(Part);
    bcopy((char *)p, (char *)savedPart, plen);

    for (i = 0; i < pstate->numdown; i++) {
        lls[i] = xOpen(self, hlpType, xGetProtlDown(self, i), p);
        if (lls[i] == ERR_SESSN) {
            /* could not open session */
            for (j = 0; j < i; j++)
                xClose(lls[j]);
            return ERR_SESSN;
        }
        bcopy((char *)savedPart, (char *)p, plen);
    }
    if (mapResolve(pstate->activeMap, lls, (void **)&s) == XK_SUCCESS) {
        /* found an existing session */
        for (i = 0; i < pstate->numdown; i++)
            xClose(lls[i]);
    }
    else {
        /* creating a new session */
        if ((s = vsizeCreateSessn(self, hlp, hlpType, lls)) == ERR_SESSN) {
            for (i = 0; i < pstate->numdown; i++)
                xClose(lls[i]);
        }
    }
    return s;
}

VSIZE's push routine is very simple---it checks the size of the message pushed to it, and calls the appropriate session below it. The code for vsizePush follows.

static XkHandle
vsizePush(Sessn s, Msg *msg)
{
    SSTATE *sstate;
    int    i;

    sstate = (SSTATE *)s->state;
    for (i = 0; i < sstate->numdown-1; i++) {
        if (msgLength(msg) <= sstate->cutoff[i])
            return xPush(xGetSessnDown(s, i), msg);
    }
    return xPush(xGetSessnDown(s, sstate->numdown-1), msg);
}



Larry Peterson
Wed Feb 21 13:58:06 MST 1996