Odyssey Adapter Programs

Introduction

There are the following programs:

  • cgigate: CGI that connects a remotely-authenticated (or anonymous) user to their own local JVM.
  • webgate: CGI that connects a remotely-authenticated user to their own local JVM running as themselves. See OdysseyWebsuid.
  • odyssey: Command-line program that connects a user's Unix command line to their own local JVM running as themselves. If this is invoked on a web server it will actually be the same JVM as they get through webgate. Referred to as cmdgate in a generic context; in our installation it is called odyssey.
  • restart: Program invoked by the other ones via ssh to start the central JVM that connects to the database.

These are in the odyssey-2 package on capo, with source in /usr/source in the usual XHier way. All four are very similar, so they actually share their source code: the few differences are created by #ifdef s in the code, controlled by the makefile.

The wire protocols used are documented in OdysseyWireProtocols.

Error diagnosis

Every system call is checked for error responses. With a few specific exceptions, an error response results in the calling of a routine error() which simply logs the error, attempts to report the error to the user, and exits. Each place where error() is called passes it a different number, which along with errno is recorded in the log and displayed in the error message. In cases where the system call is called from a procedure, that procedure will itself take a where parameter which is used to construct the value passed to the error() routine.

Error Number Assignment

Only numbers divisible by 10 are used literally. Numbers are assigned in the following ranges:

  • 1xx0: adapter.c
  • 3xx0: process.c
  • 20xx0: log.c

The IO routines use where, where+1, etc. when they make more than one system call. Numbers that are at least 20000 are reserved for errors related to logging. Reporting one of these errors turns off logging before attempting to report the error to the user.

Detailed Adapter Algorithm

This section describes the sequence of steps carried out by the adapter programs cgigate, webgate, cmdgate, and restart. For the most part they simply carry out the same steps in sequence, with some variation between the different adapter versions.

Log Initialization & Userid Determination

The log file is opened and the userid determined. The log file is named #webgate, #cmdgate, #restart, or #cgigate as appropriate, and is saved in logs/YYYY/MM/DD/ if today's date is YYYY-MM-DD.

The userid is determined as follows:

  • #webgate: Current user (getuid()), unless it is equal to POWERLESS_USER, in which case use $REMOTE_USER.
  • #cmdgate: Current user (getuid())
  • #restart: Command line (argv[1])
  • #cgigate: $REMOTE_USER

The "log userid" is equal to the userid, unless the userid is null, in which case the string "%%anon%%" is used instead. The "log userid" is meant to be used precisely wherever it is not possible to record a null value, for example when formatting a file name. This rule is not followed perfectly in all code in the system, especially in Java where Java's null is not used everywhere it should be.

Read POST Data

webgate and cgigate read standard input in its entirety and then close it. The bytes read are recorded for later use.

Open FIFO to Send Request to JVM

First the fifoName is determined. For restart this is #server. For cgigate this is the log userid. For webgate and cmdgate this is the log userid with ".=" appended. Note that there should be a one-to-one correspondence between these names and running JVMs, except that some of the JVMs may not be running at any given moment. The ".=" suffix can be thought of mnemonically: it reminds us that the corresponding JVM is running as the indicated user rather than as the odyssey user.

Corresponding to the fifoName there are two files, both residing in the connect directory. fifoName.fifo is the actual FIFO, while fifoName.lock is a regular file used for locking. The sole reason for having two separate files is that FIFOs cannot be locked. The lock file is always a 0-byte file.

We open the lock file. If necessary, it and the corresponding FIFO are created. Next we lock the entire lock file. This begins the critical section.

Start Java and SSH Processes if Necessary

Now we open the FIFO for write, in non-blocking mode. If there is a JVM waiting for the request, the open succeeds and, after switching to blocking mode on the FIFO, we move onto the next step. If there is no JVM waiting, the open should fail. We start a new Java process, and open the FIFO in blocking mode. We therefore block on the FIFO until the Java process has started up and is ready to accept input from the FIFO. Except for restart, we also SSH to the main database server to restart (if necessary) the main server process and obtain the connection key for our JVM to connect to the main server. In this case we wait until the SSH process terminates before proceeding, as its stdout is hooked to the FIFO to the JVM, so the JVM sees the output of the SSH process.

Open FIFOs for per-process JVM Communication

Now we create the FIFOs which will be used to finish the communication with the JVM. These FIFOs are per request, and are created in the same connect directory as the request-submission FIFOs. Their names are formed by separating the fifoName, the process ID, and the "type" by periods. For cmdgate, the "type" is stdi for stdin, stdo for stdout, and stde for stderr. For the other types, the "type" is just resp.

If the FIFO already exists, it is considered an error. This should not occur since the previous adapter process with the same process ID should have removed the FIFO. However, this must be considered a defect in the adapter; if it finds the FIFO already existing, it should either just use it, or delete the existing one first. Any other process trying to use it would have to have the same process ID, so it cannot exist at the same time.

Send Request to JVM

Now that we have the FIFO opened for write, we send the request to the JVM. This is described in OdysseyWireProtocolJVMRequest. Once the request is sent, we close the FIFO and then the lock file. This ends the critical section.

Copy Responses

All that remains is to take the response sent by the JVM and send it to standard output, except for cmdgate, where we need to take input on stdin and send it to the JVM, and echo data sent by the JVM to stdout or stderr as appropriate.

For cmdgate, we use select() to monitor stdin and the stdo and stde FIFOs for available data. When we see it, we copy it to the stdi FIFO, stdout, and stderr respectively. For the other adapters, we simply send everything from the resp FIFO to stdout.

Cleanup

Once the response copying is done, we are done. We do not explicitly perform cleanup. Instead, on startup, an atexit() handler is installed which performs cleanup actions consisting of deleting the per-process FIFOs. In addition, a signal handler is installed so that hangups, interrupts, terminations, segmentation violations, and bus errors all result in cleanup occurring and a log entry being made prior to the exit occurring. Child exits are handled separately.

Child Process Termination Handler

If the SSH process terminates, a flag is simply set which is tested in the code that initiates the SSH process. This is normal operation.

If the Java process terminates, this indicates a serious problem with the Java environment, such as the required class files being missing. We report the error and terminate.

If a different process terminates, it is an unexpected error since the SSH and Java processes are the only ones we ever spawn.

-- IsaacMorland - 13 Apr 2006

Topic revision: r7 - 2008-12-02 - IsaacMorland
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback