IBPhoenix Development

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
This Site Uses:

Using the InterBase Services Manager

By Mark Duquette, Borland Developers Conference 1999.

Introduction

How it works

Working with services

Working with the results

Example: Database Backup

Summary

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 (i.e. backup, restore, and user management) directly into their applications. Prior to the existence of the services manager, it would have been necessary to perform these functions 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 new InterBase 6.0 applications. The objective of this paper is to outline the basics of using this new feature and to present ideas of how it can be used to enhance existing or new InterBase applications.

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 about 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 server's version and capabilities.

Passive Services

Passive services retrieve information from the server. They do not require the server to start a thread to perform some kind of action. 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 service, 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 passive 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
  • 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 on 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 includes:

  • 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 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 requests for the information will fail). Information which can be retrieved from the server when combining active and passive services 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 a particular 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 service, 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 retrieve 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 following 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 services manager, the input parameter block will specify a username and a password. This information determines if the username and password combine to make a valid InterBase user and determines 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, however many services only require a valid login to the InterBase server. 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. Working with services is similar to using the InterBase API to work with databases and transactions.

Note:
All length values in the service parameter block (SPB) must be 2 bytes and all numeric data values in the SPB must be 4 bytes. There have been two new macros 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 initiating a connection to the services manager, the SPB must be filled out with the username and password to be used for the connection. The username and password used to connect will 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 manager using isc_service_attach, the client uses this API call to start an active service on the server. 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
*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 parameters consist of three different pieces of information: the parameter name, length, and 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 of 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 initialization is complete and the service 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. The function,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);
    }

Most 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 information requested, the response buffer will need to be increased and another call will have to be made.

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

Detaching Services

Just as when working with databases, 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 manager.

All calls into the services manager return a status vector containing 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 either 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 accommodate 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 an unformatted buffer returned by isc_info_svc_line.

Formatted Buffers

While most of the active services return unformatted information, which in this case is basically equivalent to a text dump, most of the passive 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 executed 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 is similar working with databases, though not the same
  • The username and password used to connect to the services manager will 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 is returned in 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
  • Most of the information can be combined with other API calls to take full 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.