This section will focus on some of the overall design aspects of the Status Server which will hopefully help answer some questions as to how it works.
Objects within the Status Server are grouped together in a ``tree-like'' fashion patterned after the UNIX file system. As a result, it is possible for a client to traverse and manipulate objects within the Status Server much like traversing a directory tree and manipulating files in a file system. Objects within the Status Server can be referenced either via a fully qualified directory path/object name combination, or a relative path-name combination. In order to manage relative path references, a current path is maintained for each client connection. Rules to determine whether a path-name combination is expressed as an absolute path or relative path are applied the same way they are in a UNIX file system. A visual example of the type of structure used to hold Status Server information is shown in figure 2. This example is a screen shot taken from gss.
Each directory and data object in the Status Server consists of a series of attributes. These attributes include:
If a data object has a value of NONEXISTENT, it is completely removed and deallocated whenever its use counts are zero. This means that a data object can not be completely removed if a client has performed a touch, monitor, or directory listing request on the object. This is a requirement to enforce pointer integrity within the Status Server.
The Status Server listens over a socket interface to client requests. The server services each request and sends back an associated response. With the exception of a disconnect request, each client request will receive a response from the Status Server. In most cases, the client will receive a single line response to a request. The exception to the single response model is the case where a client has requested monitoring updates or the client has requested the contents of a directory. Multiple line response messages will always be terminated with an end-of-transaction (EOT) return message. The client must not send any new commands until it has fully processed the current command. If, for some reason, the server receives a new command request from a client before it has sent the client the last response, it may inform the client that a protocol error has occurred. At this point, the Status Server will expect the client to close the connection. If, however, the client sends another command, the Status Server will close the client connection.
In the case of monitored objects, it is possible for a client to receive an unsolicited message across the interface. This message is triggered the first time a client-monitored object is updated beyond the ``deadband'' restriction and the client has not already been informed of a monitor update. Once a client is informed that it has monitored information to retrieve, it must initiate a ``poll'' request to retrieve the information. This is an event-driven model which triggers the client to always initiate a retrieval of monitor information.
The Status Server utilizes the sockio library to handle the low-level socket details. The sockio library uses a single-threaded, non-blocking approach to handling client connections. You can review the the CFHT Socket I/O Library document for more information regarding the design of this library (see http://software.cfht.hawaii.edu/sockio). Figure 3 shows a system diagram illustrating how the sockio library is used as part of both the Status Server and the client C API library.
Both the Status Server and sockio library are designed in such a way that any data sent across the socket can be gracefully handled. This includes receiving binary data or unusually long messages which may or may not be properly terminated with a newline character. If a client attempts to connect from outside the CFHT network, or a client violates the established message protocol, whenever possible its connection will be terminated.
Each request received by the Status Server will be checked to make sure it is both a valid command and does not contain any invalid characters. The Status Server will only process requests which contain URL encoded 7 bit ASCII printable characters terminated with a newline (CR/LF or LF). If a non-conforming request is received, it will be rejected with a ``syntax error'' response. In the Status Server encoding scheme, only printable characters with the exception of some special characters can be sent unencoded. Figure 4 shows the characters which must be explicitly encoded prior to being received by the Status Server.
URL encoding of a character consists of a ``%'' symbol, followed by the two-digit hexadecimal representation (case-insensitive) of the character value. For example, a tab character would be encoded as ``%09''.
Since the Status Server does not perform any encoding or decoding functionality, functions will be available in the Client API to perform encoding and decoding of Strings from an 8 bit character format to URL encoded format. Clients which decide to access the Status Server via a telnet session or custom socket implementation, must be aware of the URL encoding requirements of the Status Server and perform the necessary encoding.
It is important to note that any encoding schemes used to encapsulate data are completely hidden from clients using the Client API. A client using the Client API does not need to call any encoding or decoding functions.
All string data stored and manipulated within the Status Server is 7 bit only.
The full details of the client C API can be found at http://www.cfht.hawaii.edu/statserv/StatusServer API. If you wish to use the client C API to communicate with the Status Server, it is important to know the prerequisites and scope of the system. The Status Server was designed from the beginning to be a very simple system to meet a specific set of needs. With this in mind, the following list outlines a basic understanding required before the Client C API can be used effectively.
This is the source code for 'ssGet', a command line utility which retrieves the value of an object from the Status Server. The following would retrieve the current temperature reading from the Status Server.
#!/bin/sh ssGet /p/logger/weather/temperature
Here is the source for the ssGet.c program:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "cli/cli.h" #include "ss/ss_define.h" #include "ssapi/ss_api.h" #include "ssapi/ss_error.h" /* Print a message to stderr indicating what the proper usage syntax is */ static void usageSyntax(void) { fprintf(stderr, "usage: ssGet [NAME=]name\n"); } /* Clean up routine to free up any used memory and exit with a failure */ static void exitWithFailure(command_opt_t* opts) { cli_opts_free(opts); exit(EXIT_FAILURE); } int main(int argc, char* const argv[]) { char *name = NULL; /* Location to store the name of the object */ char *value = NULL; /* Location to store the value */ /* Set up the command parsing array for population */ command_opt_t get_opts[] = { { "n*ame", &name, "The name of the object" }, OPTIONLIST_END }; /* Parse the argument list */ if (cli_opts(argv + 1, get_opts) != argc - 1) { /* Error occured during option parsing */ usageSyntax(); exitWithFailure(get_opts); } /* Make sure that a valid object name was supplied */ if (!name || !*name) { /* Error occured during option parsing */ usageSyntax(); exitWithFailure(get_opts); } /* Allocate space to hold the value returned from the Status Server */ value = (char *)malloc(SS_MAX_VALUE_SIZE); if (value == NULL) { fprintf(stderr, "error: memory allocation failed.\n"); exitWithFailure(get_opts); } /* Log on to the Status Server */ if (ssLogon(argv[0]) == FAIL) { fprintf(stderr, "Connection failed: %s\n", ssGetStrError()); free(value); exitWithFailure(get_opts); } /* Retrieve the contents from the Status Server */ if (ssGetString(name, value, SS_MAX_VALUE_SIZE) == FAIL) { fprintf(stderr, "ssGet `%s' failed: %s\n", name, ssGetStrError()); free(value); exitWithFailure(get_opts); } puts(value); free(value); cli_opts_free(get_opts); exit(EXIT_SUCCESS); }