# hp Reliable Transaction Router
C Application Programmer's
Reference Manual

Previous | Contents | Index

# 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_client.c
> adg_server.c
> adg_shared.c
> adg_header.h

The code is shown on the next few pages. Note the following:

- Return value checking after `fprintf() fclose()` and so on, is omitted for clarity.
- `time()` and `ctime()` are used instead of higher resolution reentrant alternatives that are less portable.

# 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),
                    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,
                        RTR_NO_ACCESS               /* 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),
                                              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,
                        RTR_NO_ACCESS,   /* 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 Shared Code

    /* Shared Code */

    /*****************************************************************************
    * 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_shared.c
    * AUTHOR         : Compaq Computer Corporation
    * DESCRIPTION: This shared code is to be used with adg_server.c,
    *                          adg_header.h, and adg_client.c.
    * DATE           : Oct 22, 1998
    *******************************************************************************/

    #include "adg_header.h"

    void
    check_status( char *call, rtr_status_t status )
    {
        time_t time_val = { 0 };
        if (status != RTR_STS_OK)
        {
                    time(&time_val);
                    fprintf(fpLog, "    Call to %s failed at %s:\n",
                            call, ctime( &time_val));
                    fprintf(fpLog, "\n Call status = %s\n",
                            rtr_error_text(status));
                    fflush(fpLog);
                    exit(status);
            }
    }

    void
    get_server_parameters ( rtr_sgn_32_t argc, char *argv[], message_data_t
    *o_msg)
    {
        String31 buffer;
      if (argc < 2)
        {
                    printf (" Server number : " );
                    gets(buffer);
                    o_msg->server_number = atoi(buffer);

                    printf(" routing key : " );
                    gets (buffer);
                    o_msg->routing_key = buffer[0];
        }
        else
        {
                    sscanf( argv[1], "%1d", &(o_msg->server_number) );
                    o_msg->routing_key = *(argv[2]);
        }
    } /* End of get_server_parameters */

    void
    get_client_parameters ( rtr_sgn_32_t argc, char *argv[], message_data_t
    *o_msg, int *txn_cnt)
    {
            String31        buffer;

            if (argc < 3)
            {
                    printf (" Client number : " );
                    gets(buffer);
                    o_msg->client_number = atoi(buffer);

                    printf(" routing key : " );
                    gets (buffer);
                    o_msg->routing_key = buffer[0];

                    printf(" Message Count : " );
                    gets (buffer);
                    *txn_cnt = atoi(buffer);
            }
            else
            {
                    sscanf( argv[1], "%1d", &(o_msg->client_number) );
                    sscanf(argv[2], "%s", buffer );

            }
    } /* End of get_client_parameters */

    /***************************************************************************/

    void fprint_tid ( FILE *fp , rtr_tid_t  *tid )
    {
              fprintf ( fp , "     tid: %x,%x,%x,%x,%x,%x,%x\n", tid->tid32[0],
    tid->tid32[1],
                    tid->tid32[2], tid->tid32[3], tid->tid32[4], tid->tid32[5],
                    tid->tid32[6] );
    }

    void
    close_channel ( rtr_channel_t channel )
    {
        rtr_status_t status;

        printf ( " Closing Channel.\n" );

        status = rtr_close_channel (
                       channel ,
                       RTR_NO_FLAGS);

        check_status( "rtr_close_channel", status );

        return;

    }

# A.5 Header Code

    /* Header Code */

    /*******************************************************************************
    * 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 Application
    * MODULE NAME: adg_header.h
    * AUTHOR         : Compaq Computer Corporation
    * DESCRIPTION: This header file is to be used with adg_server.c,
    *                          adg_client.c, and adg_shared.c.
    * DATE           : Oct 22, 1998
    *******************************************************************************/
    /*
        Header file for adg_client.c and adg_server.c

    */

    #include "rtr.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <math.h>
    #include <signal.h>
    #include <ctype.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    /* #include <sys/types.h> */

    #define PERMS 0666 /* File permissions */
    #define FACILITY_NAME "DESIGN"

    typedef char String31[31];
    typedef char String200[200];

    typedef  struct {
        rtr_uns_8_t     routing_key;
        rtr_uns_32_t    server_number;
        rtr_uns_32_t    client_number;
        rtr_uns_32_t    sequence_number;
        String31        text;
        } message_data_t;

    typedef union {
        message_data_t receive_data_msg;
        rtr_status_data_t receive_status_msg;
        } receive_msg_t;

    typedef struct  {
        rtr_uns_32_t    low;
        rtr_uns_32_t    high;
        rtr_uns_32_t    expected ;
        rtr_tid_t       prior_txn;
        rtr_uns_32_t    prior_seqno;
        }boundaries_t;

    /* Function prototype section */

    void
    check_status( char *call, rtr_status_t status );

    void get_client_parameters ( rtr_sgn_32_t argc,
                            char *argv[],
                            message_data_t *o_msg,
                            int *txn_cnt);
    void get_server_parameters ( rtr_sgn_32_t argc,
                            char *argv[],
                            message_data_t *o_msg);

    rtr_status_t send_reply (
                            message_data_t *o_msg,
                            rtr_channel_t channel);

    void close_channel ( rtr_channel_t channel );

    void fprint_tid (FILE *fpLog, rtr_tid_t  *tid );

    /* External section */

    extern String200            Errormsg;

    extern time_t               time_val;
    extern boundaries_t         txn_range[10];
    extern char                 TxnLog[];
    extern char                 SvrLog[];
    extern rtr_uns_32_t         msg_cnt;
    extern int                  errno;
    extern FILE*                fpLog;

Previous | Next | Contents | Index