TOC 
SpaceKit Documentation SeriesB. Burdick
 Invisible Worlds, Inc.
 April 2000

Blocks SpaceKit for Perl

Abstract

The Blocks SpaceKit for Perl is a software development kit that implements the Blocks eXtensible eXchange Protocol (BXXP[1]) in Perl. The SpaceKit provides tools to access existing Blocks servers as well as providing a framework for developing Blocks clients and servers using Perl.

To subscribe to the Blocks discussion list, send e-mail; there is also a developers' site.



 TOC 

Table of Contents




 TOC 

1. What Do I Need To Use The Blocks SpaceKit For Perl?

SpaceKit requirements:

Perl version 5.004 or later.

Additional Perl modules required by the SpaceKit include:

Additional Perl modules required by the SpaceKit client and server example applications:

All of the above modules should be available from your nearest CPAN site.

1.1 Additional Documentation

Additional documentation on the Blocks protocol is available at:

http://xml.resource.org/profiles/BXXP/bxxp.html[1]

http://xml.resource.org/profiles/SEP/sep.html[2]



 TOC 

2. Example Client Applications

Example client applications are located in the top-level examples/client directory.

2.1 Blocks Information Groper (big.pl)

Implements the basic client (mixer) interface. The search, fetch, and store mixer operations are supported.

2.1.1 Search Operation

Returns a list of valid "name" attributes (e.g., "doc.rfc.2629") matching the search criteria. These names are suitable as arguments to the fetch operation.


% perl big.pl -server sqa.invisible.net search "<union><intersect><compare subtree='doc.rfc' operator='contains' caseSensitive='false'><path><element property='email' /></path><value>mrose@</value></compare></intersect></union>"
doc.rfc.2629

See SEP[2] for further details on the set-union specification used by the search operation.

2.1.2 Fetch Operation

Fetch the contents of the specified block to standard output.


% perl big.pl -server sqa.invisible.net fetch doc.rfc.2629
<rfc serial="2" name="doc.rfc.2629">
<rfc.props number="2629" category="info" relativeSize="46132"></rfc.props>
<doc.props>
<doc.front>
<doc.title>Writing I-Ds and RFCs using XML</doc.title>
<doc.author surname="Rose" fullname="Marshall T. Rose" initials="M.T.">
<organization>Invisible Worlds, Inc.</organization>
<address>
<postal>
<street>660 York Street</street>
<city>San Francisco</city>
<region>CA</region>
<code>94110</code>
<country>US</country></postal>
<phone>+1 415 695 3975</phone>
<email>mrose@not.invisible.net</email>
<uri>http://invisible.net/</uri></address></doc.author>
<doc.date year="1999" month="June"></doc.date>
<doc.area>General</doc.area>
<doc.keyword>RFC</doc.keyword>
<doc.keyword>Request for Comments</doc.keyword>
<doc.keyword>I-D</doc.keyword>
<doc.keyword>Internet-Draft</doc.keyword>
<doc.keyword>XML</doc.keyword>
<doc.keyword>Extensible Markup Language</doc.keyword></doc.front><doc.extras abstract="true" note="false"></doc.extras>
<doc.links>
</doc.links>
</doc.props>
<remote.props uri="http://sqa.not.invisible.net/public/rfc/html/rfc2629.html"></remote.props>
<remote.props uri="http://sqa.not.invisible.net/public/rfc/txt/rfc2629.txt" language="text"></remote.props>
</rfc>

2.1.3 Store Operation

Store the specified block using content from standard input. Four modes of store operation are available: create, delete, update, and write. This implementation of store expects to get its block content from standard input.

2.1.3.1 Store create

Create a new block, returning an error if the block already exists.

% perl big.pl -server sqa.invisible.net store test.yoursubtree test.yoursubtree.2629 create < 2629.xml

2.1.3.2 Store delete

Delete the specified block, returning an error if the block does not exist. This operation only requires the block name, so a simplified XML input can be provided (e.g., <rfc name="doc.rfc.2629" />).

% perl big.pl -server sqa.invisible.net store test.yoursubtree test.yoursubtree.2629 delete < 2629.xml

2.1.3.3 Store update

Update the specified block, returning an error if the block does not exist.

% perl big.pl -server sqa.invisible.net store test.yoursubtree test.yoursubtree.2629 update < 2629.xml

2.1.3.4 Store write

Create or update the specified block, as appropriate.

% perl big.pl -server sqa.invisible.net store test.yoursubtree test.yoursubtree.2629 write < 2629.xml

NOTE:
It is probably not a good idea to allow non-authenticated store operations against your blocks server, which is what the above examples demonstrate. The following is a more likely example in normal use, using SASL/OTP for authentication.

% perl big.pl -server sqa.invisible.net -mechanism otp -username yourusername -passphrase yourpassphrase store test.yoursubtree test.yoursubtree.2629 write < 2629.xml

2.2 BXXP Ping (bxxpng.pl)

Opens a channel with the specified server and passes arbitrary text, which is then either echoed back to the client and verified to match what was sent (NULL/ECHO profile) or is simply ignored by the server (NULL/SINK profile).

2.2.1 BXXPng echo


% perl bxxpng.pl -server sqa.invisible.net echo
initializing buffer... done.
.....
5 round-trips: min/avg/max = 312.743 334.746 360.107 (ms)
                                   3       2       2 (KB/s)

2.2.2 BXXPng sink


% perl bxxpng.pl -server sqa.invisible.net sink
initializing buffer... done.
.....
5 round-trips: min/avg/max = 306.301 329.171 376.339 (ms)
                                   3       2       2 (KB/s)



 TOC 

3. Example Server Implementation (bxxd.pl)

The example server implementation is a simple Blocks server that can be used for testing basic connectivity with Blocks client applications. It does not provide datastore support, so it is not possible to perform any of the more advanced client operations, such as: fetch, store, search, etc.

The sample server does provide support for authentication for testing.

The example server application is located in the top-level examples/server directory.

3.1 Configuration

3.1.1 Configuration File Format

bxxd.pl requires a configuration file in order to start.

The configuration file defines general server parameters as well as the available profiles and their associated parameters. The formal definition of the BXXD configuration file is available in the BXXD configuration DTD

Global configuration parameters:

homeDirectory:
all relative pathnames are relative to this directory
moduleDirectory:
all relative module files are relative to this directory
logFile:
file to log events
debugLevel:
debug events, any of: "all", "trace", "timing", and "info" (seperated by spaces) or just "none"

Per profile configuration parameters:

acl:
access control list for the profile
authDirectory:
all authentication files are relative to this directory
mode:
mode requested if the profile supports multiple modes of operation

A typical configuration file contains the following parameters and profiles:

  <?xml version="1.0"?>

  <!DOCTYPE config PUBLIC "-//Blocks//DTD BXXD CONFIG//EN"
            "http://xml.resource.org/blocks/software/bxxd/config.dtd">

  <config>
    <bxxd port="10288">
      <parameter name="homeDirectory"   value="/path/to/bxxd" />
      <parameter name="moduleDirectory" value="modules" />
      <parameter name="logFile"         value="logs/bxxd.log" />
      <parameter name="debugLevel"      value="none" />

      <profile uri="http://xml.resource.org/profiles/sasl/ANONYMOUS" module="sasl-anon">
        <parameter name="acl"           value='subtree "" privs "fetch"' />
      </profile>

      <profile uri="http://xml.resource.org/profiles/sasl/OTP" module="sasl-otp">
        <parameter name="authDirectory" value="auth/" />
      </profile>

      <profile uri="http://xml.resource.org/profiles/NULL/ECHO" module="null">
        <parameter name="mode"          value="echo" />
      </profile>

      <profile uri="http://xml.resource.org/profiles/NULL/SINK" module="null">
        <parameter name="mode"          value="sink" />
      </profile>
    </bxxd>
  </config>

This is a configuration file for the default port 10288.

3.1.2 Running bxxd.pl from INETD

To run the server under the supervision of inetd, first add the following to /etc/services:

bxxp            10288/tcp             # Blocks eXtensible eXchange Protocol

Secondly, add the following to /etc/inetd.conf (Note: this should actually be one line, but was split for readability):

bxxp	stream	tcp	nowait	bxxpuser	/path/to/bxxd/bin/bxxd.pl	/path/to/bxxd/bin/bxxd.pl -config /path/to/bxxd/etc/bxxd-config.xml

Where:

  1. bxxpuser is the supervisory username of the server.
  2. /path/to/bxxd/bin is the full pathname to the Blocks SpaceKit server bin directory.
  3. /path/to/bxxd/etc/bxxd-config.xml is the full pathname to the server configuration file.

You will need to reload inetd as super-user for the change to take effect.

3.1.3 Running bxxd.pl from the Command Line

bxxd.pl can run from the command line in "stand-alone daemon" mode. Once started, it continues to run indefinitely. This mode of running is typically used for testing purposes.

This example starts the server on port 12345 using the configuration file in the current directory named bxxd-config.xml:

bxxd.pl -daemon -port 12345 -config bxxd-config.xml

Without "-port" the server uses the default port, 10288.

3.1.4 Simple Authentication and Authorization Layer (SASL)

Authentication and authorization for the Blocks server is provided via either anonymous[5] or One-Time-Password[4] (OTP) SASL[3] user profiles. The location of this user data is in the configuration file as the "authDirectory" profile parameter. It is a combination of the server "homeDirectory" and the "authDirectory" parameters if authDirectory is a relative path name.

To create an anonymous or OTP user profile, see the SASL Administration utility.

3.2 A Complete Module Example For The Impatient

You can create your own modules by defining a new profile and implementing a new server module as well as the client using the new profile.

In the example, we create a module named "reverse" that receives a server request, reverses the order of the octets in the request, and responds back to the client with the reversed results.

3.2.1 Profile Definition

To access your new module, first define the new profile and its corresponding module in the configuration file for the port using the new profile:

      <profile uri="http://xml.resource.org/profiles/REVERSE" module="reverse">
      </profile>

If you are using the server in stand-alone mode, you will need to restart since the configuration file loads at start time

3.2.2 Module Structure

Profile modules provide a fairly simple API consisting of 6 public subroutines: boot, info, init, exch, fin, and version.

3.2.2.1 Module boot

Determine if the module is run-time bootable/loadable. Returns 0 if bootable and non-zero for all other conditions.


  #
  # reverse profile boot protocol (run-time bootable?)
  #
  sub boot {
    my $log = shift;

    # clear global error indicator
    $! = 0;

    # always bootable
    0;
  }

3.2.2.2 Module info

Returns a list containing information about the profile, including: whether the profile provides transport security (0 or 1), a list of supported profile identities (URIs), and a list of the public methods (callbacks) for using the module.


  #
  # reverse profile info
  #
  sub info {
    my $log = shift;

    return [ 0,  # profile provides transport security? (0 or 1)
             [   # supported profile identities (an XML DTD or URI)
               "http://xml.resource.org/profiles/REVERSE",
             ],
             {   # public methods of this profile
               bootV => \&Profile::reverse::boot,
               initV => \&Profile::reverse::init,
               exchV => \&Profile::reverse::exch,
               finV  => \&Profile::reverse::fin
             }
           ];
  }

3.2.2.3 Module init

Initialize the module, returning a token (hash reference) to be used by the exch and fin subroutines.


  #
  # reverse profile initialisation
  #
  sub init {
    my $log     = shift;  # server's log object (reference)
    my $serverD = shift;  # fully-qualified domain name of server
    my $clientA = shift;  # list of client ip address, hostname, and port
    my $upcallV = shift;  # callback for profile to upcall the server
    my $uri     = shift;  # profile URI

    return { log => $log };
  }

Although interactions between the server and the profile are synchronous, it's possible that the profile may need to originate traffic. An upcall is provided for this purpose.

3.2.2.4 Module exch

Module data/message exchange subroutine.


  #
  # reverse profile data/message exchange
  #
  sub exch {
    my $token = shift;
    my $data  = shift;

    $token->{log}->entry("DEBUG", "reverse::exch", data: ($data)")
      if ($debug > 1);

    return reverse($data);
  }

3.2.2.5 Module fin

Perform module specific clean up operations and dissolve the token created by the module init routine. Parameters are the init token and a status indicator. The "status" parameter indicates whether the finalization is graceful ("+") or extremely prejudicial ("-").


  #
  # reverse profile finalisation
  #
  sub fin {
    my $token  = shift;
    my $status = shift;

    0;
  }

3.2.2.6 Module version

Return the current module version information as module name, version and release number. E.g., Profile::reverse 1.00r1.


  #
  # library version info
  #
  sub version {
    return __PACKAGE__ . " " . $VERSION . "r" . $RELEASE;
  }

3.3 Utilities

3.3.1 SASL Administration Tool

The SASL administration utility is found under the example server directory as etc/sasl-adm.pl. This utility will allow you to create, delete, list, and update the SASL anonymous and SASL OTP user accounts.

Usage:

% etc/sasl-adm.pl [-action create|delete|list|update]
                  [-authdir path/to/authdirectory]
                  [-logfile path/to/logfile]
                  [-mechanism anonymous|otp]
                  [-version]
                  [username]
                  [subtree ...]

  where

    -action    action to perform, defaults to create
    -authdir   path to authentication database directory, defaults to ./auth,
               and will be created as needed
    -logfile   path to log file, defaults to logs/sasl-adm.log
    -mechanism SASL mechanism, defaults to otp
    -version   display application version and exit
    username   user account to access, defaults to anonymous
    subtree    list of subtrees user account will be given full access to,
               default subtree is empty and allows fetch operations on any
               subtree



 TOC 

References

[1] Rose, M.T., "The Blocks eXtensible eXchange Protocol", draft-mrose-blocks-protocol-02 (work in progress), April 2000.
[2] Rose, M.T., "The Blocks Simple Exchange Profile", draft-mrose-blocks-exchange-01 (work in progress), April 2000.
[3] Myers, J.G., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.
[4] Newman, C. and J. G. Myers, "ACAP -- Application Configuration Access Protocol", RFC 2244, November 1997.
[5] Newman, C., "Anonymous SASL Mechanism", RFC 2245, November 1997.


 TOC 

Author's Address

  Brad Burdick
  Invisible Worlds, Inc.
  1179 N. McDowell Blvd
  Suite A
  Petaluma, CA 94954-6559
  US
EMail:  bburdick@invisible.net
URI:  http://invisible.net/


 TOC 

Appendix A. BXXD Configuration DTD

<!--
  DTD for BXXD server configuration, as of 2000-02-14

  Copyright 2000 Invisible Worlds, Inc.

  This document is a DTD and is in full conformance with all
  provisions of Section 10 of RFC2026 except that the right to
  produce derivative works is not granted.


  Refer to this DTD as:

    <!ENTITY % CONFIG PUBLIC "-//Blocks//DTD BXXD CONFIG//EN"
               "http://xml.resource.org/blocks/software/bxxd/config.dtd">
    %CONFIG;

  -->


<!--
  Contents

    DTD data types

    Config file definition
  -->


<!--
  DTD data types:

        entity        syntax/reference     example
        ======        ================     =======
    a uniform resource identifier
        URI           c.f., [RFC1630]      "http://xml.resource.org/profiles/"

    a TCP port number
        PORTNO        0..65535             10288

    a filename
        FILE                               echo.pl
-->


<!ENTITY % URI        "CDATA">
<!ENTITY % PORTNO     "CDATA">
<!ENTITY % FILE       "CDATA">


<!ELEMENT config      (bxxd+)>

<!ELEMENT bxxd        (parameter*,profile*)>
<!ATTLIST bxxd
          port        %PORTNO;     "10288">

<!ELEMENT profile     (parameter*)>
<!ATTLIST profile
          uri         %URI;        #REQUIRED
          module      %FILE;       #REQUIRED
          privRequired
                      (true|false) "false"
          privProvider
                      (true|false) "false">
<!--
  A profile listed as requiring privacy is available only if privacy
  is already enabled. A profile listed as providing privacy is
  unavailable if privacy is already enabled.
  -->


<!ELEMENT parameter   EMPTY>
<!ATTLIST parameter
          name        CDATA        #REQUIRED
          value       CDATA        #REQUIRED>

<!--
  Global parameters:

        name               meaning
        ====               =======
        homeDirectory      all pathnames are relative to this directory
        moduleDirectory    all module files are relative to this directory
        logFile            file to log events
        debugLevel         debug events, any of: "all", "trace", "timing",
                           and "info" (seperated by spaces) or just "none"
  -->



 TOC 

Appendix B. Blocks Public License

Blocks Public License

Copyright (c) 2000, Invisible Worlds, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INVISIBLE WORLDS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.