Reliable Transaction Router
C Application Programmer's
Reference Manual


Previous Contents Index


Chapter 4
Compiling and Linking Your Application

All client and application programs must be written using C, C++, or a language that can use RTR API calls. Include the RTR data types and error messages file rtr.h in your compilation so that it will be appropriately referenced by your application. For each client and server application, your compilation/link process is as follows:

  1. Write your application code using RTR calls.
  2. Use RTR data and status types for cross-platform interoperability.
  3. Compile your application code calling in rtr.h using ANSI C include rules. For example, if rtr.h is in the same directory as your C code, compile with the following statement: #include "rtr.h".
  4. Link your object code with the RTR library to produce your application executable.

This process is illustrated in Figure 4-1. In this figure, Library represents the RTR C API shareable images (OpenVMS), DLLs (Win32), and shared libraries (UNIX).

Figure 4-1 Compile Sequence


Compilers

Compilers commonly used in developing RTR applications include those in Table 4-1. For additional information, see the Reliable Transaction Router Software Product Description.

Table 4-1 Compilers for Developing RTR Applications
Operating System Compiler Compiler Version
Microsoft Windows Microsoft Visual C++ (Microsoft Visual Studio 6.0) Version 6.0 SP4
OpenVMS Alpha Compaq C Version 6.2-006
OpenVMS VAX Compaq C Version 6.2-003
Sun Workshop Compilers Version 4.2
Tru64 UNIX Compaq C Version 6.3-126

Linking Libraries

To compile and link a C RTR application, use command lines as shown below. Separate examples are shown for use of RTR with threaded or unthreaded libraries. You may need to specify library directories explictly if the RTR header files and libraries are not installed in the same directory or in system directories.

Windows


   > cl /c /MT  yourapp.c 
   > link yourapp.obj /out:yourapp.exe rtrdll.lib 

Tru64 UNIX

Single-threaded:


   # cc -o yourapp -lrtr yourapp.c 

Multi-threaded:


   # cc -o yourapp -pthread -lrtr_r yourapp.c 

OpenVMS Alpha

Single-threaded:


    $ cc yourapp.c 
    $ link yourapp,sys$input/opt 
    librtr/share 

Multi-threaded:


    $ cc yourapp.c 
    $ link yourapp,sys$input/opt 
    librtr_r/share 

OpenVMS VAX

Single-threaded:


    $ cc yourapp.c 
    $ link yourapp,sys$input/opt 
    librtr/share 

Multi-threaded:


    $ cc yourapp.c 
    $ link yourapp,sys$input/opt 
    librtr_r/share 

Sun

Single-threaded:


    $ cc -o yourapp -lrtr yourapp.c 

Multi-threaded:


    $ cc -o yourapp -mt -lrtr_r yourapp.c 


Appendix A
RTR C API Sample Applications

A.1 Overview

The software kit contains a short sample application that is unsupported and not part of the RTR product. Code for the sample application is in the [EXAMPLES] directory on the software kit. This sample application contains four components:

ADG_HEADER.h
ADG_SHARED.c
ADG_CLIENT.c
ADG_SERVER.c

The client and server code are shown on the next few pages. Note the following:

A.2 Client Application


/* Client Application */ 
 
/************************************************************************** 
* Copyright Compaq Computer Corporation 1998. All rights reserved. 
* Restricted Rights: Use, duplication, or disclosure by the U.S. Government 
* is subject to restrictions as set forth in subparagraph (c) (1) (ii) of 
* DFARS 252.227-7013, or in FAR 52.227-19, or in FAR 52.227-14 Alt. III, as 
* applicable. 
* This software is proprietary to and embodies the confidential technology of 
* Compaq Computer Corporation. Possession, use, of copying of this software 
* and media is authorized only pursuant to a valid written license from Compaq, 
* Digital or an authorized sublicensor. 
******************************************************************************/ 
/***************************************************************************** 
* APPLICATION: RTR Sample Client Application 
* MODULE NAME: adg_client.c 
* AUTHOR:      Compaq Computer Corporation 
* DESCRIPTION: This client application initiates transactions and requests 
*              transaction status asynchronously. It is to be used with 
               adg_server.c, adg_header.h, and adg_shared.c. 
* DATE       : Oct 22, 1998 
******************************************************************************/ 
/* 
    adg_client.c 
 
    Goes with adg_server.c 
 
    To build on Unix: 
        cc -o adg_client adg_client.c adg_shared.c -lrtr 
*/ 
 
#include "adg_header.h" 
 
void declare_client ( rtr_channel_t *pchannel ); 
FILE *fpLog; 
 
int main ( int argc, char *argv[] ) 
{ 
    /* 
     * This program expects 3 parameters : 
     *   1: client number (1 or 2) 
     *   2: partition range 
     *   3: messages to send 
     */ 
 
    rtr_status_t        status; 
    rtr_channel_t       channel ; 
    time_t time_val = { 0 }; 
 
    message_data_t send_msg = {0}; 
    receive_msg_t receive_msg = {0}; 
    int txn_cnt; 
    rtr_timout_t receive_time_out = RTR_NO_TIMOUTMS; 
    rtr_msgsb_t msgsb; 
    char CliLog[80]; 
 
    send_msg.sequence_number = 1 ; 
    strcpy( send_msg.text , "from Client"); 
 
    get_client_parameters( argc , argv, &send_msg, &txn_cnt); 
 
    sprintf( CliLog, "CLIENT_%c_%d.LOG", send_msg.routing_key, 
             send_msg.client_number ); 
    fpLog = fopen( CliLog, "w"); 
 
    if ( fpLog == NULL ) 
    { 
        perror("adg_client: fopen failed"); 
        fprintf(stderr, " Error opening client log %s\n", CliLog ); 
        exit(EXIT_FAILURE); 
    } 
 
    printf( "\n Client log = %s\n", CliLog ); 
 
    fprintf(fpLog, " txn count = %d\n", txn_cnt ); 
    fprintf(fpLog, " client number = %d\n", send_msg.client_number ); 
    fprintf(fpLog, " routing key = %c\n\n", send_msg.routing_key); 
 
    declare_client ( &channel ); 
 
    /* Send the requested number of txns */ 
 
    for ( ; txn_cnt > 0; txn_cnt--, send_msg.sequence_number++ ) 
    { 
        status = rtr_send_to_server( 
                channel, 
                RTR_NO_FLAGS , 
                &send_msg, 
                sizeof(send_msg), 
                MESSAGE_DATA_MSGFMT ); 
 
        check_status( "rtr_send_to_server", status ); 
 
        fprintf(fpLog, "\n *************    sequence %10d *************\n", 
                send_msg.sequence_number); 
        time(&time_val); 
        fprintf(fpLog, "   send_to_server at:         %s", 
                ctime( &time_val)); 
        fflush(fpLog); 
 
        /* 
         *  Get the server's reply OR 
         *  an rtr_mt_rejected 
         */ 
 
        status = rtr_receive_message( 
                        &channel, 
                        RTR_NO_FLAGS, 
                        RTR_ANYCHAN, 
                        &receive_msg, 
                        sizeof(receive_msg), 
                        receive_time_out, 
                        &msgsb); 
 
        check_status( "rtr_receive_message", status ); 
 
        time(&time_val); 
        switch (msgsb.msgtype) 
        { 
        case rtr_mt_reply: 
            fprintf(fpLog, "   reply from server at:      %s", 
                    ctime( &time_val)); 
            fprintf(fpLog, "     sequence %10d from server %d\n", 
                    receive_msg.receive_data_msg.sequence_number, 
                    receive_msg.receive_data_msg.server_number); 
            fflush(fpLog); 
            break; 
 
        case rtr_mt_rejected: 
            fprintf(fpLog, "  txn rejected at:            %s", 
                    ctime( &time_val)); 
            fprint_tid(fpLog, &msgsb.tid ); 
            fprintf(fpLog, "     status is : %d\n", status); 
            fprintf(fpLog, "     %s\n", rtr_error_text(status)); 
            fflush(fpLog); 
 
            /* Resend same sequence_number after reject */ 
            send_msg.sequence_number--; 
            txn_cnt++; 
            break; 
 
        default: 
            fprintf(fpLog, 
                    "  unexpected msg at: %s", ctime( &time_val)); 
            fprint_tid(fpLog, &msgsb.tid ); 
            fflush(fpLog); 
            exit(EXIT_FAILURE); 
        } 
 
 
        if (msgsb.msgtype == rtr_mt_reply) 
        { 
            status = rtr_accept_tx( 
                            channel, 
                            RTR_NO_FLAGS, 
                            RTR_NO_REASON ); 
 
            check_status( "rtr_accept_tx", status ); 
 
            status = rtr_receive_message( 
                            &channel, 
                            RTR_NO_FLAGS, 
                            RTR_ANYCHAN, 
                            &receive_msg, 
                            sizeof(receive_msg), 
                            receive_time_out, 
                            &msgsb); 
 
            check_status( "rtr_receive_message", status ); 
 
            time(&time_val); 
 
            switch ( msgsb.msgtype ) 
            { 
            case rtr_mt_accepted: 
                fprintf(fpLog, "   txn accepted at :          
                        %s", ctime( &time_val)); 
                fprint_tid(fpLog, &msgsb.tid ); 
                fflush(fpLog); 
                break; 
 
            case rtr_mt_rejected: 
                fprintf(fpLog, "   txn rejected at :          
                       %s", ctime( &time_val)); 
                fprint_tid(fpLog, &msgsb.tid ); 
                fprintf(fpLog, "      status is : %d\n", 
                       receive_msg.receive_status_msg.status); 
                fprintf(fpLog, " %s\n", 
                       rtr_error_text(receive_msg.receive_status_msg.status)); 
                fflush(fpLog); 
 
                /* Resend same sequence_number after reject */ 
 
                send_msg.sequence_number--; 
                txn_cnt++; 
                break; 
 
            default: 
                fprintf(fpLog, 
                        "    unexpected status on rtr_mt_accepted message\n"); 
                fprint_tid(fpLog, &msgsb.tid ); 
                fprintf(fpLog, "      status is : %d\n", 
                        receive_msg.receive_status_msg.status); 
                fprintf(fpLog, 
                " %s\n", rtr_error_text(receive_msg.receive_status_msg.status)); 
                fflush(fpLog); 
                break; 
            } 
        } 
 
 
    } 
 
    close_channel ( channel ); 
} 
 
void 
declare_client ( rtr_channel_t *pchannel ) 
{ 
    rtr_status_t        status; 
    receive_msg_t       receive_msg; 
    rtr_timout_t receive_time_out = RTR_NO_TIMOUTMS;  /* forever */ 
    rtr_msgsb_t msgsb;  /* Structure into which receive puts msgtype */ 
 
    status = rtr_open_channel( 
                    pchannel, 
                    RTR_F_OPE_CLIENT , 
                    FACILITY_NAME, 
                    NULL,                       /* rpcnam */ 
                    RTR_NO_PEVTNUM, 
                    NULL,                       /* access */ 
                    RTR_NO_NUMSEG , 
                    RTR_NO_PKEYSEG ); 
 
    check_status( "rtr_open_channel", status); 
 
    status = rtr_receive_message( 
                    pchannel, 
                    RTR_NO_FLAGS, 
                    RTR_ANYCHAN, 
                    &receive_msg, 
                    sizeof(receive_msg), 
                    receive_time_out, 
                    &msgsb); 
 
    check_status( "rtr_receive_message", status ); 
 
    if ( msgsb.msgtype != rtr_mt_opened ) 
    { 
       fprintf(fpLog, " Error opening rtr channel %s : \n", FACILITY_NAME); 
 
        fprintf(fpLog, "%s\n", 
                rtr_error_text(receive_msg.receive_status_msg.status)); 
        exit(EXIT_FAILURE); 
    } 
 
    fprintf(fpLog, " Client channel successfully opened\n"); 
    return; 
} 

A.3 Server Application


/* Server Application */ 
 
/*************************************************************************** 
* Copyright Compaq Computer Corporation 1998. All rights reserved. 
* Restricted Rights: Use, duplication, or disclosure by the U.S. Government 
* is subject to restrictions as set forth in subparagraph (c) (1) (ii) of 
* DFARS 252.227-7013, or in FAR 52.227-19, or in FAR 52.227-14 Alt. III, as 
* applicable. 
* This software is proprietary to and embodies the confidential technology of 
* Compaq Computer Corporation. Possession, use, of copying of this software 
* and media is authorized only pursuant to a valid written license from Compaq, 
* Digital or an authorized sublicensor. 
******************************************************************************/ 
/***************************************************************************** 
* APPLICATION: RTR Sample Server Application 
* MODULE NAME: adg_server.c 
* AUTHOR     : Compaq Computer Corporation 
* DESCRIPTION: This server application receives transactions and receives 
*              transaction status. It is to be used with adg_client.c, 
*              adg_header.h, and adg_shared.c. 
* DATE       : Oct 22, 1998 
******************************************************************************/ 
/* 
    adg_server.c 
      Goes with adg_client.c 
 
    To build on Unix: 
        cc -o adg_server adg_server.c adg_shared.c -lrtr 
*/ 
 
#include "adg_header.h" 
 
void declare_server (rtr_channel_t *channel, const message_data_t *outmsg); 
 
FILE *fpLog; 
 
int main( int argc, char *argv[] ) 
{ 
    /* 
     * This program expects 2 parameters : 
     *   1: server number (1 or 2) 
     *   2: partition range 
     */ 
 
    rtr_msgsb_t msgsb; 
    receive_msg_t receive_msg; 
    message_data_t reply_msg; 
    rtr_timout_t receive_time_out = RTR_NO_TIMOUTMS; 
    char SvrLog[80]; 
    time_t time_val = { 0 }; 
 
    rtr_channel_t   channel; 
 
    rtr_status_t    status      = (rtr_status_t)0; 
    rtr_bool_t replay; 
 
    strcpy( reply_msg.text , "from Server"); 
 
    get_server_parameters ( argc, argv, &reply_msg ); 
 
    sprintf( SvrLog, "SERVER_%c_%d.LOG", reply_msg.routing_key, 
             reply_msg.server_number ); 
    fpLog = fopen( SvrLog, "w"); 
 
    if ( fpLog == NULL ) 
    { 
        perror("adg_server: fopen() failed"); 
        printf( " Error opening server log %s\n", SvrLog ); 
        exit(EXIT_FAILURE); 
    } 
 
    printf( " Server log = %s\n", SvrLog ); 
 
    fprintf(fpLog, " server number = %d\n", reply_msg.server_number ); 
    fprintf(fpLog, " routing key = %c\n", reply_msg.routing_key); 
 
    declare_server(&channel, &reply_msg); 
 
    while ( RTR_TRUE ) 
    { 
        status = rtr_receive_message( 
                                     &channel, 
                                     RTR_NO_FLAGS, 
                                     RTR_ANYCHAN, 
                                     &receive_msg, 
                                     sizeof(receive_msg), 
                                     receive_time_out, 
                                     &msgsb); 
        check_status( "rtr_receive_message", status); 
 
        time(&time_val); 
 
        switch (msgsb.msgtype) 
        { 
        case rtr_mt_msg1_uncertain: 
        case rtr_mt_msg1: 
            if (msgsb.msgtype ==  rtr_mt_msg1_uncertain) 
                replay = RTR_TRUE; 
            else 
                replay = RTR_FALSE; 
 
           fprintf(fpLog, "\n *************    sequence %10d *************\n", 
                    receive_msg.receive_data_msg.sequence_number); 
 
            if ( replay == RTR_TRUE ) 
                fprintf(fpLog, "   uncertain txn started at :%s", 
                        ctime( &time_val)); 
            else 
                fprintf(fpLog, "   normal txn started at :%s", 
                        ctime( &time_val)); 
 
            fprintf(fpLog, "     sequence %10d from client %d\n", 
                    receive_msg.receive_data_msg.sequence_number, 
                    receive_msg.receive_data_msg.client_number); 
            fflush(fpLog); 
 
            reply_msg.sequence_number = 
                    receive_msg.receive_data_msg.sequence_number; 
 
            status = rtr_reply_to_client ( 
                                          channel, 
                                          RTR_NO_FLAGS, 
                                          &reply_msg, 
                                          sizeof(reply_msg), 
                                          MESSAGE_DATA_MSGFMT); 
 
            check_status( "rtr_reply_to_client", status); 
            break; 
 
        case rtr_mt_prepare: 
            fprintf(fpLog, "   txn prepared at :          %s", 
                    ctime( &time_val)); 
            fflush(fpLog); 
 
            status = rtr_accept_tx ( 
                                    channel, 
                                    RTR_NO_FLAGS, 
                                    RTR_NO_REASON); 
            check_status( "rtr_accept_tx", status); 
            break; 
 
        case rtr_mt_rejected: 
            fprintf(fpLog, "   txn rejected at :          %s", 
                    ctime( &time_val)); 
            fprint_tid(fpLog, &msgsb.tid ); 
            fprintf(fpLog, "      status is : %d\n", status); 
            fprintf(fpLog, "      %s\n", rtr_error_text(status)); 
            fflush(fpLog); 
            break; 
 
        case rtr_mt_accepted: 
            fprintf(fpLog, "   txn accepted at :          %s", 
                    ctime( &time_val)); 
            fprint_tid(fpLog, &msgsb.tid ); 
            fflush(fpLog); 
            break; 
 
        } /* End of switch */ 
    } /* While loop */ 
} 
 
void 
declare_server (rtr_channel_t *channel, const message_data_t *outmsg) 
{ 
    rtr_status_t    status; 
    rtr_uns_32_t    numseg = 1; 
    rtr_keyseg_t    p_keyseg[1]; 
    receive_msg_t  receive_msg; 
    rtr_timout_t receive_time_out = RTR_NO_TIMOUTMS;  /* forever */ 
    rtr_msgsb_t msgsb;   /* Structure into which receive puts msgtype */ 
    const char *facility = FACILITY_NAME; 
 
    p_keyseg[0].ks_type = rtr_keyseg_string; 
    p_keyseg[0].ks_length  = 1; 
    p_keyseg[0].ks_offset  =  0; 
    p_keyseg[0].ks_lo_bound = 
             /* const_cast */ (rtr_uns_8_t *)(&outmsg->routing_key); 
    p_keyseg[0].ks_hi_bound = 
             /* const_cast */ (rtr_uns_8_t *)(&outmsg->routing_key); 
 
    status = rtr_open_channel( 
                    channel, 
                    RTR_F_OPE_SERVER,/* | RTR_F_OPE_EXPLICIT_ACCEPT | */ 
                                     /*   RTR_F_OPE_EXPLICIT_PREPARE, */ 
                    facility, 
                    NULL,            /* rpcnam */ 
                    RTR_NO_PEVTNUM, 
                    NULL,            /* access */ 
                    numseg, 
                    p_keyseg); 
 
    check_status( "rtr_open_channel", status); 
 
    status = rtr_receive_message( 
                    channel, 
                    RTR_NO_FLAGS, 
                    RTR_ANYCHAN, 
                    &receive_msg, 
                    sizeof(receive_msg), 
                    receive_time_out, 
                    &msgsb); 
 
    check_status( "rtr_receive_message", status); 
 
    if ( msgsb.msgtype != rtr_mt_opened ) 
    { 
        fprintf(fpLog, " Error opening rtr channel %s: \n", facility); 
 
        fprintf(fpLog, "%s\n", 
                rtr_error_text(receive_msg.receive_status_msg.status)); 
        fclose (fpLog); 
        exit(EXIT_FAILURE); 
    } 
 
    fprintf(fpLog, "  Server channel successfully opened \n"); 
    return; 
} 
 

A.4 Active-X Case Study

The Active-X Case Study uses RTR deployed on three laptops to demonstrate the capabilities of RTR using one client and two servers. It displays a graph of the number of transactions that is continuously updated. Periodically, one of the servers goes off line, and the display and activity show RTR failing over to the other server while continuing to process transactions. The failure can be simulated or can be effected by someone disconnecting the cable from one of the laptops.

The code for the Active-X Case Study is available on the RTR website at http://www.compaq.com/rtr. The website also contains a short case study describing the demo in more detail.


Previous Next Contents Index