home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / sna / aping / aping.c next >
Text File  |  1997-04-09  |  32KB  |  823 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME: APING.C
  4.  *
  5.  *  COPYRIGHTS:
  6.  *             This module contains code made available by IBM
  7.  *             Corporation on an AS IS basis.  Any one receiving the
  8.  *             module is considered to be licensed under IBM copyrights
  9.  *             to use the IBM-provided source code in any way he or she
  10.  *             deems fit, including copying it, compiling it, modifying
  11.  *             it, and redistributing it, with or without
  12.  *             modifications.  No license under any IBM patents or
  13.  *             patent applications is to be implied from this copyright
  14.  *             license.
  15.  *
  16.  *             A user of the module should understand that IBM cannot
  17.  *             provide technical support for the module and will not be
  18.  *             responsible for any consequences of use of the program.
  19.  *
  20.  *             Any notices, including this one, are not to be removed
  21.  *             from the module without the prior written consent of
  22.  *             IBM.
  23.  *
  24.  *  AUTHOR:    Peter J. Schwaller
  25.  *             VNET:     PJS at RALVM6           Tie Line: 444-4376
  26.  *             Internet: pjs@ralvm6.vnet.ibm.com     (919) 254-4376
  27.  *
  28.  *  FUNCTION:  Perform an echo test to a specified destination.
  29.  *             APING can be used when you are first installing APPC on
  30.  *             your computer to make sure you can connect to another
  31.  *             computer in the network.  APING can also be used to
  32.  *             get an estimate of the delay time or throughput to another
  33.  *             computer in the network.
  34.  *
  35.  *  AVAILABILITY:
  36.  *             These sample programs and source are also available on
  37.  *             CompuServe through the APPC Information Exchange.  To get
  38.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  39.  *             prompt.  The samples are available in the Sample Programs
  40.  *             library section.  Just search on the keyword CPICPGMS to
  41.  *             find all the samples in this series.
  42.  *
  43.  *             Updates for the sample programs and support for many more
  44.  *             CPI-C platforms will also be made available on CompuServe.
  45.  *
  46.  *  RELATED FILES:
  47.  *             See APING.DOC for detailed information.
  48.  *
  49.  *  PORTABILIITY NOTES:
  50.  *             The APING client program is completely portable.  In fact,
  51.  *             all of the source modules can be compiled without #define-ing
  52.  *             any platform constant value.
  53.  *
  54.  *             To take advantage of a performance optimization on the
  55.  *             OS/2 platform, the alloc_cpic_buffer() is used.  If the
  56.  *             OS/2 platform is specified (#define of OS2, FAPI, or OS2_20)
  57.  *             alloc_cpic_buffer() will return a shared memory buffer.
  58.  *             If not, a buffer allocated with malloc() will be returned.
  59.  *
  60.  *             If you are porting to a platform that can take advantage
  61.  *             of a specially allocated memory buffer, you should
  62.  *             add this support to the alloc_cpic_buffer() routine in the
  63.  *             CPICPORT.C file.
  64.  *
  65.  *             The get_time() routine is used to determine the current time,
  66.  *             which is in turn used to calculate the elapsed time of the
  67.  *             data transfer.  The get_time() routine is used to hide
  68.  *             differences between operating system timer facilties that
  69.  *             are available.  Since the C library routine to query the
  70.  *             current time only returns the time in seconds, it is
  71.  *             advantageous to return the current time in milliseconds
  72.  *             if it is available.
  73.  *
  74.  *             If you are porting to a platform that support a timer
  75.  *             with a resolution better than one second, you should
  76.  *             modify the get_time() routine in the CPICPORT.C file.
  77.  *
  78.  *  CHANGE HISTORY:
  79.  *  Date       Description
  80.  *  06/15/92   NS/DOS accepts version 2.02 into system test.
  81.  *  08/05/92   Version 2.31 released to CompuServe
  82.  *             This version was also distributed at the APPC/APPN Platform
  83.  *             Developer's Conference held in Raleigh, NC.
  84.  *  08/13/92   Changed all printf and fprintf calls to use a write_*() call.
  85.  *  08/17/92   Made security handling code conditionally compiled.
  86.  *  08/23/92   Removed call to cpicinit_default_destination().
  87.  *  08/24/92   Version 2.32 released to CompuServe.
  88.  *  08/28/92   Changed message about invalid size parm to go to write_error().
  89.  *  09/08/92   Added check for buffer==NULL.  Initialized block to zeros.
  90.  *  09/22/92   Version 2.33 released to CompuServe.
  91.  *  11/17/92   Added support for printing remote operating system name.
  92.  *             Version 2.34 released to CompuServe
  93.  *  01/07/93   Version 2.35
  94.  *             Fixed a number of problems when compiling with IBM C Set/2
  95.  *                password input was displayed
  96.  *                timer resolution was 1 second
  97.  *
  98.  *****************************************************************************/
  99.  
  100. /*****************************************************************************
  101.  * OVERVIEW of APING CPI-C Flows
  102.  *
  103.  *   Client (APING)                      Server (APINGD)
  104.  *   --------------                      ---------------
  105.  * Set up conversation
  106.  *   Allocate       -------------------> Accept Conversation
  107.  * Exchange Version Numbers
  108.  *   Send Data      -------------------> Receive
  109.  *   Receive        <------------------- Send Data
  110.  * For number of iterations (i)
  111.  *  For number of consecutive packets (c)
  112.  *     Send Data    -------------------> Receive
  113.  *  For number of consecutive packets (c)
  114.  *     Receive      <------------------- Send Data
  115.  * Shut down the conversation
  116.  *   Deallocate (FLUSH)
  117.  *****************************************************************************/
  118.  
  119. #if defined(WIN32) || defined(WINDOWS)                                 /*WIN32*/
  120. #include <windows.h>                                                   /*WIN32*/
  121. #endif                                                                 /*WIN32*/
  122.  
  123. #include "wincpic.h"
  124.  
  125. /* Set up constant declarations */
  126. #include "cpicdefs.h"
  127.  
  128. /* Collection of routines with special ported version for each platform */
  129. #include "cpicport.h"
  130.  
  131. /* standard C include files */
  132. #include <stdio.h>
  133. #include <stdlib.h>
  134. #include <string.h>
  135.  
  136.  
  137. /* CPI-C error handling routines */
  138. /* This file is supplied with APING */
  139. #include "cpicerrs.h"
  140.  
  141. /* CPI-C conversation startup routines */
  142. /* This file is supplied with APING */
  143. #include "cpicinit.h"
  144.  
  145. /* Argument processing procedure */
  146. /* This file is supplied with APING */
  147. #include "getopt.h"
  148.  
  149.  
  150.  
  151. /* CPI-C error handling info */
  152. CPICERR * cpicerr;
  153.  
  154.  
  155. /*
  156.  * Max size of a data buffer.  This is the largest size buffer that can
  157.  * be specified on a call to CPI-C.
  158.  */
  159. #define  MAX_SIZE (32763)
  160.  
  161. /* These are the defaults to be used if the user does not provide arguments  */
  162. /* to override these values.                                                 */
  163. #define  DEFAULT_TP_NAME   "APINGD"
  164. #define  DEFAULT_MODE_NAME "#INTER"
  165. #define  DEFAULT_SYM_DEST  "APINGD"
  166.  
  167. /* Define these here so we can make changes throughout the code. */
  168. /*
  169.  * The PROGRAM_INFO string should be kept in sync with the
  170.  * MAJOR_VERSION and MINOR_VERSION constants.  Although the
  171.  * cpicerr_exchange_version() call will support values up to 255,
  172.  * values for MINOR_VERSION should be from 00-99 to maintain the
  173.  * two character format in the version string.
  174.  */
  175. #define  PROGRAM_NAME      "APING"
  176. #define  PROGRAM_INFO      "version 2.35"
  177. #define  MAJOR_VERSION     (2)
  178. #define  MINOR_VERSION     (35)
  179. #define  LOG_FILE_NAME     "aping.err"
  180. #define  LOG_FILE_PATH     "$LOGPATH"
  181.  
  182. /*
  183.  * Define the first APING version to support one way data transfer.
  184.  * (Version 2.02).  After we exchange version numbers, we can determine
  185.  * whether or not our partner can handle one way data or not.
  186.  */
  187. #define  ONEWAY_MAJOR_VERSION    (2)
  188. #define  ONEWAY_MINOR_VERSION    (2)
  189.  
  190.  
  191.  
  192. typedef struct flags {
  193.     int    one_way_flag;                    /* Was one way data requested    */
  194.                                             /* value of 2 means two way echo */
  195.                                             /* value of 1 means one way      */
  196.     unsigned long size;                     /* size of data sends            */
  197.     unsigned long number_iterations;        /* times through the loop        */
  198.     unsigned long number_concurrent;        /* sends by each side per loop   */
  199. } FLAGS;
  200.  
  201. /* function prototypes for procedures in this file */
  202. void     do_aping(int argc,
  203.                   char *argv[]);
  204. void     process_arguments(int argc,
  205.                            char *argv[],
  206.                            CPICINIT * cpicinit,
  207.                            FLAGS * flags);
  208.  
  209.  
  210.  
  211. /*
  212.  * Message displayed with show_info() when APING is started.
  213.  */
  214. char * intro[] = {
  215.     PROGRAM_NAME " " PROGRAM_INFO " APPC echo test with timings.",
  216.     "  by Peter J. Schwaller (pjs@ralvm6.vnet.ibm.com)",
  217.     NULL
  218.     };
  219.  
  220. /*
  221.  * Message displayed with show_info() when usage information is requested or
  222.  * after an invalid flag was specified.
  223.  */
  224. char * usage[] = {
  225.     "",
  226.     "APING [flags] destination",
  227.     "  destination",
  228.     "\tmay be either a symbolic destination name or a partner LU name",
  229.     "  -m mode_name",
  230.     "\tmode name (default: " DEFAULT_MODE_NAME ")",
  231.     "  -t tp_name",
  232.     "\tthe TP to start on the server (default: " DEFAULT_TP_NAME ")",
  233.     "  -s N",
  234.     "\tN is the size of the packet transmitted (default: 100 bytes)",
  235.     "  -i N",
  236.     "\tN is the number of iterations (default: 2)",
  237.     "  -c N",
  238.     "\tN is the number of consecutive packets sent by each side (default: 1)",
  239.     "  -1",
  240.     "\tOnly send data from client to server (No echo)",
  241. #if defined(SUPPORTS_SETTING_SECURITY)
  242.     "  -u userid",
  243.     "  -p password",
  244.     "\tSecurity parameters.  If a userid is specified without a password,",
  245.     "\tyou will be prompted for the password.",
  246.     "  -n",
  247.     "\tDo not use any security (SECURITY=NONE).",
  248. #endif
  249.     "",
  250.     "The minimum time, maximum time, and average time will be shown.",
  251.     NULL
  252.     };
  253.  
  254. void _cdecl
  255. main(int argc, char *argv[])
  256. {
  257.  
  258.     do_aping(argc, argv);
  259.  
  260. }
  261.  
  262.  
  263. void
  264. do_aping( int argc, char *argv[])
  265. {
  266.     /* Variables used for CPI-C calls */
  267.     unsigned char cm_conv_id[8];            /* CPI-C conversation ID         */
  268.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  269.     CM_INT32    length;                     /* generic length variable       */
  270.     CM_INT32    rts_received;               /* request to send received      */
  271.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  272.     CM_INT32    data_received;              /* Data received parm from CMRCV */
  273.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  274.     CM_INT32    status_received;            /* Status from CMRCV             */
  275.  
  276.     /* Data buffer for send and receive */
  277.     unsigned char CM_PTR buffer;            /* CPIC data buffer              */
  278.  
  279. #ifdef WIN32                                                          /*WIN32*/
  280.     unsigned short WinCPICVERSION = 0x0001;                           /*WIN32*/
  281.     WCPICDATA CPICData;                                               /*WIN32*/
  282. #endif                                                                /*WIN32*/
  283.  
  284.     /* Destination information */
  285.     CPICINIT * cpicinit;
  286.  
  287.     unsigned long start_time = 0;           /* when a ping starts            */
  288.     unsigned long end_time;                 /* when a ping ends              */
  289.     unsigned long elapsed_time;             /* used for time calculations    */
  290.  
  291.     char          partner_major_version;
  292.     char          partner_minor_version;
  293.     char          opsys_string[64];
  294.  
  295.  
  296.     unsigned long curr_iteration;           /* which iteration is active     */
  297.     unsigned long curr_concurrent;          /* which send/recv is active     */
  298.     unsigned long total_time = 0;           /* used to calculate averages    */
  299.  
  300.     unsigned long min_time = 0xFFFFFFFF;    /* used for min elapsed time     */
  301.     unsigned long max_time = 0;             /* used for max elapsed time     */
  302.                                             /* min and max are initialized   */
  303.                                             /* to the extreme opposite values*/
  304.                                             /* to avoid doing special        */
  305.                                             /* processing the first time thru*/
  306.  
  307.     double data_rate;                       /* Variable used to calculate    */
  308.                                             /* the data rate                 */
  309.  
  310.     FLAGS  flags;                           /* Command line flags            */
  311.  
  312.     flags.one_way_flag = 2;
  313.     flags.size = 100;
  314.     flags.number_iterations = 2;
  315.     flags.number_concurrent = 1;
  316.  
  317.     /*
  318.      * Make sure all output is seen as soon as possible.
  319.      */
  320.     setbuf(stdout, NULL);
  321.  
  322.     show_info(intro);                       /* Show program information      */
  323.  
  324. #if (defined(WIN32) || defined(WINDOWS))                              /*WIN32*/
  325.        /****************************************************************WIN32*/
  326.        /* Initialisation for WinCPIC                                   *WIN32*/
  327.        /****************************************************************WIN32*/
  328.     if (WinCPICStartup(WinCPICVERSION,&CPICData))                     /*WIN32*/
  329.     {                                                                 /*WIN32*/
  330.        return ;                                                    /*WIN32*/
  331.     }                                                                 /*WIN32*/
  332. #endif                                                                /*WIN32*/
  333.  
  334.     /*
  335.      * Create a new CPICINIT structure and initialize values.
  336.      * The procedures are in CPICINIT.C
  337.      */
  338.  
  339.     cpicinit = cpicinit_new();
  340.     cpicinit_default_tp_name(cpicinit, DEFAULT_TP_NAME);
  341.     cpicinit_default_mode_name(cpicinit, DEFAULT_MODE_NAME);
  342.     cpicinit_default_sym_dest_name(cpicinit, DEFAULT_SYM_DEST);
  343.  
  344.     /*
  345.      * Process all of the command line arguments.  All of the conversation
  346.      * setup arguments are stored in the cpicinit object.  The block size
  347.      * and other loop parameters are set in the global variables.
  348.      */
  349.     process_arguments(argc, argv, cpicinit, &flags);
  350.  
  351.  
  352.     if (cpicinit->set_destination == NOT_SET) {
  353.         write_error( "\n\aYou must specify a destination.\n");
  354.         show_info(usage);
  355.         do_exit(EXIT_FAILURE);
  356.     }
  357.  
  358.     if (cpicinit_query_password_needed(cpicinit)) {
  359.         /* get a password from the user */
  360.         cpicinit_get_password(cpicinit);
  361.     }
  362.  
  363.     buffer = (unsigned char CM_PTR)alloc_cpic_buffer((unsigned int)flags.size);
  364.                                             /* allocate an APPC buffer       */
  365.  
  366.     if (buffer == NULL) {
  367.         write_error("Error allocating memory buffer.\nExiting...\n");
  368.         do_exit(EXIT_FAILURE);
  369.     }
  370.  
  371.     memset(buffer, 0, (unsigned int)flags.size);  /* Set block to zeros      */
  372.  
  373.  
  374.     /*
  375.      * Initialize the CPICERR structure.  This is done before the CMINIT
  376.      * call so that we can use CPICERR for help with errors on CMINIT.
  377.      * The procedure is in CPICERR.C
  378.      */
  379.     cpicerr = cpicerr_new();
  380.     cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
  381.     cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
  382.     cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
  383.     cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
  384.     cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
  385.     cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
  386.  
  387.     /*
  388.      * Setup a CPI-C conversation.  This routine issues all of the
  389.      * CPI-C calls from CMINIT() through just before you would
  390.      * issue the CMALLC() call.  The conversation id is returned
  391.      * for use by the program.
  392.      */
  393.     cpicinit_setup_conversation(cpicinit, cm_conv_id, cpicerr);
  394.  
  395.     /*
  396.      * Fill in conversation information for CPI-C error reporting.
  397.      */
  398.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  399.  
  400.     {
  401.     CM_SYNC_LEVEL sync_level = CM_CONFIRM;
  402.     cmssl(cm_conv_id,                       /* Set sync level                */
  403.           &sync_level,
  404.           &cm_rc);
  405.     /* The only expected return code is CM_OK */
  406.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSSL, cm_rc);
  407.     }
  408.  
  409.     {
  410.     CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
  411.     cmsptr(cm_conv_id,                      /* Set prepare to receive type   */
  412.            &prep_to_receive,
  413.            &cm_rc);
  414.     /* The only expected return code is CM_OK */
  415.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
  416.     }
  417.  
  418.  
  419.     /*
  420.      * Fill in conversation information for CPI-C error reporting.
  421.      */
  422.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  423.  
  424.     start_time = get_time();            /* let's time the allocate       */
  425.  
  426.     cmallc(cm_conv_id,
  427.            &cm_rc);
  428.  
  429.     end_time = get_time();                  /* stop the timer                */
  430.  
  431.     /* The only expected return code is CM_OK */
  432.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMALLC, cm_rc);
  433.  
  434.  
  435.                                             /* show the allocate time        */
  436.     write_output("\nAllocate duration:                     %8lu ms\n",
  437.                                                        end_time - start_time);
  438.  
  439.     start_time = get_time();
  440.  
  441.     cpicerr_exchange_version_plus(cpicerr,
  442.                                   cm_conv_id,
  443.                                   CM_SEND_STATE,
  444.                                   &partner_major_version,
  445.                                   &partner_minor_version,
  446.                                   opsys_string,
  447.                                   sizeof(opsys_string));
  448.  
  449.     end_time = get_time();                  /* stop the timer                */
  450.  
  451.  
  452.     /*
  453.      * Display the operating system string returned in the exchange.
  454.      * The string length will be 0 if the operating system string
  455.      * wasn't available.
  456.      */
  457.  
  458.     if (strlen(opsys_string) != 0) {
  459.         write_output("\nConnected to a partner running on: %s\n",
  460.                      opsys_string);
  461.     }
  462.  
  463.  
  464.     /*
  465.      * If the one_way_flag has been set, we have to make sure that our
  466.      * partner is at the correct version to accept one way data.  If
  467.      * the partner is not at the right level, we'll turn off the one
  468.      * way flag and the partner will echo data (normal operating mode).
  469.      *
  470.      * Trying to use one way data with a partner that can't handle the
  471.      * CONFIRM status indicator would result in an error on the partner
  472.      * side.  On this side, we would see DEALLOCATE_ABEND.
  473.      */
  474.     if ((flags.one_way_flag == 1)  &&
  475.         !(partner_major_version > ONEWAY_MAJOR_VERSION ||
  476.         (partner_major_version == ONEWAY_MAJOR_VERSION &&
  477.          partner_minor_version >= ONEWAY_MINOR_VERSION))) {
  478.         write_output("\nOne way data transfer is not supported by partner.\n");
  479.         write_output("Partner will echo data.\n");
  480.         flags.one_way_flag = 2;
  481.     }
  482.  
  483.  
  484.                                             /* show the startup time         */
  485.     write_output("\nProgram startup and Confirm duration:  %8lu ms\n\n",
  486.                                                        end_time - start_time);
  487.  
  488.  
  489.     write_output(
  490.     "        Duration        Data Sent        Data Rate        Data Rate\n");
  491.     write_output(
  492.     "        (msec)          (bytes)          (KB/s)           (Mb/s)   \n");
  493.     write_output(
  494.     "        --------        ---------        ---------        ---------\n");
  495.  
  496.     /*
  497.      * Set the amount of data we will send on each CMSEND() call.
  498.      */
  499.     length = flags.size;
  500.  
  501.     /*
  502.      * Start current at zero so if a BREAK occurs, it will contain the number
  503.      * of iterations completed.  We take a slight risk in assuming that
  504.      * the curr_iteration++ operation is atomic.
  505.      *
  506.      * This loop encompasses both a send loop and a receive loop.  Both
  507.      * the send a receive loop are executed the number of times specified
  508.      * by the number_iterations variable (set by the -i argument).
  509.      */
  510.     for (curr_iteration = 0;
  511.          curr_iteration<flags.number_iterations;
  512.          curr_iteration++ ) {
  513.         {
  514.         CM_SEND_TYPE send_type = CM_BUFFER_DATA;
  515.         cmsst(cm_conv_id,
  516.               &send_type,
  517.               &cm_rc);
  518.         if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  519.         }
  520.  
  521.         start_time = get_time();
  522.  
  523.  
  524.         for (curr_concurrent = 1;           /* Start current at one so we    */
  525.              curr_concurrent<flags.number_concurrent ;/* do one LESS send in */
  526.              curr_concurrent++ ) {          /* loop than the specifed number */
  527.  
  528.             cmsend(cm_conv_id,
  529.                    buffer,
  530.                    &length,
  531.                    &rts_received,
  532.                    &cm_rc);
  533.  
  534.  
  535.             /* The only expected return code is CM_OK */
  536.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  537.  
  538.         }
  539.  
  540.         /*
  541.          * For the final send in the number of concurrent sends, set the send
  542.          * type to do a send and a prepare to receive.  This will send both
  543.          * the data and the send permission indicator to our partner all at
  544.          * once.
  545.          *
  546.          * If the one_way_flag has been set, we will issue a Confirm along
  547.          * with the Send_Data.  This will allow us to know when the partner
  548.          * has actually received all the data so we can get an accurate
  549.          * timing.
  550.          *
  551.          * On the partner side, if Send status is received, the partner will
  552.          * know to echo the data.  If Confirm status is received, the partner
  553.          * will know to issued Confirmed and then get ready to receive
  554.          * more data, since the partner won't be echoing.
  555.          */
  556.         {
  557.         CM_SEND_TYPE send_type;
  558.         if (flags.one_way_flag != 1) {
  559.             send_type = CM_SEND_AND_PREP_TO_RECEIVE;
  560.         } else {
  561.             send_type = CM_SEND_AND_CONFIRM;
  562.         }
  563.         cmsst(cm_conv_id,
  564.               &send_type,
  565.               &cm_rc);
  566.         if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  567.         }
  568.  
  569.         cmsend(cm_conv_id,
  570.                buffer,
  571.                &length,
  572.                &rts_received,
  573.                &cm_rc);
  574.         /* The only expected return code is CM_OK */
  575.         if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  576.  
  577.         if (flags.one_way_flag != 1) {
  578.             max_receive_len = flags.size;
  579.             do {
  580.  
  581.                 cmrcv (cm_conv_id,          /* Receive Data                  */
  582.                        buffer,              /* Data Pointer                  */
  583.                        &max_receive_len,    /* Size of Data Buffer           */
  584.                        &data_received,      /* returned - data received      */
  585.                        &received_len,       /* returned - length of data     */
  586.                        &status_received,    /* returned - status received    */
  587.                        &rts_received,       /* returned - request to send    */
  588.                        &cm_rc);
  589.                 /* The only expected return code is CM_OK */
  590.                 if (cm_rc != CM_OK) {
  591.                     cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  592.                 }
  593.  
  594.                 if (data_received != CM_NO_DATA_RECEIVED) {
  595.                     curr_concurrent--;
  596.                 }
  597.  
  598.             } while ((status_received !=  CM_SEND_RECEIVED));
  599.             /* Repeat the receive loop until SEND permission has been rcvd. */
  600.  
  601.             if (curr_concurrent != 0) {
  602.                 write_error(
  603.                 "ERROR.\n");
  604.                 write_error(
  605.                     "Partner did not send the expected number of records.\n");
  606.             }
  607.         } else {
  608.         }
  609.  
  610.         end_time = get_time();              /* stop timer                    */
  611.  
  612.         elapsed_time = end_time - start_time; /* calculate elapsed time      */
  613.  
  614.         write_output("%16ld", elapsed_time);
  615.         write_output("%17lu", flags.size * flags.number_concurrent *
  616.                               flags.one_way_flag);
  617.  
  618.         if (elapsed_time) {
  619.             data_rate =                     /* in KBytes / 0.1 Sec           */
  620.                               (double)
  621.               ( ( (((double)flags.size * (double)flags.number_concurrent) /
  622.                        (double)1024) *
  623.                    (double)1 * (double)1000 * (double)flags.one_way_flag)
  624.                            /    /* divided by */
  625.                  ( (double)elapsed_time  / (double)10)  );
  626.  
  627.             data_rate = data_rate / (double)10;
  628.  
  629.             write_output("%17.1f", data_rate);
  630.             write_output("%17.3f\n", (data_rate * (double)8) / (double)1000);
  631.             {
  632.             /* this code was for integer arithmetic */
  633.             unsigned long data_rate;
  634.             unsigned long modifier = 100000L;
  635.             unsigned long bytes = flags.size * flags.number_concurrent
  636.                                   * flags.one_way_flag;
  637.  
  638.             while ( bytes > (0xFFFFFFFF / modifier) && (modifier > 10)) {
  639.                 modifier = modifier / 10;
  640.             } /* endwhile */
  641.  
  642.             data_rate = (unsigned long)
  643.                            ((bytes * modifier))
  644.                                     /
  645.                (((unsigned long)elapsed_time * 1024L) / (100000L / modifier) );
  646.             }
  647.  
  648.  
  649.         } else {
  650.             write_output("\n");             /* Make sure we move to next line*/
  651.         }
  652.  
  653.         total_time += elapsed_time;         /* accumulate the elapsed time   */
  654.  
  655.         if (elapsed_time > max_time) {
  656.             max_time = elapsed_time;        /* set the max time              */
  657.         }
  658.         if (elapsed_time < min_time) {
  659.             min_time = elapsed_time;        /* set the min time              */
  660.         }
  661.  
  662.     }
  663.  
  664.     {
  665.     CM_DEALLOCATE_TYPE deallocate_type = CM_DEALLOCATE_FLUSH;
  666.     cmsdt(cm_conv_id,
  667.           &deallocate_type,
  668.           &cm_rc);
  669.     /* The only expected return code is CM_OK */
  670.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSDT, cm_rc);
  671.     }
  672.  
  673.     cmdeal(cm_conv_id,
  674.            &cm_rc);
  675.     /* The only expected return code is CM_OK */
  676.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMDEAL, cm_rc);
  677.  
  678.     /* destroy the object we created with cpicinit_new() */
  679.     cpicinit_destroy(cpicinit);
  680.  
  681.     /* destroy the object we created with cpicerr_new() */
  682.     cpicerr_destroy(cpicerr);
  683.  
  684.     /*
  685.      * Print out the grand totals and max/min times.
  686.      */
  687.     {
  688.  
  689.         double data_rate;
  690.  
  691.  
  692.         if (total_time > 10) {
  693.  
  694.             data_rate =                 /* in KBytes / 0.1 Sec           */
  695.                               (double)
  696.               ( ( (((double)flags.size * (double)flags.number_concurrent) /
  697.                          (double)1024) *
  698.                 (double)curr_iteration * (double)1000 *
  699.                 (double)flags.one_way_flag)
  700.                            /    /* divided by */
  701.                  ( (double)total_time  / (double)10)  );
  702.  
  703.             data_rate = data_rate / 10;
  704.  
  705.             write_output("Totals:%9lu", total_time);
  706.             write_output("%17lu", flags.size *
  707.                                   flags.number_concurrent *
  708.                                   curr_iteration *
  709.                                   flags.one_way_flag);
  710.             write_output("%17.1f", data_rate);
  711.             write_output("%17.3f\n", (data_rate * (double)8) /
  712.                                                (double)1000);
  713.         } else {
  714.             write_output("Totals:%9lu", total_time);
  715.             write_output("%17lu\n", flags.size *
  716.                                     flags.number_concurrent *
  717.                                     curr_iteration *
  718.                                     flags.one_way_flag);
  719.         }
  720.         if (curr_iteration > 0) {
  721.             write_output(
  722.             "\nDuration statistics:   Min = %lu   Ave = %lu   Max = %lu\n",
  723.                                              min_time,
  724.                                              total_time / curr_iteration,
  725.                                              max_time);
  726.         }
  727.  
  728.     }
  729.     do_exit(EXIT_SUCCESS);
  730.  
  731. }
  732.  
  733. void
  734. process_arguments(int argc,
  735.                   char *argv[],
  736.                   CPICINIT * cpicinit,
  737.                   FLAGS * flags )
  738. {
  739.     int         c;                          /* flag specifed, used w/getopt  */
  740.  
  741.     /*
  742.      * GETOPT is an easy way to parse command line arguments
  743.      * Each parameter which can have a flag is passed in the third argument
  744.      * to getopt.  Getopt returns the character of the flag on the command
  745.      * line and sets optarg to point to the value associated with the flag.
  746.      * optind is the index of the argument that getopt is currently processing.
  747.      */
  748.     while (optind != argc) {
  749.         c = getopt(argc, argv, "?1c:t:m:i:s:u:p:C:T:M:I:S:U:P:nNqQ");
  750.         switch (c) {
  751.         case EOF:
  752.             optarg = argv[optind];
  753.             if (optarg[0] == '?') {
  754.                show_info(usage);
  755.                do_exit(EXIT_FAILURE);
  756.             }
  757.             optind++;
  758.             if (cpicinit->set_destination == NOT_SET) {
  759.                 cpicinit_set_destination(cpicinit, optarg);
  760.             } else {
  761.                 write_error("Only one destination may be specified.\n");
  762.             }
  763.             break;
  764.         case 'M':
  765.         case 'm':
  766.             cpicinit_set_mode_name(cpicinit, optarg);
  767.             break;
  768.         case 'T':
  769.         case 't':
  770.             cpicinit_set_tp_name(cpicinit,optarg);
  771.             break;
  772. #if defined(SUPPORTS_SETTING_SECURITY)
  773.         case 'U':
  774.         case 'u':
  775.             cpicinit_set_userid(cpicinit, optarg);
  776.             break;
  777.         case 'P':
  778.         case 'p':
  779.             cpicinit_set_password(cpicinit, optarg);
  780.             break;
  781.         case 'N':
  782.         case 'n':
  783.             cpicinit_set_security_type(cpicinit, CM_SECURITY_NONE);
  784.             break;
  785. #endif
  786.         case 'S':
  787.         case 's':
  788.             flags -> size = atol(optarg);
  789.  
  790.             if (flags->size > MAX_SIZE) {   /* check bounds                  */
  791.                 write_error("Size (-s) of %lu too large.\n", flags->size);
  792.                 write_error("Setting size to %lu\n", (unsigned long)MAX_SIZE);
  793.                 flags->size = MAX_SIZE;     /* reset to MAX                  */
  794.             }
  795.             break;
  796.         case 'Q':
  797.         case 'q':
  798.             /* quiet processing is done in main() */
  799.             break;
  800.         case 'I':
  801.         case 'i':
  802.             flags->number_iterations = atol(optarg);
  803.             break;
  804.         case 'C':
  805.         case 'c':
  806.             flags->number_concurrent = atol(optarg);
  807.             break;
  808.         case '1':
  809.             flags->one_way_flag = 1;
  810.             break;
  811.         case '?':
  812.             show_info(usage);
  813.             do_exit(EXIT_FAILURE);
  814.             break;
  815.         default:
  816.             write_output("Invalid flag.  Use %s -? for usage\n", PROGRAM_NAME);
  817.             do_exit(EXIT_FAILURE);
  818.         }
  819.     }
  820. }
  821.  
  822. 
  823.