@section(Various server functions)

There are several server requests which do not specify or access
particular resources on the server, but do control server behavior.

@blankspace(2 lines)
@begin(example)
@flushleft[int GRelease(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GRelease() releases the server from maintaining the results of the
previous command.  If the server is not maintaining results because the
library is in ASYNC_MODE mode, this command has no effect.

@blankspace(2 lines)
@begin(example)
@flushleft[int GLock(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GLock() establishes a temporary lock on all the resources of the server.
This allows a client to be guaranteed of exclusive access to all
resources on the server without other client interfering.  These locks
are typically limited in length by servers so that other clients are not
permanently locked out of a server.  Any other client that attempts to
access the server during a locked period is simply blocked.  If the
locking client does not unlock the server before the time limit is
reached, the lock is silently broken by the server.  The maximum lock
time is available with the GMaxLockTime() call.  Using locks is
encouraged for clients which need to ensure that a volume of interest is
completely set up for them for a short period of a time.  Say, to
GConfigure(), then GSearch(), then perform a still frame grab with an
external processor, then unlock.  GLock() is the only method to
guarantee that no other client will intrude between the GConfigure() and
the GSearch().  Also, if the frame grabbing board takes more time to
grab than the standard release time, this mechanism provides for a
slightly longer leeway after the GSearch().

(Caution: locks that must be forwarded between servers may provide less
than the normal maximum lock time.)

@blankspace(2 lines)
@begin(example)
@flushleft[int GUnlock(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GUnlock() unlocks a server which has been locked by GLock().  Clients
are encouraged to unlock a server as soon as possible, in order to allow
other clients access to server resources.

@blankspace(2 lines)
@begin(example)
@flushleft[G_INT32 GGetServerTime(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GGetServerTime() returns the current time on the server machine in
seconds since midnight, January 1, 1970.  This information is useful in
realizing volume scheduling systems.

@blankspace(2 lines)
@begin(example)
@flushleft[GGetStatistics(@b[server], @b[stat_struct])]
@flushleft[Server *server;]
@flushleft[GStats *stat_struct;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b(stat_struct)@\A structure into which the server statistics will be
placed.
@end(description)

GGetStatistics() is used to get information regarding the server
performance.  The following structure is filled in:

@begin(example) 
typedef struct { 
int revision; 
int num_requests; 
int run_time; 
int num_collisions; 
int num_connections; 
int max_connections;
int delayed_requests;
} GStats; 
@end(example)
@begin(description)
@b(revision)@\Indicates how many times the server has rebuilt its
internal volume table.

@b(num_requests)@\Specifies how many client requests have been made to
the server.  (Includes the current GGetStatistics() request.)

@b(run_time)@\The number of seconds for which the server has been
running.

@b(num_collisions)@\The number of times two client requests have arrived
at the server simultaneously.  @b(num_connections)@\The total number of
connections made to the server.

@b(max_connections)@\The maximum number of simultaneous connections made
to the server.

@b(delayed_requests)@\The total number of client requests that were
delayed because the server was busy processing another request.

@end(description)

@blankspace(2 lines)
@begin(example)
@flushleft[int GCheckRevision(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GCheckRevision() allows a client to manually check if its volume list
(contained in the server structure) is up to date.  Normally, an out of
date volume list is indicated by the error message, VOLUME_LIST_OLD,
returned by the server on most other commands.  GCheckRevision() should
only return NO_ERROR, VOLUME_LIST_OLD, or GIO_ERROR. NO_ERROR means that
the client has an up to date volume list.  VOLUME_LIST_OLD means that
the client should get a new volume list with GReopenServer().  GIO_ERROR
is encountered when a connection to a server dies.  Unless a client is
handling SIGPIPE's however, the SIG_PIPE will probably arrive first, and
the client will exit.

@blankspace(2 lines)
@begin(example)
@flushleft[Server *GReopenServer(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GReopenServer() is used by a client to obtain a new volume list, if the
server indicates that the client has an out of date volume list.  This
situation can occur if a secondary server crashed, or comes on-line, and
the primary server rebuilds its internal volume tables to match the new
availibilty of resources.  A server can also be forced to rebuild its
volumes tables by sending it a SIGHUP.  GReopenServer() returns a pointer
to a new server structure, or NULL, if there was some failure.

@blankspace(2 lines)
@begin(example)
@flushleft[GRebuild(@b[server])]
@flushleft[Server *server;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().
@end(description)

GRebuild() simply requests that the specified server rebuild its volume
table.

@blankspace(2 lines)
@begin(example)
@flushleft[GShutOff(@b[server], @b[up_down])]
@flushleft[Server *server;]
@flushleft[int up_down;]
@end(example)
@begin(description)
@b(server)@\The server connection as returned by GOpenServer().

@b(up_down)@\An integer value indicating whether the server should leave
the disks in a spun up or spun down state.
@end(description)

GShutOff() requests that the server shut itself down, possibly spinning
down the disks first.  An @b[up_down] value of SPINDOWN will make the
server spin down the disks before exiting.  A value of NOSPINDOWN will
leave the disks in the spinning state when the server exits.

@blankspace(2 lines)
@begin(example)
@flushleft[GMount(@b[server], @b[disc_name], @b[dev_name])]
@flushleft[Server *server;]
@flushleft[char *disc_name;]
@flushleft[char *dev_name;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b[disc_name]@\The name of the disc being placed in a device.

@b[dev_name]@\The name of the device into which the specified disc is
placed.
@end(description)

GMount() allows a client program to indicate to the server that the
contents of a device have been replaced with a new disc.  @b[dev_name]
is the name of the local device on which the new disc, @b[disc_name] is
to be mounted.  GMount() can only be performed by a client on the same
host as the server, and only on a device local to that server.  Once the
mount is performed, the server rebuilds its volume table so that the
mount takes place immediately.

@blankspace(2 lines)
@begin(example)
@flushleft[GUmount(@b[server], @b[dev_name])]
@flushleft[Server *server;]
@flushleft[char *dev_name;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b[dev_name]@\The name of the device which is to be taken off-line.
@end(description)

GUmount() is used to bring a local device, on the local server,
off-line.  The server immediately rebuilds its volume table, but ignores
the now unmounted device.

@blankspace(2 lines)
@begin(example)
@flushleft[GMounts(@b[server], @b[num_mounts], @b[disc_names],@b[dev_names], @b[rets])]
@flushleft[Server *server;]
@flushleft[int num_mounts;]
@flushleft[char **disc_names;]
@flushleft[char **dev_names;]
@flushleft[int *rets;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b[num_mounts]@\The number of mount operations to perform.

@b[disc_names]@\An array of disc names to be mounted.

@b[dev_names]@\An array of device names to be mounted upon.

@b[rets]@\An array to contain the return values from each mount
operation.
@end(description)

GMounts() performs like GMount(), except that multiple mount operations
are performed with a single request.  The advantage of GMounts() is that
@b[num_mounts] mounts can be performed with only a single ensuing volume
table rebuild.  If GMount() were called multiple times, a volume table
rebuild would be performed for each call.  Each mount performed by
GMounts[] is comprised of a disc name from @b[disc_names] and the
corresponding device name from @b[dev_names].  The return value of each
mount is placed in the @b[rets] array, which should have already been
allocated by the client program.

@blankspace(2 lines)
@begin(example)
@flushleft[GUmounts(@b[server], @b[num_umounts], @b[dev_names],@b[rets])]
@flushleft[Server *server;]
@flushleft[int num_umounts;]
@flushleft[char **dev_names;]
@flushleft[int *rets;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b[num_umounts]@\The number of unmount operations to perform.

@b[dev_names]@\An array of device names to be unmounted.

@b[rets]@\An array to contain the return values from each unmount
@end(description)

GUmounts() performs @b[num_umounts] unmount operations.  The devices to
be unmounted are specified in the @b[dev_names] array, and the return
values from each unmount are placed in the corresponding entry in the
@b[rets] array, which should already have been allocated by the client
program.  Once all of the unmounts are accomplished, a volume table
rebuild is performed.

@blankspace(2 lines)
@begin(example)
@flushleft[GGetMounts(@b[server], @b[num_mounts], @b[mount_devs],@b[mount_discs])]
@flushleft[Server *server;]
@flushleft[int *num_mounts;]
@flushleft[char ***mount_devs;]
@flushleft[char ***mount_discs;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b[num_mounts]@\Returns the number of mountable devices.

@b[mount_devs]@\Returns the list of mountable devices.

@b[mount_discs]@\Returns the list of discs mounted on the devices.
@end(description)

GGetMounts() retrieves the list of mountable devices from the server,
along with the currently mounted disc for each device.  The number of
mountable devices is returned in @b[num_mounts], and the arrays
@b[mount_devs] and @b[mount_discs] are allocated to accommodate the
returned arrays.  The client program must free the arrays when finished.
If a device has nothing mounted, then the corresponding disc name is
returned as [nothing].

@blankspace(2 lines)
@begin(example)
@flushleft[GRequestNotification(@b[server], @b[yesno])]
@flushleft[Server *server;]
@flushleft[int yesno;]
@end(example)
@begin(description)
@b[server]@\The server connection as returned by GOpenServer().

@b[yesno]@\An integer value indicating whether to enable notification.
@end(description)

GRequestNotification() should never be used by an ordinary client.  It
is used by servers to request that other servers notify them of volume
table rebuilds.  A @b[yesno] value of Notify indicates that notification
to this host should be enabled; and value of NoNotify indicates that
notification to this host should be disabled.  Notification is only
performed on a per-host basis, not on a per-client basis.  The
notification takes place over a UDP channel independent of the TCP
connection used for normal communication.

@section(Routines which change the action of the Galatea library)

The Galatea library (Glib) can be set to act in several different modes.
There are debug settings, timeouts, and asynchronous operation modes, as
well as an error handling system.

@blankspace(2 lines)
@begin(example)
@flushleft[int GSetState(@b[debug_mode], @b[set_time], @b[set_sync])]
@flushleft[int debug_mode;]
@flushleft[struct timeval *settime;]
@flushleft[int set_sync;]
@end(example)
@begin(description)
@b(debug_mode)@\Specifies the new debug mode for library operation.

@b(set_time)@\Specifies the new time out length on reads from the server.

@b(set_sync)@\Specifies whether the library should act synchronously or
asynchronously.  
@end(description)

GSetState() sets several modes of library operation.  Debugging allows
the library to print out some information as routines are called.  This
is mainly used in debugging the library, so the information printed may
not be very consistent or useful.  A value of one enables debugging and
a value of zero disables debugging.  

The maximum time that the library will wait for a reply from the server
can be set with the @b[set_time] argument.  If NULL, the time out is
infinite.  Infinite is the default library time out.  If @b[set_time] is
non-NULL, the time contained in the timeval structure is copied and used
for the new time out.

The library can also be set to use asynchonous or synchronous operation.
Normally, all commands send a request to the server and then wait for a
reply from the server indicating the request has been completed or that
an error occured.  This is called synchronous operation, since the
client is kept synchronized to the server.  For some applications, say a
video shuttle control, acknowledgment of successful completetion is not
necessary, since many commands are being sent, and single failures are
not a problem.  In the shuttle application, it is also unnecessary to
wait for synchronization, and that wait can cause poor performance.  For
such applications, setting the @b[set_sync] argument to ASYNC_MODE will
provide better performance.  In this mode, many commands will report
that no error occurred.  For some commands, such as GReopenServer(),
asynchronous mode is meaningless.  Some other commands also act
synchronously, even in ASYNC_MODE, such as GLock() and GCheckRevision().
The other change in ASYNC_MODE is that the server will not wait for a
GRelease() from a client.  A @b[set_sync] of SYNC_MODE returns the
library to synchronized operation.

@blankspace(2 lines)
@begin(example)
@flushleft[int GSetErrorHandler(@b[handler])]
@flushleft[void (*handler)(Server *, int);]
@end(example)
@begin(description)
@b(handler)@\A handler procedure to be called when errors are reported
by a server.
@end(description)

Many Galatea commands can be met with an error response from the server.
These errors are normally reported back to the client through the return
value for the command.  It is possible to intercept these error
messages, and cause the library to invoke a client specified error
handler.  A very useful error handler is one that can deal with a
VOLUME_LIST_OLD error, execute a GReopenServer() and then update client
structures or displays before returning.  Such a system reduces code
duplication.  The command that caused the server still returns the error
code, but the main sections of the client application need not handle
the error explicitly.  A NULL for the @b[handler] procedure, causes the
library to resume default action, which is to call GReopenServer() on
the server which returned the error.  This permits the following Galatea
calls to procede normally.

The arguments to the error handler are the server on which the error was
generated and the error code returned by the server.  The return value
from the handler is not used.


