Raima Database Manager 11.0 - TFS Configuration and Extension API Guide TFS Configuration and Extension API Guide
←
→
Page content transcription
If your browser does not render page correctly, please read the page content below
TFS Configuration and Extension API Guide Raima Database Manager 11.0 TFS Configuration and Extension API Guide 1
TFS Configuration and Extension API Guide Trademarks Raima Database Manager® (RDM®), RDM Embedded® and RDM Server® are trademarks of Raima Inc. and may be registered in the United States of America and/or other countries. All other names may be trademarks of their respective owners. This guide may contain links to third-party Web sites that are not under the control of Raima Inc. and Raima Inc. is not responsible for the content on any linked site. If you access a third-party Web site mentioned in this guide, you do so at your own risk. Inclusion of any links does not imply Raima Inc. endorsement or acceptance of the content of those third-party sites. 2
TFS Configuration and Extension API Guide Contents Contents 3 Introduction 5 TFS Server Configurations 6 Introduction 6 Direct-Link Configuration 6 Direct-Link Configuration (TFST): 9 Client-Server Configuration (TFSR) 10 Standalone Configuration (TFSS) 10 Standard Client/Server Configuration 11 Standalone Configuration 12 TFS Configuration Settings 14 TFS Server Extension API 18 Introduction 18 Step 1: Set Up Hybrid Environment 18 Step 2: Add XAPI Functions 18 Step 3: Querying the Database 22 Enhanced HTTP Monitor 27 HTTP Extension API Functions 36 http_freeURLArgs 37 http_getURLArgValue 38 http_initURLArgs 39 Return Codes 39 http_printf 41 http_URLDecode 43 Summary Listing of TFS API Functions 44 d_tfsdisconnect 45 d_tfsinit, d_tfsinitEx 48 Contents 3
TFS Configuration and Extension API Guide d_tfsIterateConnectedUsers 52 d_tfsrun 55 d_tfsstop 57 d_tfsterm 59 d_tfsversion 61 d_tfsxapiparams 63 Glossary 67 Index 78 Contents 4
TFS Configuration and Extension API Guide Introduction RDM's Transactional File Server (TFS), in addition to controlling database access from runtime libraries, is also a simple HTTP server. This means that the TFS is prepared to service the RPCs from runtimes, and also GET and POST messages sent from a HTTP client. The first implication of this capability is that the TFS can serve HTML pages, contained in files, to HTTP clients. This can be a convenient way to share information from the TFS host computer without needing to run a full HTTP server. The RDM TFS may also be extended such that a programmer can create functions that are linked into the TFS and are accessible from HTTP clients through standard URLs. These functions may do anything within the TFS environment, including accessing databases. This means that an RDM developer has the ability to customize the TFS, adding functionality that can be accessed through programs or through standard HTTP clients. Unmodified, the TFS services runtime RPCs and HTML file requests. Modified by a programmer, the TFS can recognize additional URLs with parameter strings that are passed to Extension API functions. An additional ability to select a configuration will be described in this section. Application systems can be con- structed that have a client/server architecture or an in-process architecture. Hybrids can be constructed to suite specific needs. The following section describes the configuration options. Introduction 5
TFS Configuration and Extension API Guide TFS Server Configurations Introduction The TFS functionality is accessed through an API. This API is reentrant, so that its functions may be accessed by multiple threads concurrently. Anything that can be done with a database is done through the TFS API. The runtime library is linked into an application's program space, and performs caching of database pages and manipulations of those page contents in order to implement database queries and updates. The application uses the runtime's API, sometimes referred to as the "d_" API. To obtain a page from a database, the runtime must call a TFS API function. To lock a record or set type, a TFS API function is called. To perform an update to the database (transaction), a series of TFS API's are called. The location and invocation of TFS functions is configurable. The normal configuration is to have the TFS API directly linked into the application program. However, the TFS can be available through a multi- threaded TFS Server. This is what the tfserver utility is, where applications linked with runtimes remotely access TFS functions through a server, running in a different process. A third configuration, discussed below, is a single-process, single-thread application. This special situation does- n't require much of the TFS functionality, and a special compact TFS is available for this situation. The TFS Configuration types listed below are enumerated types used by d_tfsinitEx and rsqlTFSIn- itEx. TFS Configuration Types TFS_TYPE_DEFAULT Factory default TFS type is TFS_TYPE_TFS. TFS_TYPE_TFS See Direct-Link Configuration TFS_TYPE_RPC See Standard Client/Server Configuration TFS_TYPE_STANDALONE See Standalone Configuration If a TFS type is not specified, the default TFS type will be used by functions d_tfsinit, rsqlTFSinit and d_opentask. Installations with source code can change this default. Direct-Link Configuration If an application does not require a separate server, it is possible to link the TFS API with the application to make it run in-process. Because the TFS functions are reentrant, this application may be multi-threaded. Figure 14-2 shows this configuration. TFS Server Configurations 6
TFS Configuration and Extension API Guide Fig. 14-2. Direct-Link Configuration An obvious benefit of this configuration is that the calls from the runtime to the TFS have no intermediate mar- shalling/demarshalling or TCP/IP send and receive, so this application should perform better than the same appli- cation in the client/server configuration. Note that since the RPC mechanism in the client/server configuration makes the TFS functions look local, there are no changes required to the application or runtime library to make them work in either configuration. TFS Server Configurations 7
TFS Configuration and Extension API Guide Now note the similarity between the TFS Server Process in Figure 14-1 and the Application Program in Figure 14-2. The only difference between the Server Program and Application Program is that the Server Program starts up threads that exist to service connections with other runtimes and call TFS stub functions. The Appli- cation Program threads can exist side-by-side with the server connection threads, and an Application Program has the ability to start them up if it chooses. If it starts up connection threads, then it is acting as a TFS to other applications that are configured to run in the client/server configuration. Figure 14-3 attempts to illustrate this con- figuration, which is a combination of direct-link and client/server. Fig. 14-3. Hybrid Direct-Link, Client/Server Configuration TFS Server Configurations 8
TFS Configuration and Extension API Guide By starting up the server connection threads, the application is allowing other applications to have access to the databases that are under the control of this TFS (application). The code below shows the necessary code to start up the server connection threads. TFS_HANDLE hTFS; /* handle to control TFS server connection threads */ char *docroot = "c:/RDM/databases"; /* should be command-line option */ int32_t rc; ... if ((rc = d_tfsinit(docroot, NULL, &hTFS)) != S_OKAY) error_exit(rc); if ((rc = d_tfsrun(hTFS, TRUE, NULL)) != S_OKAY) error_exit(rc); /* begin Application code */ ... /* Application termination */ if ((rc = d_tfsstop(hTFS)) == S_OKAY) /* stop the server threads */ d_tfsterm(hTFS); /* free resources */ It is possible to set the configuration programmatically through the use of the d_tfsinitex(..) function with one of the following three parameters: TFS_TYPE_TFS, TFS_TYPE_STANDALONE, or TFS_TYPE_RPC as follows: Direct-Link Configuration (TFST): This configuration runs the TFS engine within your application, and the database is stored there. The TFST con- figuration is ACID compliant. Optionally, the ability to accept remote connections (set in those applications as clients using TFS_TYPE_RPC) can also be enabled, allowing your application to act as a server to other users. TFS_HANDLE hTFS; TFS_PARAMS tparams; tparams.port= 21553; tparams.rd_only= FALSE; tparams.no_disk= FALSE; tparams.verbose= FALSE; tparams.logfile= NULL; tparams.stdout_file= NULL; /* start Direct-Link TFS configuration */ sStatus= d_tfsinitEx ("/my/directory", &tparams, &hTFS, TFS_TYPE_TFS); if (sStatus == S_OKAY) { DB_TASK *task; d_opentask (&task); ... d_closetask (task); TFS Server Configurations 9
TFS Configuration and Extension API Guide d_tfsterm (hTFS); } Client-Server Configuration (TFSR) This configuration does not run any TFS engine in your application, requiring it to connect to a TFS (either tfserver or another application in TFST configuration) hosting the database over TCP/IP. This configuration is also ACID compliant. TFS_HANDLE hTFS; TFS_PARAMS tparams; tparams.port= 21553; tparams.rd_only= FALSE; tparams.no_disk= FALSE; tparams.verbose= FALSE; tparams.logfile= NULL; tparams.stdout_file= NULL; /* start Direct-Link TFS configuration */ sStatus= d_tfsinitEx (NULL, &tparams, &hTFS, TFS_TYPE_RPC); if (sStatus == S_OKAY) { DB_TASK *task; d_opentask (&task); ... d_closetask (task); d_tfsterm (hTFS); } Standalone Configuration (TFSS) This configuration runs a TFS engine within your application, however it is not multi-user capable (and therefore cannot accept incoming connections), and is not ACID compliant. It is very fast however, and is useful for sit- uations where complete safety is not required. TFS_HANDLE hTFS; TFS_PARAMS tparams; tparams.port= 21553; tparams.rd_only= FALSE; tparams.no_disk= FALSE; tparams.verbose= FALSE; tparams.logfile= NULL; tparams.stdout_file= NULL; /* start Direct-Link TFS configuration */ TFS Server Configurations 10
TFS Configuration and Extension API Guide sStatus= d_tfsinitEx ("/my/directory", &tparams, &hTFS, TFS_TYPE_STANDALONE); if (sStatus == S_OKAY) { DB_TASK *task; d_opentask (&task); ... d_closetask (task); d_tfsterm (hTFS); } This hybrid configuration may involve application programs that are all identical (i.e. there is one designated to be the server, and others are clients), or the server program may be unique while client programs are different. An additional function exists to inform a program of the configuration in which it is running, in case there is different program logic involved, or if it is an error condition. This is shown by example below. uint16_t major; /* RDM major version number */ uint16_t minor; /* RDM minor version number */ TFS_LIB_TYPE type; /* TFS Library type */ ... d_tfsversion(&major, &minor, &type); switch (type) { case TFS_LIB_TYPE_TFS: /* this program is direct-linked to the TFS library */ ... break; case TFS_LIB_TYPE_RPC: /* this program is linked as a client to the server, using RPCs */ ... break; case TFS_LIB_TYPE_STANDALONE: /* this program is linked to the standalone TFS library */ /* only one thread may access the database functions */ ... break; } Note that there are two library types where starting up server connection threads does not make sense (TYPE_ RPC and TYPE_STANDALONE), but in these libraries, the d_tfsinit, d_tfsrun, d_tfsstop and d_ tfsterm functions simply return successfully, so there is no need to build an application in two ways if it is intended for two configurations. In fact, the TYPE_STANDALONE configuration requires the use of the d_ tfsinit function to establish a root directory for the databases (if not always the current directory). Standard Client/Server Configuration The runtimes and TFS are running within different processes. The runtimes invoke the TFS functions through a Remote Procedure Call (RPC) mechanism, as shown in Figure 14-1 below. TFS Server Configurations 11
TFS Configuration and Extension API Guide Fig. 14-1. Standard Client/Server Configuration In the client/server configuration, any number of runtimes can be connected to the TFS process. If an application program is multi-threaded, each thread can establish a connection with the server. For each runtime connection, the server will spawn a thread to service the RPCs from that thread for the duration of the thread's activity. In this client/server configuration, the application process may be on the same computer as the server process, or a different one. The TFS proxies that are linked into the application process "act like" the actual TFS API functions. The proxies will marshal the input parameters and send them in a packet to the server. The server will determine, from the contents of the packet, which function is being called, and will call the corresponding stub function. The stub func- tion will interpret the marshaled parameter values and then call the real TFS function with those parameter values. Upon return from the function, there may be output parameters and a return code. These are all mar- shaled into a packet that is returned to the client, where the values are demarshaled and returned to the appli- cation. Again, the application, calling a TFS API function, does not know that the actual function was not local. Standalone Configuration The standalone configuration uses a version of the TFS API that assumes that only one thread within one proc- ess will be calling the functions. With this assumption, a number of simplifications can be made: TFS Server Configurations 12
TFS Configuration and Extension API Guide l The program has exclusive access to all databases, even when opening them in shared mode. So all lock- ing functions are accepted, but have no effect. l No changes are ever made by other runtimes, so the cache need not be flushed, and the TFS need not keep a store of the modified pages. l Read-only-transactions don't require any cache versioning because no other runtimes are making changes. NOTE: The implementation of transactions in the standalone configuration leaves a database vul- nerable to corruption if there is an interruption of the program's processing during the commit of a trans- action, or if the computer or operating system crash before the database files are closed. It is not recommended that this configuration be used in unstable environments. All of the above differences amount to an extremely high-performing configuration. If this configuration satisfies an application's requirements, it is preferable to the others. The figure below illustrates the standalone configuration. Fig. 14-4. Standalone Configuration TFS Server Configurations 13
TFS Configuration and Extension API Guide TFS Configuration Settings Aspects of the runtime environment of RDM can be configured using a configuration file, or programmatically through the API. The TFS environment can be configured using configuration files, through environment var- iables, or on utility command-lines. Variables set in the environment take precedence over variables set in the configuration file variables set programmatically, or on a command-line will take the highest precedence. The TFS configuration affects the behavior of the TFS (tfserver) and the other utilities that have direct access to the files in the document root. There is a global configuration file, tfs.ini, kept in the document root of the TFS, that applies to all databases stored within the document root. Each database may also have its own con- figuration file for database specific settings related to mirroring and replication. These parameters affect the databases regardless of the property name settings of the runtimes, since TFS configuration properties must apply to all users of the databases. The tfs.ini and dbname.ini files may contain the same property name/value pairs, and the database-spe- cific file has priority. The priority of the property name values are as follows: l If the dbname/dbname.ini exists, and if the property name is specified, use this value, l Else if tfs.ini exists, and if the property name is specified, use this value, l Else use the default value (shown below). The following example shows the potential placement of configuration files: c:\RDM\databases tfs.ini phlist\ phlist.ini ... (other database files) tfs.corporate.com-21553\ phlist\ ... (other database files) mkt\ ... (other database files) tims\ tims.ini ... (other database files) This example shows two databases that have their own configuration files, phlist and tims. Two databases have none, tfs.corporate.com-21553/phlist and mkt. Since there is a tfs.ini file in the document root, any property names that do not exist in the database directories will be obtained from this file. Environment Variables Variable Name Description RDM_DOCROOT In the absence of a command-line specification of the document root (-d option), tell tfserver, dbmirror, dbrep or dbrepsql to use this directory instead of the current directory for the document root. TFS Configuration Settings 14
TFS Configuration and Extension API Guide Variable Name Description RDM_TFSERVER In the absence of a command-line specification of the host name and port number the run- time can locate the TFS to connect to using the contents of this variable: RDM_TFSERVER=localhost:21553 Configuration File (tfs.ini, dbname.ini) The RDM TFS configuration file follows the standard formatting for INI text files (See Wikipedia). An INI file can hold a number of sections, each section consist of a section name enclosed in bracket followed by a number of properties. Each property consists of a name followed by an equal sign and a value. A semicolon marks the beginning of a comment that continues to the end of the line. Section names and variable names will be case insensitive. Unrecognized section names and properties as well as properties appearing in the wrong sections will be ignored by the system. Only two sections, [configuration] and [LogCleanup], are used by the TFS. The function d_dbsetini has been provided to set the database-specific values when a database is open in exclu- sive mode. To programmatically set the tfs.ini values, you must use the psp_iniSet function. Since the configuration files are simple text files, it is possible to create and edit them with common text editors. Update access to the document root is required. The currently supported properties and associated section names are located in the table below. [configuration] ; The following settings are only read from tfs.ini and apply to all databases ; Maximum number of users connected to the TFS, between 16 and 1000, defaults to 256 maxusers=256 ; Maximum number of files per database, between 16 and 65535, defaults to 4096 maxfiles=4096 ; The following settings can appear in either tfs.ini or dbname.ini ; Set to 1 (on) to enable sorting based on system locale, default is 0 (off). use_string_locale=0 ; Set to 0 (off) to disable file syncing to disk. This will improve per- formance ; but at a risk of data loss. Default is 1 (on). synclogfiles=1 ; Specify the type of compression to be used for log files. ; Compression types: ; none : No compression TFS Configuration Settings 15
TFS Configuration and Extension API Guide ; zero : Compress zeros (default) logfile_compression=zero ; Enable replication. 0=off (default) and 1=on. Enabling this property ; will cause the runtime to generate replication log files for use ; in a replicated environment. replication=0 ; Enable mirroring. 0=off (default) and 1=on. Enabling this property ; will cause the TFS to generate mirroring log files for use ; in a mirrored environment. mirroring=0 ; The number of milliseconds delay between checkpoint operations for a ; database (default is 1000 ms for disk based databases and 100 ms for ; in memory databases). checkpoint_frequency=1000 ; Set to 0 to disable single slave mode, when you have more than one ; slave connected to a single master. Single slave mode optimizes ; log file cleanup when there is only one slave. This option is enabled by default ; and will automatically be disabled if a second slave is detected. SingleSlaveMode=1 [LogCleanup] ; LogCleanup settings are used to specify when log files can be removed to ; prevent the disk from filling up during the mirroring or replication activ- ity. ; LogFileAge specifies when a log file can be removed base on file date and time. ; If the log file's age is greater than the specified value, it will be removed. ; Values can be specified as s (seconds), m (minutes), h (hours), d (days). ; Care should be used when specifying a value in seconds as a value too small ; may cause log files to be cleaned up before they have a chance to mirror to the slave. ; (examples: 30s | 10m | 2h | 1d). ; If no unit character is specified, minutes will be assumed. ; Default is 10 minutes. LogFileAge=10m ; LogFileSpace specifies the amount of disk space that can be used by log files. ; Space is calculated per database. If the total size of all log files is ; greater than this value, they will be removed (oldest first). Values can be ; specified as k (kilobytes), m (megabytes), g (gigabytes). ; (ex: 500k | 100m | 1g). If no unit character is specified, kilobytes will ; be assumed. TFS Configuration Settings 16
TFS Configuration and Extension API Guide LogFileSpace=0 TFS Configuration Settings 17
TFS Configuration and Extension API Guide TFS Server Extension API Introduction By default, the RDM TFS program called tfserver will serve static HTML files to HTTP clients. However, addi- tional customized functions may be added to your own custom-built HTTP server. In this section, we will create a simple hybrid direct-link configuration (as defined in the Direct-Link Configuration section) that has customized extensions available for use by HTTP clients. In this example, we will generate HTML so that the HTTP client can be any web browser. The starting point will be the Market example. It is already coded to detect whether it is supposed to run as a TFS or not (using the passed in parameter). Step 1: Set Up Hybrid Environment The hybrid environment requires the program that is designated as the server to initialize using the TFST library. Only one program that wants to use databases hosted by this TFS instance may run this way. On Windows, it could look like this: marketExample –tfs TFST –d c:\RDM\databases This instance of marketExample will be acting as a market application and as a TFS to other market appli- cations. All other market application instances should be run using the TFSR library. On Windows it could look like this: marketExample -tfs TFSR At this point you can verify that the market application is working correctly. Please examine the function star- tAsTFS in the example code GettingStarted/examples/market/marketExample_main.c. Step 2: Add XAPI Functions The Market example has no extension functions. In this step, we will add two functions. The first one will be used to produce an HTML file that lists all investors with their current totals. In that HTML file will be links to the second extension function which lists the details of a particular investor. The first function we will call investorList, and the second investorDetail. The first function requires no parameters. The second function requires an investor ID. The d_tfsxapiparams function is called to set the XAPI parameters. Here is code that correctly sets up two functions to be called when named by an HTTP client: TFS Server Extension API 18
TFS Configuration and Extension API Guide /* marketExample_main.c */ #include "rdmhttp.h" int32_t investorList(RHS_HANDLE, PSP_OUTPUTBUFF, const char*, const char*, const char*); int32_t investorDetail(RHS_HANDLE, PSP_OUTPUTBUFF, const char*, const char*, const char*); static const TFS_XAPI_FCNMAP mktfcnmap[] = { { "/investorList", (TFS_XAPI_FCN *)investorList }, { "/investorDetail", (TFS_XAPI_FCN *)investorDetail } }; #define NUM_MKTFCNS RLEN(mktfcnmap) ... /* In the startAsTFS function */ TFS_XAPI_PARAMS xapi_params; ... xapi_params.xapifcnmap = mktfcnmap; xapi_params.fcnmapsize = NUM_MKTFCNS; xapi_params.subdocroot = "/mkt"; rc = d_tfsinitEx(full_docroot, &tparams, hTFS, cmd_status->tfs_type); if(rc == S_OKAY) { /* We check using d_tfsversion so that we can determine what * TFS_TYPE_DEFAULT resolves to */ rc = d_tfsversion(&major, &minor, &tfs_type); { if (rc == S_OKAY) { /* Direct linked TFS library, start server */ if (tfs_type == TFS_TYPE_TFS) { rc = d_tfsxapiparams(hTFS, &xapi_params); if(rc == S_OKAY) { rc = d_tfsrun(*hTFS, TRUE, &tfs_done); if(rc != S_OKAY) { printf("Error starting TFS threads - %s (%d): %s\n", d_errorname(rc), rc, d_errorstr(rc)); } } } } } } else { TFS Server Extension API 19
TFS Configuration and Extension API Guide printf("Error initialzing TFS - %s (%d): %s\n", d_errorname(rc), rc, d_ errorstr(rc)); } ... When the TFS (your own application which starts up the TFS threads) is built and run, you can access these func- tions from a web browser. The address for these functions is formed by identifying the domain under which the TFS is running, the correct port, then the function name as identified in the first element if the TFS_XAPI_ FCNMAP structure. For these two functions, the full address may look like the following: http://localhost:21553/investorList or http://localhost:21553/investorDetail?invID=3& Note that the first function, investorList, is shown with no parameters. This is because the function itself will not be affected by parameters, but simply produces the current list of investors. The second function, investorDetail, has one parameter, invID. In the example, the value is 3. The definition of these functions follows their intended use. The investorList function is an entry point that produces a list of investors together with links to the investor details. Thus, the investorDetail function is intended to be used from within hyperlinks in an HTML page, with the parameter value matching the name of an investor. The functions have the following prototype: int32_t fcnName(RHS_HANDLE hRHS, PSP_OUTPUTBUFFoutbuff, const char *args, const char *raw_args, const char *content); While the function is active, it can perform any function available to it, especially access to an RDM database. The PSP_OUTPUTBUFF parameter must be used as input to the http_printf function, as this is the reply that will be sent back to the HTTP client. The first character (args) points to a string representing the param- eters that were sent in the URL. . The string in args is URL decoded. The second string (raw_args) points to a string containing the raw (URL encoded) argument list. The third string (context), if not NULL, points to the content portion of the HTTP message, which will be present with a POST method. Below is an example of how the upper level of these two functions may be coded. static void EXTERNAL_FCN HttpErr(int32_t, const char*, void*, DB_TASK*); ... /* investor list XAPI function */ int32_t investorList( RHS_HANDLE hRHS, TFS Server Extension API 20
TFS Configuration and Extension API Guide PSP_OUTPUTBUFF outbuf, const char *args, const char *raw_args, const char *content) { int32_t status; DB_TASK *task; /* prepare to use the database */ d_opentask(&task); d_set_dberr_ex(HttpErr, (void *)outbuf, task); if ((status=d_open("mkt", "s", task)) != S_OKAY) { http_printf(outbuf, "Error %d opening mkt database", status); return S_OKAY; } /* bare-bones HTML to surround the output */ http_printf(outbuf, "\n"); http_printf(outbuf, "List of Investors\n"); investor_list_html(outbuf, task); http_printf(outbuf, "\n"); d_close(task); d_closetask(task); return S_OKAY; } /* investor detail XAPI function */ int32_t investorDetail( RHS_HANDLE hRHS, PSP_OUTPUTBUFF outbuf, const char *args, const char *raw_args, const char *content) { int32_t status; DB_TASK *task; /* prepare to use the database */ d_opentask(&task); d_set_dberr_ex(HttpErr, (void *)outbuf, task); if ((status=d_open("mkt", "s", task)) != S_OKAY) { http_printf(outbuf, "Error %d opening mkt database", status); return S_OKAY; } /* bare-bones HTML to surround the output */ http_printf(outbuf, "\n"); TFS Server Extension API 21
TFS Configuration and Extension API Guide http_printf(outbuf, "Investor Detail\n"); investor_detail_html(hRHS, outbuf, args, task); http_printf(outbuf, "\n"); d_close(task); d_closetask(task); return S_OKAY; } Any XAPI function may not print to stdout or stderr, because it may appear in the program that is running the TFS. All output is to be generated for the client through the http_printf function. The d_set_dberr_ex function is used to prevent the standard dberr function from printing to stderr. It is optional whether HTML is generated by the HttpErr function, but an example of it is shown below. static void EXTERNAL_FCN HttpErr( int32_t err, const char *errmsg, void *ob, DB_TASK *task) { /* avoid printing to stdout */ http_printf((PSP_OUTPUTBUFF)ob, "Database error %d: %s\n", err, errmsg); } Step 3: Querying the Database In this example, the functions doing the database work are named investor_list_html and investor_ detail_html. They will be fetching information from the database and producing HTML output. First, we will have investor_list_html produce a table row for each investor record that is read. The fol- lowing code produces a row containing the investor ID, investor name, and the liquid funds. The investor ID field will have a hyperlink added that references the second function, so that the correct reference is generated when the ID is clicked. static int32_t investor_list_html(PSP_OUTPUTBUFF, DB_TASK*); ... static int32_t investor_list_html( PSP_OUTPUTBUFF outbuf, DB_TASK *task) { int32_t rc; struct investor investorRec; TFS Server Extension API 22
TFS Configuration and Extension API Guide /* Lock the FUND and INVESTOR records for read access see mktfcns.c */ if ((rc = d_lock(investor_fund_r_sz, investor_fund_r, task, 0)) != S_OKAY) return -1; http_printf(outbuf, ""); for (rc = d_keyfrst(INVESTOR_INVID, task, 0); rc == S_OKAY; rc = d_keynext(INVESTOR_INVID, task, 0)) { if ((rc = d_recread(&investorRec, task, 0)) != S_OKAY) return -1; /* the ID hyperlink, and the ID */ http_printf(outbuf, "%d", investorRec.invID, investorRec.invID); /* the investor name and liquid funds */ http_printf(outbuf, "%s$%.2f\n", investorRec.name, investorRec.money_mkt); http_printf(outbuf, "\n"); } http_printf(outbuf, ""); if (rc == S_NOTFOUND) rc = S_OKAY; d_freeall(task); return rc; } The second function, investor_detail_html, must parse the argument string to obtain the investor ID, look up the investor from the ID, then generate HTML output containing that investor's data. In the code snippet below, the function obtains the ID using http_getURLArgValue from RDM's HTTP support library functions. First, args is parsed into the urlargs structure. Then this structure is searched for the value matching the invID key. Since this key/value pair is generated by our own investorList function, it should be valid. int32_t investor_detail_html(RHS_HANDLE, PSP_OUTPUTBUFF, const char*, DB_TASK*); ... int32_t investor_detail_html( RHS_HANDLE hRHS, PSP_OUTPUTBUFF outbuf, const char *args, DB_TASK *task) { int32_t rc; TFS Server Extension API 23
TFS Configuration and Extension API Guide const URLARGS *urlargs; int16_t invIDVal; const char *invIDptr; double total_funds; double assetsValue; struct investor investorRec; struct fund fundRec; struct asset assetRec; struct trans transRec; struct stock stockRec; double current_value; /* locate this investor based on ID */ if ((rc = http_initURLArgs(hRHS, args, &urlargs)) != S_OKAY) return rc; invIDptr = http_getURLArgValue("invID", urlargs); if (invIDptr == NULL) { http_printf(outbuf, "Invalid parameters\n"); http_freeURLArgs(urlargs); return rc; } invIDVal = atoi(invIDptr); http_freeURLArgs(urlargs); /* look up investor and generate HTML */ rc = d_lock(investor_fund_asset_trans_stock_r_sz, investor_fund_asset_trans_stock_r, task, 0); if (rc != S_OKAY) return -1; if((rc = d_keyfind(INVESTOR_INVID, &invIDVal, task, 0)) != S_OKAY) { d_freeall(task); if(rc != S_NOTFOUND) { http_printf(outbuf, "Error %d looking up investor with ID of %d", rc, invIDVal); } else { http_printf(outbuf, "Unable to find investor with ID of %d", invIDVal); } return -1; } if ((rc = d_setor(FUNDING, task, 0)) != S_OKAY) return -1; if ((rc = d_setor(INV_TRANS, task, 0)) != S_OKAY) return -1; TFS Server Extension API 24
TFS Configuration and Extension API Guide if ((rc = d_recread(&investorRec, task, 0)) != S_OKAY) return -1; http_printf(outbuf, "\nInvestor (%d) %s\n", investorRec.invID, invest- orRec.name); total_funds = 0; http_printf(outbuf, ""); http_printf(outbuf, "Funding"); for (rc = d_findfm(FUNDING, task, 0); rc == S_OKAY; rc = d_findnm(FUNDING, task, 0)) { if ((rc = d_recread(&fundRec, task, 0)) != S_OKAY) return -1; http_printf(outbuf, "$%-7.2f", fundRec.amount); total_funds += fundRec.amount; } http_printf(outbuf, ""); if (rc != S_EOS) /*lint !e850 */ return -1; assetsValue = 0; /* prerequisite: current owner of INV_TRANS */ for (rc = d_findfm(INV_TRANS, task, 0); rc == S_OKAY; rc = d_findnm(INV_TRANS, task, 0)) { if ((rc = d_setor(HISTORY, task, 0)) != S_OKAY) return -1; if ((rc = d_recread(&assetRec, task, 0)) != S_OKAY) return -1; if ((rc = d_findco(STOCK_TRANS, task, 0)) != S_OKAY) return -1; if ((rc = d_recread(&stockRec, task, 0)) != S_OKAY) return -1; http_printf(outbuf, ""); http_printf(outbuf, "ASSET: (%d) %s, currently $%-7.2f\n", stockRec.stkID, stockRec.company, stockRec.share_price); http_printf(outbuf, "Shares owned"UINT64_ SPEC"", assetRec.shares_owned); for (rc = d_findfm(HISTORY, task, 0); rc == S_OKAY; rc = d_findnm(HISTORY, task, 0)) /*lint !e445 */ { if ((rc = d_recread(&transRec, task, 0)) != S_OKAY) TFS Server Extension API 25
TFS Configuration and Extension API Guide return -1; http_printf(outbuf, "%s"INT64_SPEC" @ $%- 7.2f", transRec.shares > 0 ? "purchased": "sold", transRec.shares > 0 ? transRec.shares : -transRec.shares, transRec.value); } if (rc != S_EOS) /*lint !e850 */ return -9; current_value = (double) assetRec.shares_owned * stockRec.share_price; http_printf(outbuf, "Current value$%-7.2f", cur- rent_value); assetsValue += current_value; http_printf(outbuf, ""); } http_printf(outbuf, ""); http_printf(outbuf, "Liquid funds$%-7.2f", investorRec.money_mkt); http_printf(outbuf, "Net worth:$%-8.2f", investorRec.money_mkt + assetsValue); http_printf(outbuf, "Profit/Loss:$%-7.2f", investorRec.money_mkt+assetsValue-total_funds); http_printf(outbuf, ""); d_freeall(task); return S_OKAY; } TFS Server Extension API 26
TFS Configuration and Extension API Guide Enhanced HTTP Monitor The Enhanced HTTP Monitor is a browser-based monitor/administrator that displays status of servers, data- bases, users, and Replication. It allows the starting and stopping of mirroring or replication if the appropriate servers are running. The user interface communicates to a TFS through HTTP requests. To protect security of the servers and data, we require that a user logs in before being able to perform any function in the Enhanced HTTP Monitor. Once logged in, all HTTP requests and responses are encrypted. See separate document on RDM TFS Admin Secu- rity. Due to the session-less nature of HTTP, encrypting every request ensures that the server only responds to valid (authorized) requests. The development build will create a default user account for user 'admin' with a password of 'secret'. The pass- word is encrypted and stored as a URL encoded string in the tfs.ini file in the [Accounts] section. Cus- tomers should create their own user accounts. This can be accomplished by running the tfsuser utility. The tfsuser utility will prompt for a password. The default user name is 'admin'. A different name can be specified on the command line. Run 'tfsuser –h' to see a complete list of command line options. It is important to know that all TFS servers that are to be access through a browser must have the same user- name and password. You must either run tfsuser with a -th option for each TFS running, or you must copy the [Accounts] entry from one tfs.ini file to all other server tfs.ini files. The same password is required on all servers because the main TFS, the one the user logs into, is used as a proxy server to all other servers. It is impractical to force the user to login separately to every server to which they might connect. Using the main TFS as a proxy server is required due to browser security restrictions. We cannot connect from a browser via AJAX to any other server. We can only connect to the server and port that sent the page currently active in the browser. HTTP request flow Enhanced HTTP Monitor 27
TFS Configuration and Extension API Guide Once logged in, every page contains one or more HTTP requests to a server. Internally, the username is used on every HTTP request and the password is used to encrypt the request sent to the server. The password is also used to decrypt the content of responses from the server. The password is never sent to the server. The content of a message is encrypted using the password. The server, which has a copy of the password, decrypts the mes- sage using the password. If the server is unable to decrypt the message, that means the user is not logged in, and an error is returned. If the server is able to perform the requested action, the response is encrypted using the password already stored on the server. The response is decrypted in the browser and the results are displayed. Users can logout from any page. The user's session can timeout. The default timeout value is 10 minutes. This value can be configured manually by adding a Timeout=xxx (in seconds) property to the [Accounts] section of the tfs.ini file. On a time- out or login error, the main login page is displayed. Enhanced HTTP Monitor 28
TFS Configuration and Extension API Guide After login, the main TFS page is displayed. This page shows all databases on this server, all users logged in to this server, any databases that are mirrored or replicated from or to this server, and the Replication settings for this server. Each box is expandable by clicking on the arrow to the left of each box's heading. The Databases box shows all databases that exist on this TFS. Clicking a database name will open a new tab with information about that database. The tab shows the name of the database and the server and port where the database exists (i.e.: test@EDH-Win7:21553). If the tab is already opened, it will be activated. Enhanced HTTP Monitor 29
TFS Configuration and Extension API Guide The database info page shows information about file locks, users with this database open, files used by this data- base and their allocation sizes. Also from the database page, the user can configure the Replication settings specific to this database. This allows the user to override the default settings from the TFS. For example, the user can enable mirroring log file generation for a specific database without the overhead of creating log files for all other databases controlled by this TFS. The user will make their changes and click the Apply button. To change this database to use the global TFS settings for Replication, click the Default button. If you want to open a connection to another TFS, click the '+' tab. Enhanced HTTP Monitor 30
TFS Configuration and Extension API Guide This creates a New tab that will ask for the host name and port of the requested TFS. When the Connect button is clicked, a connection will be made to this server. This tab will be renamed to the server's name and, if the server is available, the main TFS information page will be displayed for this server. If the connection already exists, that tab will be activated. Enhanced HTTP Monitor 31
TFS Configuration and Extension API Guide In the Users box on a TFS tab, all users that are connected to this server will display. You can disconnect a user by clicking on the X next to a user's login name. You cannot disconnect a user from a database tab, as a user may have more than one database opened. Care should be taken when disconnecting a user this way. You have no way to know if the user is in the middle of a transaction. If there are too many tabs to be displayed on the screen at one time, a drop down box is available from the down arrow on the right side of the tab row. From here you can go directly to any tab. Tabs can be closed by clicking on the red x next to their name. You cannot close the first tab to the main TFS. Tab names that are too long will be truncated and end with '...'. Enhanced HTTP Monitor 32
TFS Configuration and Extension API Guide There are three refresh settings, Off, 2 and 5. The default is to refresh the page every 2 seconds. The selected refresh rate will be underlined. Only the visible tab refreshes. Since each TFS controls its own session, each tab could timeout if they are in the background for too long. Therefore, tabs that are in the background are kept alive during each refresh interval internally without any action by the user. If the refresh setting is Off, the session will timeout if the session becomes idle. With refresh enabled, sessions with tabs will not timeout. If you want to start mirroring or replication, open a new tab connection to a slave TFS. In the Replication box, there are three sections; databases that this server is sending as a master, databases that this server is receiving as a slave, and a way to start a new database mirror or replication. Enhanced HTTP Monitor 33
TFS Configuration and Extension API Guide The title of the Replication box will change depending on the type of server associated with the TFS. The Rep- lication server type will be 'Mirroring Server', 'Replication Server' or 'SQL Replication Server'. The options (checkboxes) below the drop downs will change depending on the type of server. A mirroring server will have an option for 'synchronous' mirroring. A SQL replication server will have options for the type of destination SQL server (RDM Server, MySQL, MSSQL, or Oracle). It will also have a field to enter the DSN if necessary. The DSN will not be needed if the user set the RDSLOGIN environment variable before starting dbrepsql. All server types will have 'override in-memory' to allow a master in-memory database to be an on-disk database on a slave. The ability to start mirroring or replication will only appear if there are two or more TFS tabs open. From the slave TFS tab, the user will select a master TFS server from the 'Connected Masters' drop down. The 'Databases' Enhanced HTTP Monitor 34
TFS Configuration and Extension API Guide drop down will automatically update with the list of databases available from that master. When the 'Start' button is clicked, this TFS tab becomes a slave of the selected database from the selected master. If the user starts mirroring or replication, but the master is not configured to create log files for the appropriate type, an error message will be displayed. To stop mirroring or replication, simply click the Stop button from either the master's TFS tab or the slave's TFS tab. Enhanced HTTP Monitor 35
TFS Configuration and Extension API Guide HTTP Extension API Functions From within XAPI (HTTP extension API), these functions may be used to parse the incoming data and generate the outgoing data. These functions require the header file "rdmhttp.h" included in source files. To link these functions, the library name 'http' must be included (see Library Naming Conventions for library naming conventions). The following table lists alphabetically all the HTTP support functions, along with brief descriptions. Function Description http_freeURLArgs Frees structure allocated by http_initURLArgs http_getURLArgValue Retrieves a value given a key http_initURLArgs Parses arguments received through HTTP into key/value pairs http_printf Prints content for HTTP response http_URLDecode Decode incoming HTTP URL encoded string HTTP Extension API Functions 36
TFS Configuration and Extension API Guide http_freeURLArgs Free structure allocated for URL arguments Prototype void http_freeURLArgs( const URLARGS *urlargs); Parameters urlargs (input) Pointer to an allocated structure created by http_initURLArgs. Description This function is required to clean up memory allocated by the http_initURLArgs function. Required Headers #include "rdmhttp.h" Libraries Library Name Description rdmhttp11 RDM HTTP Library See Library Naming Conventions section for full library name and a list of library dependencies. Return Codes None. See Also http_initURLArgs http_getURLArgValue http_printf http_URLDecode HTTP Extension API Functions 37
TFS Configuration and Extension API Guide http_getURLArgValue Retrieve the value associated with a key Prototype const char *http_getURLArgValue( const char *key, const URLARGS *urlargs); Parameters key (input) A string identifying the key associated with the requested value. urlargs (input) Pointer to an allocated structure created by http_initURLArgs. Description This function searches through the key/value pairs represented in urlargs (must have been created by http_ini- tURLArgs) for the key. If found, a pointer to the value associated with key is returned. If the key is not found, NULL is returned. See the http_initURLArgs for more description and an example. Required Headers #include "rdmhttp.h" Libraries Library Name Description rdmhttp11 RDM HTTP Library See Library Naming Conventions section for full library name and a list of library dependencies. See Also http_initURLArgs http_freeURLArgs http_printf http_URLDecode HTTP Extension API Functions 38
TFS Configuration and Extension API Guide http_initURLArgs Parse HTTP arguments for access within functions Prototype void http_initURLArgs( RHS_HANDLE hRHS, const char *args, const URLARGS **urlargs); Parameters hRHS (input) HTTP Stream handle. args (input) Character string containing the URL arguments. urlargs (output) Pointer to an allocated structure created by http_initURLArgs. Description This function accepts the arguments string that appears after the '?' character on a URL, and parses them into key/value pairs that can be searched with the http_getURLArgValue function. When running in the XAPI environment (see d_tfsinit), the input to http_initURLArgs is the args parameter to the TFS_XAPI_FCN functions. Required Headers #include "rdmhttp.h" Libraries Library Name Description rdmhttp11 RDM HTTP Library See Library Naming Conventions section for full library name and a list of library dependencies. Return Codes Value Name Description 0 S_OKAY normal return, okay -82 S_INVURLARGFMT Invalid URL argument format -904 S_NOMEMORY out of memory HTTP Extension API Functions 39
TFS Configuration and Extension API Guide -924 S_INVNULL invalid NULL parameter See Also http_freeURLArgs http_getURLArgValue d_tfsinit http_printf http_URLDecode Example int32_t navigate_handler( RHS_HANDLE hRHS, PSP_OUTPUTBUFF outbuff, const char *args, const char *raw_args, const char *content { int32_t stat; const URLARGS *urlargs; /* 'args' is a string containing everything after the '?', for example, if the reference is 'http://localhost:21553/navigate.rdm?action=d_recfrst&' then args will be 'action=d_recfrst'. */ ... if ((stat=http_initURLArgs(hRHS, argc, &urlargs)) != S_OKAY) return stat; name = http_getURLArgValue("action", urlargs); if (strcmp(name, "d_recfrst") == 0) { ... /* produce output for browser */ http_printf(outbuff, "id_code=%s&info_title=%s&stat=%d&", code, title, stat); } else { http_printf(outbuff, "stat=%d&", stat); } http_freeURLArgs(urlargs); return stat; } HTTP Extension API Functions 40
TFS Configuration and Extension API Guide http_printf Print reply to HTTP request Prototype int32_t http_printf( PSP_OUTPUTBUFF outbuf, const char *fmt, ...); Parameters outbuff (input) Output stream that will be returned to the requestor. fmt (input) Pointer to printf style format string. Description This function acts like fprintf, except that the resulting string is put into outbuf, which will be sent to the HTTP client making the request that is currently being serviced. This function may only be used from within an XAPI function. See d_tfsinit for more description and example. The outbuf is passed to the TFS_XAPI_FCN. Required Headers #include "rdmhttp.h" Libraries Library Name Description rdmhttp11 RDM HTTP Library See Library Naming Conventions section for full library name and a list of library dependencies. Return Codes Value Name Description 0 S_OKAY normal return, okay -49 S_INVPTR invalid pointer -203 S_TX_NETWRITE failure to write data to network HTTP Extension API Functions 41
TFS Configuration and Extension API Guide See Also http_freeURLArgs http_getURLArgValue http_initURLArgs http_URLDecode HTTP Extension API Functions 42
TFS Configuration and Extension API Guide http_URLDecode Decode a URL encoded string Prototype void http_URLDecode( char *args, uunt32_t *result_len); Parameters args (in/output) URL encoded argument string. result_len (output) Length of decoded data. Description This function accepts a null-terminated string and decodes any URL encoding in the string. It is important to make sure that the string is encoded before using this function. If result_len is NULL, no length is returned. The decoding is done in-place. This is possible because decoded strings are always smaller than the encoded strings. Ex: %40 = '@' Required Headers #include "rdmhttp.h" Libraries Library Name Description rdmhttp11 RDM HTTP Library See Library Naming Conventions section for full library name and a list of library dependencies. See Also http_freeURLArgs http_getURLArgValue http_initURLArgs http_printf HTTP Extension API Functions 43
TFS Configuration and Extension API Guide Summary Listing of TFS API Functions The following table lists alphabetically the functions used to initialize the TFS in various configurations. Function Description d_tfsinit Provide TFS with parameters to start up as a server d_tfsinitEx d_tfsrun Begin running connections from other runtimes d_tfsstop Stop running connections from other runtimes d_tfsterm Terminate the use of the TFS, releasing resources d_tfsversion Obtain version and type of TFS library d_tfsxapiparams Provide TFS with parameters to start up as a HTTP server d_tfsIt- Query names of all users currently connected to a TFS erateConnectedUsers Summary Listing of TFS API Functions 44
TFS Configuration and Extension API Guide d_tfsdisconnect Disconnect a user connection from a TFS. Prototype int32_t d_tfsdisconnect( TFS_HANDLE hTFS, const char *hostname, uint16_t port, const char *username) int32_t d_tfsdisconnectW( TFS_HANDLE hTFS, const wchar_t *hostname, uint16_t port, const wchar_t *username) Parameters hTFS (input) Handle returned from a successful d_tfsinit call. hostname (input) Hostname of the TFS to query for user names. port (input) Port number of the TFS to query for user names. username (input) Username to disconnect Description This function disconnects a specific user from a TFS. Required Headers #include "rdm.h" Libraries Library Name Description rdmrdm11 RDM Runtime Library See Library Naming Conventions section for full library name and a list of library dependencies. Summary Listing of TFS API Functions 45
TFS Configuration and Extension API Guide Return Codes Value Name Description 0 S_OKAY normal return, okay -200 S_TX_ERROR generic tx_ error -202 S_TX_NETREAD failure to read data from network -203 S_TX_NETWRITE failure to write data to network -214 S_TX_CONNECT failed to connect to TFS -215 S_TX_HOSTNAME TFS host name not found -904 S_NOMEMORY out of memory See Also d_tfsIterateConnectedUsers Example int32_t EXTERNAL_FCN UserName_handler( const char *username) { TFS_HANDLE hTFS = NULL; /* This function is called once for each connected user to a TFS. Return S_OKAY to continue receiving user names. Return any other error to stop receiving user names. Ignore internal RDM connections. */ if (strncmp(username, "RDM.", 5) == 0) return S_OKAY; /* ignore internal connections */ printf("Username: %s\n", username); if (strcmp(username, "my_user") == 0) { if (d_tfsdisconnect(hTFS, "localhost", 21553, username) == S_OKAY) { printf("Disconnected user %s\n", username); return S_EOS; /* Return error to stop getting new user names */ } else printf("Error disconnecting user\n"); } return S_OKAY; } ... Summary Listing of TFS API Functions 46
TFS Configuration and Extension API Guide main() { TFS_HANDLE hTFS = NULL; int32_t rc; const char *docroot = "\data"; ... rc = d_tfsIterateConnectedUsers(hTFS, "localhost", 21553, UserName_handler); if (rc == S_OKAY) { ... } ... } Summary Listing of TFS API Functions 47
TFS Configuration and Extension API Guide d_tfsinit, d_tfsinitEx Provide TFS with parameters to start up as a server Prototype int32_t d_tfsinit( const char *docroot, const TFS_PARAMS *tparams, TFS_HANDLE *hTFS) int32_t d_tfsinitW( const wchar_t *docroot, const TFS_PARAMSW *tparams, TFS_HANDLE *hTFS) int32_t d_tfsinitEx( const char *docroot, const TFS_PARAMS *tparams, TFS_HANDLE *hTFS, TFS_TYPE tfs_type) int32_t d_tfsinitExW( const wchar_t *docroot, const TFS_PARAMSW *tparams, TFS_HANDLE *hTFS, TFS_TYPE tfs_type) Parameters docroot (input) The directory under which all databases controlled by this TFS are stored. If "" or NULL is used, the environment variable RDM_DOCROOT is used, other- wise the current working directory is used. tparams (input) Parameters required for TFS operation. If NULL, defaults are used. hTFS (output) Handle used for running, stopping or terminating this TFS. tfs_type (input) Set type of TFS configuration. Description Call d_tfsinit to set up the TFS with non-default parameters. The d_tfsinit function should be called before any tasks are created. Any successful call to d_tfsinit requires a corresponding call to d_tfsterm. Summary Listing of TFS API Functions 48
TFS Configuration and Extension API Guide d_tfsinit and d_tfsterm are implemented using reference counting so they can be nested. Only the initial call to d_tfsinit and the final call to d_tfsterm will actually perform any useful work. This function does not have any effect when the RPC configuration is used. The current implementation always returns the handle as NULL. The d_opentask function call will automatically initialize the TFS with the default values if your application does not explicitly call this function prior to a call to d_opentask. TFS Configuration Types TFS_TYPE_DEFAULT Factory default TFS type is TFS_TYPE_TFS. TFS_TYPE_TFS See Direct-Link Configuration TFS_TYPE_RPC See Standard Client/Server Configuration TFS_TYPE_STANDALONE See Standalone Configuration Note: The TFS Configuration Type can only be changed after the d_tfsterm has been called. TFS_PARAMS(W) prototypes typedef struct { uint16_t port; uint32_t rd_only; uint32_t no_disk; uint16_t verbose; const char *logfile; const char *stdout_file; } TFS_PARAMS; typedef struct _tfs_paramsw { uint16_t port; uint32_t rd_only; uint32_t no_disk; uint16_t verbose; const wchar_t *logfile; const wchar_t *stdout_file; } TFS_PARAMSW; TFS_PARAMS struct members Element Declaration Description port uint16_t Server listen port rd_only uint32_t Read-only device, TRUE or FALSE. no_disk uint32_t Diskless mode, TRUE or FALSE. verbose uint16_t Verbose mode, TRUE or FALSE. logfile const char * File name to open for logging. Can be NULL. stdout_file const char * The name of a file to wirte informational messages instead of displaying them to stdout. If the value is NULL or "stdout" the messages will be sent to stdout. If the value is an empty string ("") no messages will be displayed. Summary Listing of TFS API Functions 49
You can also read