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 / apingd.c < prev    next >
Text File  |  1997-04-09  |  22KB  |  530 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME: APINGD.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 LU.
  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.  *             APINGD echos whatever is sent by APING.
  36.  *                Keep receiving until you get permission to send
  37.  *                Send the same number of same size records
  38.  *
  39.  *  AVAILABILITY:
  40.  *             These sample programs and source are also available on
  41.  *             CompuServe through the APPC Information Exchange.  To get
  42.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  43.  *             prompt.  The samples are available in the Sample Programs
  44.  *             library section.  Just search on the keyword CPICPGMS to
  45.  *             find all the samples in this series.
  46.  *
  47.  *             Updates for the sample programs and support for many more
  48.  *             CPI-C platforms will also be made available on CompuServe.
  49.  *
  50.  *  RELATED FILES:
  51.  *             See APING.DOC for usage instructions.
  52.  *
  53.  *  PORTABILIITY NOTES:
  54.  *             The APINGD server program is completely portable.  In fact,
  55.  *             all of the source modules can be compiled without #define-ing
  56.  *             any platform constant value.
  57.  *
  58.  *             To take advantage of a performance optimization on the
  59.  *             OS/2 platform, the alloc_cpic_buffer() is used.  If the
  60.  *             OS/2 platform is specified (#define of OS2, FAPI, or OS2_20)
  61.  *             alloc_cpic_buffer() will return a shared memory buffer.
  62.  *             If not, a buffer allocated with malloc() will be returned.
  63.  *
  64.  *             If you are porting to a platform that can take advantage
  65.  *             of a specially allocated memory buffer, you should
  66.  *             add this support to the alloc_cpic_buffer() call in the
  67.  *             CPICPORT.C file.
  68.  *
  69.  *  CHANGE HISTORY:
  70.  *  Date       Description
  71.  *  06/15/92   NS/DOS accepts version 2.02 into system test.
  72.  *  08/05/92   Version 2.31 released to CompuServe
  73.  *             This version was also distributed at the APPC/APPN Platform
  74.  *             Developer's Conference held in Raleigh, NC.
  75.  *  08/13/92   Changed all printf and fprintf calls to use a write_*() call.
  76.  *  08/24/92   Version 2.32 released to CompuServe.
  77.  *  09/22/92   Version 2.33 released to CompuServe.
  78.  *  11/17/92   Supports sending operating system string - see CPICERR.C
  79.  *             Version 2.34 released to CompuServe
  80.  *  01/07/93   Version 2.35
  81.  *             Fixed a number of problems when compiling with IBM C Set/2
  82.  *                password input was displayed
  83.  *                timer resolution was 1 second
  84.  *
  85.  *****************************************************************************/
  86.  
  87. #ifdef WIN32                                                           /*WIN32*/
  88. #include <windows.h>                                                   /*WIN32*/
  89. SERVICE_STATUS_HANDLE stat_hand;                                       /*WIN32*/
  90. SERVICE_STATUS servstat;                                               /*WIN32*/
  91. #endif                                                                 /*WIN32*/
  92.  
  93. #include "wincpic.h"
  94.  
  95. /* standard C include files */
  96. #include <stdio.h>
  97. #include <stdlib.h>
  98. #include <string.h>
  99.  
  100. /* Set up constant declarations */
  101. #include "cpicdefs.h"
  102.  
  103. /* Collection of routines with special ported version for each platform */
  104. #include "cpicport.h"
  105.  
  106. /* CPI-C error handling routines */
  107. /* This file is supplied with APINGD */
  108. #include "cpicerrs.h"
  109.  
  110. /* CPI-C initialization routines */
  111. /* This file is supplied with APINGD */
  112. #include "cpicinit.h"
  113.  
  114. /* Argument processing procedure */
  115. /* This file is supplied with APINGD */
  116. #include "getopt.h"
  117.  
  118. /* CPI-C error handling info */
  119. CPICERR * cpicerr;
  120.  
  121. /*
  122.  * Max size of a data buffer.  This is the largest size buffer that can
  123.  * be specified on a call to CPI-C.
  124.  */
  125. #define  MAX_SIZE (0x7FFF)
  126.  
  127. /* Define these here so we can make changes throughout the code. */
  128. /*
  129.  * The PROGRAM_INFO string should be kept in sync with the
  130.  * MAJOR_VERSION and MINOR_VERSION constants.  Although the
  131.  * cpicerr_exchange_version() call will support values up to 255,
  132.  * values for MINOR_VERSION should be from 00-99 to maintain the
  133.  * two character format in the version string.
  134.  */
  135. #define  PROGRAM_NAME      "APINGD"
  136. #define  PROGRAM_INFO      "version 2.35"
  137. #define  MAJOR_VERSION     (2)
  138. #define  MINOR_VERSION     (35)
  139. #define  LOG_FILE_NAME     "apingd.err"
  140. #define  LOG_FILE_PATH     "$LOGPATH"
  141.  
  142. /*
  143.  * Message displayed with show_info() when APINGD is started.
  144.  */
  145. char * intro[] = {
  146.     PROGRAM_NAME " " PROGRAM_INFO " - APPC loopback server",
  147.     NULL
  148.     };
  149.  
  150. char * log_file_name = NULL;
  151.  
  152. void TPStart( DWORD argc, LPSTR *argv)                                /*WIN32*/
  153. {
  154.     /* Variables used for CPI-C calls */
  155.     unsigned char cm_conv_id[8];            /* CPI-C conversation ID         */
  156.     CM_INT32    temp;                                                 /*WIN32*/
  157.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  158.     CM_INT32    length;                     /* generic length variable       */
  159.     CM_INT32    rts_received;               /* request to send received      */
  160.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  161.     CM_INT32    data_received;              /* Data received parm from CMRCV */
  162.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  163.     CM_INT32    status_received;            /* Status from CMRCV             */
  164.  
  165.     /* Data buffer for send and receive */
  166.     unsigned char CM_PTR buffer;            /* CPIC data buffer              */
  167.  
  168.     char        destination[MAX_DESTINATION];/* Partner destination          */
  169.     unsigned int max_size;                  /* size to receive               */
  170.     int         c;                          /* flag specifed, used w/getopt  */
  171.  
  172.     char partner_major_version;
  173.     char partner_minor_version;
  174.  
  175.  
  176.     show_info(intro);                       /* display intro information     */
  177.  
  178. #ifdef WIN32
  179.     {
  180.        /**********************************************************************/
  181.        /* Initialisation for WinCPIC                                         */
  182.        /**********************************************************************/
  183.        unsigned short WinCPICVERSION = 0x0001;
  184.        WCPICDATA CPICData;
  185.        if (WinCPICStartup(WinCPICVERSION,&CPICData))
  186.        {
  187.          return;
  188.        }
  189.        /**********************************************************************/
  190.        /* Set our local TP Name                                              */
  191.        /**********************************************************************/
  192.        temp=6;
  193.        cmsltp("APINGD",&temp,&cm_rc);
  194.     }
  195. #endif
  196.  
  197.     while ((DWORD)optind != argc) {
  198.         c = getopt(argc, argv, "?l:");
  199.         switch (c) {
  200.         case EOF:
  201.             optind++;
  202.             break;
  203.         case 'l':
  204.         case 'L':
  205.             write_output("\nIncoming partner LU names will be logged to: %s\n",
  206.                                                                 optarg);
  207.             log_file_name = optarg;
  208.             break;
  209.         } /* endswitch */
  210.     } /* endwhile */
  211.  
  212.     /*
  213.      * Initialize the CPICERR structure.  This is done before the CMACCP
  214.      * call so that we can use CPICERR for help with errors on CMACCP.
  215.      * The procedure is in CPICERR.C
  216.      */
  217.     cpicerr = cpicerr_new();
  218.     cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
  219.     cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
  220.     cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
  221.     cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
  222.     cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
  223.     cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
  224.  
  225.     cmaccp(cm_conv_id,                      /* Accept Conversation           */
  226.            &cm_rc);
  227.     /*
  228.      * Note that as we have used cmsltp to specify our local TP name,
  229.      * cmaccp may return asynchronously, so we must do a cmwait
  230.      */
  231.     if (cm_rc == CM_OPERATION_INCOMPLETE)                             /*WIN32*/
  232.     {                                                                 /*WIN32*/
  233.       cmwait(cm_conv_id, &cm_rc, &temp);                              /*WIN32*/
  234.     }                                                                 /*WIN32*/
  235.  
  236.     /*
  237.      * Fill in conversation information for CPI-C error reporting.
  238.      */
  239.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  240.  
  241.  
  242.     if (cm_rc != CM_OK) {
  243.         cpicerr_handle_rc(cpicerr, MSG_CMACCP, cm_rc);
  244.     } else {
  245.         CM_INT32 pln_length;
  246.         /*
  247.          * Extract the partner LU name and display it.
  248.          */
  249.         cmepln(cm_conv_id,
  250.                (unsigned char *)destination,
  251.                &pln_length,
  252.                &cm_rc );
  253.  
  254.         destination[(int)pln_length] = '\0';
  255.         write_output("\nContacted by partner: %s\n", destination);
  256.  
  257.         if (log_file_name != NULL) {
  258.             FILE * file;
  259.             file = fopen(log_file_name, "a");
  260.             if (file != NULL) {
  261.                 write_log(file, "\nContacted by partner: %s\n", destination);
  262.                 fclose(file);
  263.             }
  264.         }
  265.  
  266.     }
  267.  
  268.  
  269.     {
  270.     CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
  271.     cmsptr(cm_conv_id,                       /* Set prepare to receive type  */
  272.            &prep_to_receive,
  273.            &cm_rc);
  274.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
  275.     }
  276.  
  277.  
  278.     max_receive_len = max_size = MAX_SIZE;
  279.  
  280.     buffer = (unsigned char CM_PTR)alloc_cpic_buffer(max_size);
  281.                                             /* allocate a buffer             */
  282.  
  283.     cpicerr_exchange_version(cpicerr,
  284.                              cm_conv_id,
  285.                              CM_RECEIVE_STATE,
  286.                              &partner_major_version,
  287.                              &partner_minor_version);
  288.  
  289.     do {
  290.         unsigned long count;                /* number of consecutive         */
  291.                                             /* sends or receives             */
  292.         count = 0;                          /* initialize count of recvs     */
  293.         do {
  294.            cmrcv (cm_conv_id,               /* Receive Data                  */
  295.                   buffer,                   /* Data Pointer                  */
  296.                   &max_receive_len,         /* Size of Data Buffer           */
  297.                   &data_received,           /* returned - data received      */
  298.                   &received_len,            /* returned - length of data     */
  299.                   &status_received,         /* returned - status received    */
  300.                   &rts_received,            /* returned - request to send    */
  301.                   &cm_rc);
  302.  
  303.             if (data_received != CM_NO_DATA_RECEIVED) {
  304.                 count++;                    /* keep track of receives        */
  305.             }
  306.         } while ( (status_received != CM_SEND_RECEIVED) &&
  307.                   (status_received != CM_CONFIRM_RECEIVED) &&
  308.                    !cm_rc);
  309.         /*
  310.          * loop until we get permission to send data or until error
  311.          */
  312.  
  313.         if (cm_rc != CM_OK) {
  314.             if (cm_rc == CM_DEALLOCATED_NORMAL) {
  315.                 do_exit(EXIT_SUCCESS);
  316.             } else {
  317.                 cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  318.             }
  319.         }
  320.  
  321.         if (status_received != CM_CONFIRM_RECEIVED) {
  322.             /*
  323.              * count is now equal to the number of data blocks we received
  324.              * now we will send back the same number of data blocks of equal
  325.              * size
  326.              */
  327.             {
  328.             CM_SEND_TYPE send_type = CM_BUFFER_DATA;
  329.             cmsst(cm_conv_id,
  330.                   &send_type,
  331.                   &cm_rc);
  332.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  333.             }
  334.  
  335.                                  /* send back the same number except for one */
  336.             for ( count--; count && !cm_rc; count-- ) {
  337.                 length = received_len;
  338.                 cmsend(cm_conv_id,
  339.                        buffer,
  340.                        &length,
  341.                        &rts_received,
  342.                        &cm_rc);
  343.                 if (cm_rc != CM_OK) {
  344.                     cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  345.                 }
  346.             }
  347.  
  348.             /*
  349.              * Set the send type to do a send and a prepare to receive.
  350.              * This will send both the data and the send permission indicator
  351.              * to our partner all at once.
  352.              */
  353.             {
  354.             CM_SEND_TYPE send_type = CM_SEND_AND_PREP_TO_RECEIVE;
  355.             cmsst(cm_conv_id,
  356.                   &send_type,
  357.                   &cm_rc);
  358.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  359.             }
  360.  
  361.             length = received_len;
  362.             cmsend(cm_conv_id,
  363.                    buffer,
  364.                    &length,
  365.                    &rts_received,
  366.                    &cm_rc);
  367.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  368.         } else {
  369.             /*
  370.              * The partner has requested one way data transfer only.
  371.              * We'll just issue Confirmed, then go back up to receive
  372.              * more data.
  373.              */
  374.             cmcfmd(cm_conv_id,
  375.                    &cm_rc);
  376.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMCFMD, cm_rc);
  377.         }
  378.     } while (cm_rc == CM_OK);
  379.  
  380.  
  381.     /* destroy the object we created with cpicerr_new() */
  382.     cpicerr_destroy(cpicerr);
  383.  
  384.     do_exit(EXIT_SUCCESS);
  385. }
  386.  
  387. #ifdef WIN32
  388. /*****************************************************************************/
  389. /* The following code makes this TP invokable as an NT service. There are 3  */
  390. /* routines.                                                                 */
  391. /*                                                                           */
  392. /* 1. main. This is the entry point for the process, it sets up a service    */
  393. /*          table entry and then calls StartServiceCtrlDispatcher. This call */
  394. /*          doesn't return, but uses the thread which called it as a         */
  395. /*          control dispatcher for all the services implemented by this      */
  396. /*          process (in this case, just the TP itself).                      */
  397. /*                                                                           */
  398. /* 2. ServiceMain. This is the main entry point for the service itself, the  */
  399. /*          service control dispatcher creates a thread to start at this     */
  400. /*          routine. It must register a service control handler for the      */
  401. /*          service which will be called by the control dispatcher when it   */
  402. /*          has control instructions for the service. It then informs the    */
  403. /*          service control manager that the service is running and finally  */
  404. /*          calls the start of the TP itself. This routine should not return */
  405. /*          until the service is ready to die.                               */
  406. /*                                                                           */
  407. /* 3. ControlHandler. This routine is called by the control dispatcher when  */
  408. /*          it has instructions for the service. We do not respond to any    */
  409. /*          of the instructions as this service should be transitory and not */
  410. /*          actually run for more than a few seconds so we don't need to do  */
  411. /*          anything with the STOP or SHUTDOWN requests.                     */
  412. /*          Note that we MUST call SetServiceStatus, even if the status      */
  413. /*          hasn't changed.                                                  */
  414. /*****************************************************************************/
  415.  
  416. void __cdecl main( DWORD argc, LPSTR * argv);
  417. void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs);
  418. VOID WINAPI ControlHandler(DWORD dwControl);
  419. SERVICE_STATUS_HANDLE stat_hand;
  420. SERVICE_STATUS servstat;
  421.  
  422. void __cdecl main( DWORD argc, LPSTR * argv)
  423. {
  424.   SERVICE_TABLE_ENTRY  stab[2];
  425.  
  426.   /***************************************************************************/
  427.   /* Start the control dispatcher. This call gives the SCManager this        */
  428.   /* thread for the entire period that this service is running, so that it   */
  429.   /* can call us back with service controls. It will spawn a new thread to   */
  430.   /* run the service itself, starting at entrypoint ServiceMain.             */
  431.   /***************************************************************************/
  432.   stab[0].lpServiceName = "APINGD\0";
  433.   stab[0].lpServiceProc = ServiceMain;
  434.  
  435.   stab[1].lpServiceName = NULL;
  436.   stab[1].lpServiceProc = NULL;
  437.  
  438.   StartServiceCtrlDispatcher(stab);
  439.  
  440. }
  441.  
  442.  
  443. /*****************************************************************************/
  444. /* This routine is the entry-point for the service itself the service        */
  445. /* control dispatcher creates a thread to start here when we issue           */
  446. /* StartServiceControlDispatcher.                                            */
  447. /*                                                                           */
  448. /* Inputs:  number of arguments to services, array of strings.               */
  449. /*                                                                           */
  450. /* Outputs: none                                                             */
  451. /*                                                                           */
  452. /*****************************************************************************/
  453. void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs)
  454. {
  455.  
  456.   DWORD rc;
  457.  
  458.   stat_hand = RegisterServiceCtrlHandler("APINGD\0", ControlHandler);
  459.   if (stat_hand == (SERVICE_STATUS_HANDLE)NULL)
  460.   {
  461.     rc = GetLastError();
  462.     DebugBreak();
  463.   }
  464.  
  465.   /***************************************************************************/
  466.   /* Let the SCManager know that we are running.                             */
  467.   /***************************************************************************/
  468.   servstat.dwServiceType              = SERVICE_WIN32;
  469.   servstat.dwCurrentState             = SERVICE_RUNNING;
  470.   servstat.dwControlsAccepted         = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  471.   servstat.dwWin32ExitCode            = NO_ERROR;
  472.   servstat.dwServiceSpecificExitCode  = NO_ERROR;
  473.   servstat.dwCheckPoint               = 0;
  474.   servstat.dwWaitHint                 = 0;
  475.  
  476.   rc = SetServiceStatus(stat_hand, &servstat);
  477.   if (!rc)
  478.   {
  479.      rc = GetLastError();
  480.      DebugBreak();
  481.   }
  482.  
  483.   TPStart(dwNumServiceArgs, lpServiceArgs);
  484.  
  485. }
  486.  
  487. /*****************************************************************************/
  488. /* This routine is the callback from the SCManager to handle specific        */
  489. /* service control requests. It MUST call SetServiceStatus before it         */
  490. /* returns, regardless of whether the status has changed.                    */
  491. /*                                                                           */
  492. /* Inputs: service control requested                                         */
  493. /*                                                                           */
  494. /* Outputs: none                                                             */
  495. /*                                                                           */
  496. /*****************************************************************************/
  497. VOID WINAPI ControlHandler(DWORD dwControl)
  498. {
  499.   DWORD rc;
  500.  
  501.   switch (dwControl)
  502.   {
  503.     case SERVICE_CONTROL_STOP :
  504.       servstat.dwCurrentState = SERVICE_STOP_PENDING;
  505.       servstat.dwWaitHint     = 24000;
  506.       break;
  507.  
  508.     case SERVICE_CONTROL_PAUSE :
  509.     case SERVICE_CONTROL_CONTINUE :
  510.     case SERVICE_CONTROL_INTERROGATE :
  511.       servstat.dwWaitHint     = 0;
  512.       break;
  513.  
  514.      case SERVICE_CONTROL_SHUTDOWN:
  515.       servstat.dwCurrentState = SERVICE_STOP_PENDING;
  516.       servstat.dwWaitHint     = 10000;
  517.         break;
  518.   }
  519.  
  520.   rc=SetServiceStatus(stat_hand, &servstat);
  521.   if (!rc)
  522.   {
  523.      rc=GetLastError();
  524.   }
  525.  
  526. }
  527.  
  528. #endif
  529. 
  530.