Using the InterBase Services Manager

By: Mark Duquette

Abstract: How to use the new InterBase Service API to perform tasks such as database backup and restore, displaying connected users and databases, and retrieving database statistics.

Introduction

The InterBase services manager is a new feature added to the latest version of the product.  The services manager allows developers to program administrative functions, like backup, restore, and user management, directly into their applications.  Prior to the existence of the services manager, it would be necessary to perform these types of functions by either using the command line utilities by themselves or having the application execute the utility.  This paper will describe how the services manager works as well as how to integrate it into your new InterBase 6.0 applications.    The objective of this paper is to outline the basics of using this new feature in InterBase and to present ideas of how it can be used to enhance existing or new applications written using InterBase.

How it works

Normally when using the InterBase API, a connection is made to a specific database.   From this connection, information can  be retrieved.  The services manager works outside the realm of databases.  This allows an application to make a connection directly to the server without first making a connection to a database.   Because of this, is is possible to get information on the server itself as well as initiate actions on databases.

The services manager makes use of two type of services: passive services and active services.  By using these services effectively, applications can easily administer a server and customize its interface based on the capabilities and version of a server.

Passive Services

Passive services are used to retrieve information from the server and do not require the server to start a thread to perform some kind of action, unlike active services which will be discussed next.  Passive services can be started using the API call isc_service_query and will not return from the server until the request is processed or a timeout period has expired.  When the server receives a request for a passive services, it simply locates the service requested, retrieves the required information, and places the information in the output buffer sent in via the API call.

The information returned by these types of services fall into the following three categories.

  • Static information

  • This information does not change based on the state of the server since it is usually a static element inside the server.  Different types of  static information which can be retrieved from the server include

       
    • the version and implementation of the server, for example a Windows NT server would return "WI-V6.0.0" for its version and its implementation would return "InterBase/x86/Windows NT"
    • the version of the services manager, currently 2
    • the path to and name of the security database (ISC4.GDB) currently in use
    • the path to the directory which contains the interbase.msg file
    • and the location where the server will create its .lck files.

  • Dynamic information

  • Dynamic information changes based on the state of the InterBase server.  When requesting dynamic information from the server, it is important to keep in mind that the service query call will return the information based when the server started processing the request.  Any changes made while the request is being processed may not be reflected in the return from a particular request.  Dynamic information which can be returned from the server include

       
    • the number of active user connections on the server
    • the names and number of databases in use by the server
    • the current licenses active on the server  (certificate keys and IDs)
    • the number of users licensed to access the server
    • the current settings in the InterBase configuration file

    Dynamic information can be used in conjunction with the existing InterBase API calls to return information such as the users connected to a particular database, and with the active services to perform administrative tasks such as adding additional user licenses to the server and retrieving log file information.

  • Active Service Information

  • A number of the services which can be started instruct the server to perform some action.  These services are known as active services and will be discussed next.  When requesting information about an active service, it is important to remember to start the service first (otherwise, your calls will fail).   Information which can be retrieved from the server when using the two types of services together include

       
    • the interbase.log file from a remote server
    • the user information found in the InterBase security database (ISC4.GDB)
    • the information about limbo transactions
    • and the verbose output that results from a database backup or restore

Active Services

Active services are used to request that the server start a worker thread to perform some kind of action.  Active services are started using the API call isc_service_start and will return control back to the client from the server once the thread has been started or on an error condition.  When the server receives a request to start an active serrvice, it locates the service requested, parses the service parameter buffer, and starts the thread specified by the service action call.

The services manager only allows one active service to be running at a time per attachment to the services manager.  Because of this, active services are usually started in the following manner

  • call isc_service_attach with the appropriate connection information
  • call isc_service_start with the parameters needed for a particular service
  • call isc_service_query to retrive information about the service which was started
  • call isc_service_detach to disconnect from the services manager
The services which can be started using isc_service_start mirror the functionality of the command-line tools gbak, gstat, gfix, and gsec.  The follwing tasks can be performed using active services:
  • Database backup and restore
  • Database validation and repair
  • Adding, modifying, removing, and retrieving user entries from the security database
  • Administering software activation certificates
  • Setting database properties
  • Retrieving remote interbase.log files

Security

The security context used by the services manager is determined by the information passed in when connecting to the services manager.  When connecting to the service manager, the input parameter block will specify a username and a password.  This information is used to determine if the username and password combine to make a valid InterBase user and to determine if the user is the SYSDBA user.  This base security context is used for all services, active or passive, which are executed using this connection.

Some of the services can only be accessed by the SYSDBA user, for example adding license certificates.  Most of the passive services can be accessed by any valid InterBase user and many of the active services take an optional role name as a parameter if the service acts on a database, for example modifying user information in the security database.

Working with services

When working with services, the most important thing to remember is that everything done by the services is with respect to the server and its environment.  This is particularly important when using the active services.  If you are already familiar with using the InterBase API to work with databases and transactions, then working with services should seem familiar.

Note:
All length values in the spb must be 2 bytes and all numeric data values in the spb must be 4 bytes, there are two new macros that have been added to ibase.h.  They are ADD_SPB_LENGTH and ADD_SPB_NUMERIC.  Each of these takes a pointer to the spb and the data to be added.  ADD_SPB_LENGTH adds the length to the spb as 2 bytes and ADD_SPB_DATA adds the data to the spb as 4 bytes.  After each of these macros are called, the spb is incremented to the next available slot in the buffer.  The macros are defined as follows:

#define ADD_SPB_LENGTH (p, length)    {*p++ = length; 
                                       *p++ = length >> 8;}

#define ADD_SPB_NUMERIC (p, data)    {*p++ = data; 
                                      *p++ = data >> 8; 
                                      *p++ = data >> 16; 
                                      *p++ = data >> 24;}
When parsing a buffer which has information returned from the server via a call to isc_service_query, discussed later, the same restriction applies.  Use the existing InterBase API call isc_vax_integer to process the length and numeric data information.

Connecting to the services manager

The first step in working with the services manager is connecting to it.  This is done using the API call isc_service_attach which is defined as follows:
ISC_STATUS ISC_EXPORT isc_service_attach (ISC_STATUS *status_vector,
                                          ISC_USHORT service_length,
                                          char *service,
                                          isc_svc_handle *svc_handle,
                                          ISC_USHORT spb_length,
                                          char *spb)
returns: value of ISC_STATUS[1] :: 0 if no error
                                   >0 if there is an error
*status_vector: pointer to a 20 element array of  ISC_STATUS
service_length: length in characters of the name of the service and host to connect to.
        Specify 0 if the service is a null terminated string.
*service: pointer to a character buffer containing the name of the host to connect to.
*svc_handle: pointer to a long value used to store the handle of the service structure 
             on the server.  note: This value MUST be 0L when attaching to a service.
spb_length:  length in bytes of the service parameter buffer
*spb: pointer to a buffer containing the service parameter
To specify which server to connect to, set the service parameter to one of the following connection strings
  • serverhost:service_mgr for a TCP/IP connection
  • serverhostservice_mgr for a NetBEUI connection
  • serverhost@service_mgr for a SPX connection
  • service_mgr for a local connection
The literal string service_mgr is required in all instances.   Replace serverhost with the name of the actual server that will be used for the connection.

Before intiating a connection to the services manager, a service parameter block (SPB) must be filled out with the username and password to be used for the connection.  As described earlier, the username and password used to connect will be used to determine access to other services.  Once the connection is made, use the svc_handle to start or query services and to disconnect from the services manager.

An example of how to connect to the services manager via TCP/IP


char            *user = "SYSDBA",
                *pass = "masterkey";
ISC_STATUS      status [20];
isc_svc_handle  *svc_handle = NULL;
char            svc_name[32],
                spb_buff[128],
                *spb = spb_buff,;
ISC_USHORT      spblen;
*spb++ = isc_spb_version;
*spb++ = isc_spb_current_version;
*spb++ = isc_spb_user_name;
*spb++ = strlen (user);
strcpy (spb, user);
spb += strlen (user);

*spb++ = isc_spb_password;
*spb++ = strlen (pass);
strcpy (spb, pass);
spb += strlen (pass);

sprintf (svc_name, "myserver:service_mgr");     /* TCP/IP */

spblen = spb - spb_buff;

if (isc_service_attach (status, 0, svc_name, &svc_handle, spblen, spb_buff))
    {
    isc_print_status (status);
    exit (1);
    }

The user parameters accepted in the spb for isc_service_attach are:
 

Parameter Length Data Meaning
isc_spb_current_version 1 isc_spb_version 2 bytes which specify the version of the spb.  These must always be the first two bytes in the spb.
isc_spb_user_name length of username the username the username to connect to the service manager with.  This username will be used for all services that require a username to be specified.
isc_spb_password length of password the password the password to connect to the service manager with.  This password will be used for all services that require a password to be specified.

Starting services

Once a client has attached to the services mananger using isc_service_attach, the client uses this API call to start an active service on the server.  As mentioned before, active services can perform such operations as database backup, log file retrieval, or administration of server licenses.  Only one active service can be started at a time per service handle.  An error will result if an attempt is made to start more than one service on the server using the same service handle.    The API call for starting a service, isc_service_start is defined as follows:
ISC_STATUS ISC_EXPORT isc_service_start(ISC_STATUS *status_vector,
                                         isc_svc_handle *svc_handle,
                                         isc_resv_handle *reserved,
                                         ISC_USHORT spb_length,
                                         char *spb);

returns: value of ISC_STATUS[1] :: 0 if no error
                                   >0 if there is an error

*status_vector: pointer to a 20 element array of ISC_STATUS

*svc_handle: pointer to a long value used to store the handle of the service structure
             on the server.  This must point to a handle previously allocated in
             isc_service_attach.

*reserved: this parameter is being reserved for future use

spb_length: length in characters of the send buffer

*spb: pointer to a buffer containing flags instructing the service manager to process
      information
For each service action, there is a list of parameters which define that action.   The paramters consist of three different peices of information: the parameter name, a length, and a value.  The length and value are specific to the individual parameters.

The services which can be started using isc_service_start are
 

Service Description
Restrictions
isc_action_svc_backup Starts database backup process on the server SYSDBA or database owner
isc_action_svc_restore Starts database restore process on the server SYSDBA or database owner
isc_action_svc_repair Starts database repair process on the server SYSDBA or database owner
isc_action_svc_add_user Adds a new user to the security database none
isc_action_svc_delete_user Deletes a user record from the security database none
isc_action_svc_modify_user Modifies a user record in the security database none
isc_action_svc_display_user Displays a user record from the security database none
isc_action_svc_properties Sets database properties SYSDBA or database owner
isc_action_svc_add_license Adds a license to the license file SYSDBA user only
isc_action_svc_remove_license Removes a license from the license file SYSDBA user only
isc_action_svc_db_stats Retrieves database statistics SYSDBA or database owner
isc_action_svc_get_ib_log Retrieves the InterBase log file from the server none

When the server receives a request to start a service thread, the following process occurs

  • The service parameter is validated against the known services.  This determines the thread to start and any security restrictions that may be in place.
  • Next, a check is made to determine if any services are currently running using the same service handle.  If another service is active and using the same service handle, the current request to start is denied and an error is returned to the client.
  • The parameters to the service are parsed and validated based on the information passed in.  The service parameters are validated twice; once by the server and again by the service thread.  Since the service threads mirror much of the same functionality as some of the command-line tools, the service thread will always produce an exact error if one is encountered during the parsing stage.
  • After the service has been identified and the service parameters parsed and organized into a form by which it can be recognized by the thread, the service thread is launched.   At this point the server waits until the thread sends an event which signals that all intialization is complete and the serivice has actually started, or in some cases completed.
  • Once the server receives the event, the isc_service_start call returns control back to the client.
It is very important to keep in mind that the service is executing based on the current server environment and not the client environment.  This means that any database or file parameters specified must be done with respect to the server.

The return value and status from isc_service_start represents any error that could have occurred either in the process of launching the service thread or from the service itself, for example, the database to backup could not be opened.  isc_service_start will not return until the service has completed its initialization and is actually running.   The following is an example of starting the service to retrieve the contents of the interbase.log file.  It assumes that a connection has already been made using isc_service_attach.


ISC_STATUS      status [20];
char            thd_buff[256], *thd = thd_buff;
ISC_USHORT      thdlen;

 /* isc_service_attach happens here */
*thd++ = isc_action_svc_get_ib_log;

thdlen = thd - thd_buff;

if (isc_service_start(status, &svc_handle, NULL, thdlen, thd_buff))
    {
    isc_print_status (status);
    isc_service_detach (status, &svc_handle);
    exit(1);
    }

Many of the active services return some type of information back to the client.   The way this is accomplished is via a call to isc_service_query, which will be discussed next.  The information from the service thread is stored in an internal buffer in the server.  This buffer is currently set to hold 1k worth of information.  If, while the service is writing to this internal buffer, the buffer becomes filled, the service thread will wait until there is more room in the buffer.   In order for the buffer to be emptied, the client must query this information.   However, if, while the service is running the client disconnects, the service will stop writing to the internal buffer, but will complete its operation.  There is currently no way to cancel a running service.

Querying services

In addition to starting active services on the server using isc_service_start, a client can start a passive service using the API call isc_service_query once a successful connection has been made to the services manager via isc_service_attach.  The client uses this API call to retrieve information about the server, such as the installed licenses or to return information from a currently running active service.  This is accomplished by specifying the correct parameters in the receive buffer specified in the API call which is defined below
ISC_STATUS ISC_EXPORT isc_service_query (ISC_STATUS *status_vector,
                                         isc_svc_handle *svc_handle,
                                         isc_resv_handle *reserved,
                                         ISC_USHORT send_spb_length,
                                         char *send_spb,
                                         ISC_USHORT recv_spb_length,
                                         char *recv_spb,
                                         ISC_USHORT response_buffer_length,
                                         char *response_buffer);
returns: value of ISC_STATUS[1] :: 0 if no error
                                   >0 if there is an error
*status_vector: pointer to a 20 element array of ISC_STATUS
*svc_handle: pointer to a long value used to store the handle of the service structure on the server.
             This must point to a handle previously allocated in isc_service_attach.
*reserved: this parameter is being reserved for future use
send_spb_length: length in characters of the send buffer
*send_spb: pointer to a buffer containing flags instructing the service manager to process information
recv_spb_length: length in characters of the receive buffer
*recv_spb: pointer to a buffer containing flags instructing the service manager to return information
response_buffer_length: length in characters of the return buffer
*response_buffer: pointer to a buffer containing information received from the services manager
The services which can be used to return information about the server and its environment are
 
Service Description
isc_info_svc_svr_db_info  Retrieves the number of active attachments, databases, and database names
isc_info_svc_get_license  Retrieves all license keys and IDs from the license file
isc_info_svc_get_license_mask  Retrieves a bitmask representing licensed options on the server
isc_info_svc_get_config  Retrieves the parameters and values for IB_CONFIG
isc_info_svc_version  Retrieves the version of the services manager
isc_info_svc_server_version  Retrieves the version of the InterBase server
isc_info_svc_implementation  Retrieves the implementation of the InterBase server
isc_info_svc_capabilities  Retrieves a bitmask representing the server's capabilities
isc_info_svc_user_dbpath  Retrieves the path to the security database in use by the server
isc_info_svc_get_env  Retrieves the setting of $INTERBASE
isc_info_svc_get_env_lock  Retrieves the setting of $INTERBASE_LCK
isc_info_svc_get_env_msg  Retrieves the setting of $INTERBASE_MSG
isc_info_svc_get_licensed_users  Retrieves the number of users licensed for accessing the server

As mentioned earlier, isc_service_query can also be used to return information about any active services which are currently running on the server.  The services which retrieve information from active services are
 

Service Description Active service
isc_info_svc_get_users  Returns the user information from isc_action_svc_display_users isc_action_svc_display_user
isc_info_svc_limbo_trans  Retrieve the limbo transactions isc_action_svc_repair with the option isc_spb_rpr_list_limbo_trans
isc_info_svc_running  Checks to see if a service is running on an attachment can be used with any isc_action_svc call
isc_info_svc_line  Retrieves 1 line of service output per call can be used with any isc_action_svc call
isc_info_svc_to_eof  Retrieves as much of the server output as will fit in the supplied buffer can be used with any isc_action_svc call

Calls to isc_service_query can request more than one item at a time.   This can be useful in reducing the number of calls to the server, however, as with anything, there are always caveats.  If the call to isc_query_service is going to return more information than can fit in the response buffer, the buffer will be filled with as much information as possible and the buffer will be terminated by the flag isc_info_truncated.  Since these services normally return information about the server's environment, there is no way to reissue the request and have it restart from where the last call left off.  To retrieve all of the informaion requested, the response buffer will need to be increased and another call will need to be made.

Now, the information regarding isc_info_truncated only relates to those services which do not work with active services.

The following example demonstrates how to request and process a query to return the number of users licensed to access the server and the path to the interbase.msg which is currently in use.


@@ Insert Example here!!


Detaching services

Just as when working with databases, you should always disconnect from the services manager when finished.  If an application does not disconnect properly, the server will continue to hold onto the memory used by the connection until the server detects that the client is no longer attached.  Once the server detects that the client is not connected, all memory held by that connection is freed.  To detach from the services manager, use the API call isc_service_detach which is defined as
ISC_STATUS ISC_EXPORT isc_service_detach (ISC_STATUS *status_vector,
                                         isc_svc_handle *svc_handle);
returns: value of ISC_STATUS[1] :: 0 if no error
                                   >0 if there is an error
*status_vector: pointer to a 20 element array of ISC_STATUS
*svc_handle: pointer to a long value used to store the handle of the service structure on the
             server.  This must point to a handle previously allocated in isc_service_attach.

Working with the results

Now that we have discussed the mechanics involved in accessing and working with the services manager, it is time to explore how to work with the information returned from the services mananger.

All calls into the services manager return a status vector which contains any errors which may have occurred during the call.  However, in order to actually work with the information requested, a call to isc_service_query is required.  As mentioned above, the service manager can be queried to return information about the server's environment or about active services which are currently running or have just completed.  Information is returned using via the response buffer specified in the call to isc_service_query.  This buffer contains information in one of two formats; formatted or unformatted.

Unformatted buffers

Most active services store their information as unformatted text inside the server.   An example of an active service which stores its information this way is isc_action_svc_backup which is used to backup a database.  When this service is initiated along with the parameter isc_spb_verbose, the backup service will store all of the output produced.  This corresponds to the -v flag used with the command-line tool GBAK.  The information stored in the internal buffer is then returned to the client via isc_service_query using either the parameter isc_info_svc_line or isc_info_svc_to_eof.   Using the parameter isc_info_svc_line instructs the server to fill the client's buffer with no more than 1 line of information.  Since a line of information is delimited by a carriage return, the response buffer for the query call does not have to accomodate 1K of information, however it may require more calls into the server.  An alternative method for returning the information is to use isc_info_svc_to_eof .  Using this parameter in the query call instructs the server to fill the client's response buffer with as much information as will fit.  In order to make the most of the call to the server using isc_info_svc_to_eof, it is important to keep in mind that the server will store up to 1K of information at a time.  In addition, it is even more important to keep in mind that once the internal buffer is full, the service will not continue until the client requests some of the information stored in the buffer.  The database backup example will show how to work with and unformatted buffer returned by isc_info_svc_line.

Formatted buffers

While some of the active services return unformatted information, which in this case is basically equivalent to a text dump, most of the services return information in a formatted buffer.  The information in a formatted buffer is returned via a specific buffer sent in with the call to isc_service_query.  The information returned has a is very specific to the parameter sent in, however, the format of the buffer is fairly generic between the different services.

The basic format of the buffer is made of clumpets of data, much like an InterBase status vector or dpb buffer.  The format of a service buffer is

For queries that return a single piece of information (i.e. isc_info_svc_get_env)

<isc_info_svc_get_env>
        <2 byte length>
        <data>
<isc_info_end>
For queries that return numeric information (i.e isc_info_svc_get_licensed_users)
<isc_info_get_licensed_users>
        <4 byte data>
<isc_info_end>
For queries that return a clumpet of information (i.e. isc_info_svc_db_info)
<isc_info_svc_db_info>
        <isc_spb_num_att>
                <4 byte data>
        <isc_info_spb_num_users>
                <4 byte data>
        <isc_info_spb_dbname>
                <2 byte length>
                <data>
        ..... (the clumpet is repeated for each database)
        <isc_info_spb_dbname>
                <2 byte length>
                <data>
        <isc_info_flag_end>
<isc_info_end>
Even though each call has a slightly different return buffer, they all follow the same pattern which is
  • The first bit of the clumpet responds to the information being requested
  • The next bit of the clumpet corresponds to one of three things (based on the first bit)
    •  
    • A 2 byte length which indicates the length of the data to follow
    • A 4 byte numeric value which indicates the data requested
    • A bit which represents the start of a new clumpet of information which will end with isc_info_flag_end
  • The last bit of the return buffer is one of the following flags
    •  
    • isc_info_end which indicates that all of the information requested was returned successfully
    • isc_info_truncated which indicates that not all of the information requested could be returned in the buffer given.  If the information returned was truncated, you will need to increase the response buffer and reissue the query.  The information returned when the query is reissued will start from the first request.   It will not continue where it left off.

Example: Database Backup

To put all of the information presented above into perspective, this example will center around performing a database backup and will use much of the information presented above.  As with all services, and especially those which work with databases, it is extremely important to remember that the service is excuted on the server.

This example is separated into two parts.  The first part performs the setup for connecting to the services manager and starting the service.  In this section there will be examples of the following:

  • setting up the connection SPB and attaching to the services manager
  • setting up the SPB for starting the service
  • basic error handling
The second part of the example focuses on querying the service to provide the output for the backup.  There will be specific examples of
  • setting up the receive spb to issue the query using isc_info_svc_line
  • parsing an unformatted buffer
  • sending the output to the console
  • detaching from the services manager

The setup

char *user = "SYSDBA",
     *pass = "masterkey",
     *dbname = "employee.gdb",
     *bkup_file = "employee.gbk";
ISC_STATUS    status [20];
isc_svc_handle svc_handle = NULL;
char    svc_name[RESPBUF], spb_buff[RESPBUF], thd_buff[RESPBUF];
char    respbuf[RESPBUF], *p = respbuf, *spb = spb_buff, *thd = thd_buff,*x;
short   spblen, thdlen;
int     i = 0, cnt=0;
boolean finished = FALSE;
/* Set up the spb for connecting to the services manager.
 * in this example, we will connect to the server running
 * on the local machine.
 */
*spb++ = isc_spb_version;
*spb++ = isc_spb_current_version;

*spb++ = isc_spb_user_name;
*spb++ = strlen (user);
strcpy (spb, user);
spb += strlen(user);

*spb++ = isc_spb_password;
*spb++ = strlen (pass);
strcpy (spb, pass);
spb += strlen (pass);

sprintf (svc_name, "service_mgr");

spblen = spb - spb_buff;

if (isc_service_attach (status, 0, svc_name, &svc_handle, spblen, spb_buff))
    {
    isc_print_status (status);
    exit (1);
    }
/* Set up the spb for starting the backup service */

*thd++ = isc_action_svc_backup;
/* Add the database name to the buffer */
*thd++ = isc_spb_dbname;
ADD_SPB_LENGTH (thd, strlen(dbname));
strcpy (thd, dbname);
thd += strlen (dbname);
/* Add the name of the backup file to the buffer */
*thd++ = isc_spb_bkp_file;
ADD_SPB_LENGTH (thd, strlen(bkup_file));
strcpy (thd, bkup_file);
thd += strlen (bkup_file);
/* Specify that that we want verbose output (GBAK -v) */
*thd++ = isc_spb_verbose;

thdlen = thd - thd_buff;
/* Start the service and process any errors that may be returned */
if (isc_service_start(status, &svc_handle, NULL, thdlen, thd_buff))
    {
    long *vector = status;
    printf ("Unable to start service:n");
    while (isc_interprete (respbuf, &vector))
        printf ("ERROR: %sn", respbuf);
    printf ("End of errorsn");
    isc_service_detach (status, &svc_handle);
    exit(1);
    }

Seeing the results

do {
    /* Add isc_info_svc_line to the send buffer for the query */
    char sendbuf[] = {isc_info_svc_line};
    ISC_STATUS loc_status[20], *stat = loc_status;

    /* Issue the query */
    if (isc_service_query (status, &svc_handle, NULL, 0, NULL,
                           sizeof (sendbuf), sendbuf, RESPBUF, respbuf))
        {
        isc_print_status (status);
        isc_service_detach (status, &svc_handle);
        exit(1);
        }
    /* If the query is successful,  start processing the return buffer */
    x = p = respbuf;
    if (*p++ == isc_info_svc_line)
        {
        ISC_USHORT len = 0, chTmp = 0;
        /* Get the length of the data being returned */
        len = (ISC_USHORT)isc_vax_integer(p, sizeof(ISC_USHORT));
        p += sizeof (ISC_USHORT);

        /* If there is no length, then we should be done .. let's check */
        if (!len)
            {
            if (*p != isc_info_end)
                printf ("Format error ... <%d>n", *p);
            else
                printf ("Output completedn");
            break;
            }
        /* There is a length for the data, so to be different, let's print
         * it out character by character
         */
        for (chTmp = 0; chTmp < len; chTmp++)
            printf("%c",p[chTmp]);

        /* Since we only requested one item this time, we should be at the end of 
         * the buffer terminated by isc_info_end after moving the pointer past the
         * data we just printed out
         */
        p += len;
        if (*p != isc_info_truncated && *p != isc_info_end)
            { 
            printf ("Format error ... encountered <%d>n", *p);
            break;
            }

        }
    }
while (*x == isc_info_svc_line);

isc_service_detach(status, &svc_handle);
}

Summary

This paper outlined the new InterBase services manager which can enable developers to program administrative functions, like backup, restore, and user management, directly into new applications.   To be successful with the services API, it is important to keep the following issues in mind.
  • All services are performed on the server based upon the server's environment
  • Working with the services are much like working with databases, though not the same
  • The username and password used to connect to the services manager is going to be used for all subsequent calls using that attachment
  • All numeric information must be passed to the services manager as a 4 byte value.   Use the macro ADD_SPB_DATA to facilitate this
  • All lengths returned from the services manager are 2 bytes and numeric data is 4 bytes.   Use isc_vax_integer to retrieve this information
  • The basic format of the return buffers is the same, however, it is specific to the information being requested
  • Keep and open mind.  Much of the information can be combined with other API calls to really take advantage of the InterBase server.  For example, an application can return a list of all the usernames currently attached to all databases which are active on the server.  This can be accomplished using the service isc_info_svc_db_info and a call to isc_database_info with the dpb parameter isc_info_user_names.

Presented at the 1999 Borland Develpers Conference

Server Response from: ETNASC01