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 / mping / mpingd.c < prev    next >
Encoding:
Text File  |  1997-04-09  |  22.6 KB  |  570 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.  *  24/02/94   Close thread handles
  85.  *
  86.  *****************************************************************************/
  87.  
  88. #ifdef WIN32                                                           /*WIN32*/
  89. #include <windows.h>                                                   /*WIN32*/
  90. HANDLE hWaitEvent;                                                     /*WIN32*/
  91. void __cdecl main( DWORD argc, LPSTR * argv);
  92. void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs);
  93. void TPStart( DWORD argc, LPSTR *argv);
  94. DWORD WINAPI ThreadStart( int threadarg );
  95. VOID WINAPI ControlHandler(DWORD dwControl);
  96. SERVICE_STATUS_HANDLE stat_hand = {0};
  97. SERVICE_STATUS servstat = {0};
  98. #endif                                                                 /*WIN32*/
  99.  
  100. #include "wincpic.h"
  101.  
  102. /* standard C include files */
  103. #include <stdio.h>
  104. #include <stdlib.h>
  105. #include <string.h>
  106.  
  107. /* Set up constant declarations */
  108. #include "cpicdefs.h"
  109.  
  110. /* Collection of routines with special ported version for each platform */
  111. #include "cpicport.h"
  112.  
  113. /* CPI-C error handling routines */
  114. /* This file is supplied with APINGD */
  115. #include "cpicerrs.h"
  116.  
  117. /* CPI-C initialization routines */
  118. /* This file is supplied with APINGD */
  119. #include "cpicinit.h"
  120.  
  121. /* CPI-C error handling info */
  122. CPICERR * cpicerr = {0};
  123.  
  124. /*
  125.  * Max size of a data buffer.  This is the largest size buffer that can
  126.  * be specified on a call to CPI-C.
  127.  */
  128. #define  MAX_SIZE (0x7FFF)
  129.  
  130. /* Define these here so we can make changes throughout the code. */
  131. /*
  132.  * The PROGRAM_INFO string should be kept in sync with the
  133.  * MAJOR_VERSION and MINOR_VERSION constants.  Although the
  134.  * cpicerr_exchange_version() call will support values up to 255,
  135.  * values for MINOR_VERSION should be from 00-99 to maintain the
  136.  * two character format in the version string.
  137.  */
  138. #define  PROGRAM_NAME      "APINGD"
  139. #define  PROGRAM_INFO      "version 2.35"
  140. #define  MAJOR_VERSION     (2)
  141. #define  MINOR_VERSION     (35)
  142. #define  LOG_FILE_NAME     "apingd.err"
  143. #define  LOG_FILE_PATH     "$LOGPATH"
  144.  
  145. void TPStart( DWORD argc, LPSTR *argv)
  146. {
  147.     DWORD Tid;
  148.     HANDLE      ThreadHandle;               /* thread handle for closing     */
  149.     CM_INT32    temp;                                                 /*WIN32*/
  150.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  151.  
  152.     {
  153.        /**********************************************************************/
  154.        /* Initialisation for WinCPIC                                         */
  155.        /**********************************************************************/
  156.        unsigned short WinCPICVERSION = 0x0001;
  157.        WCPICDATA CPICData;
  158.        if (WinCPICStartup(WinCPICVERSION,&CPICData))
  159.        {
  160.          return;
  161.        }
  162.        /**********************************************************************/
  163.        /* Set our local TP Name                                              */
  164.        /**********************************************************************/
  165.        temp=6;
  166.        cmsltp("APINGD",&temp,&cm_rc);
  167.     }
  168.  
  169.     /*
  170.      * Initialize the CPICERR structure.  This is done before the CMACCP
  171.      * call so that we can use CPICERR for help with errors on CMACCP.
  172.      * The procedure is in CPICERR.C
  173.      */
  174.     cpicerr = cpicerr_new();
  175.     cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
  176.     cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
  177.     cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
  178.     cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
  179.     cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
  180.     cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
  181.  
  182.     /*
  183.      * Create the first receive thread.
  184.      */
  185.     ThreadHandle = CreateThread(NULL,
  186.                                 16000,
  187.                                 (LPTHREAD_START_ROUTINE)ThreadStart,
  188.                                 NULL,
  189.                                 0,
  190.                                 &Tid);
  191.     if (ThreadHandle == NULL)
  192.     {
  193.        GetLastError();
  194.        DebugBreak();
  195.     }
  196.     CloseHandle(ThreadHandle);
  197.  
  198.     /*
  199.      * As this is effectively the ServiceMain routine, we should not return
  200.      * here until we are ready to die. We wait for an event to signal.
  201.      */
  202.  
  203.     WaitForSingleObject( hWaitEvent, INFINITE );
  204.  
  205.     /*
  206.      * Cleanup WinCPIC now.
  207.      */
  208.  
  209.     WinCPICCleanup();
  210.  
  211. }
  212.  
  213. DWORD WINAPI ThreadStart( int threadarg )                              /*WIN32*/
  214. {
  215.     /* Variables used for CPI-C calls */
  216.     unsigned char cm_conv_id[8];            /* CPI-C conversation ID         */
  217.     CM_INT32    temp;                                                 /*WIN32*/
  218.     DWORD       Tid;                                                  /*WIN32*/
  219.     HANDLE      ThreadHandle;               /* thread handle for closing     */
  220.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  221.     CM_INT32    length;                     /* generic length variable       */
  222.     CM_INT32    rts_received;               /* request to send received      */
  223.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  224.     CM_INT32    data_received;              /* Data received parm from CMRCV */
  225.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  226.     CM_INT32    status_received;            /* Status from CMRCV             */
  227.  
  228.     /* Data buffer for send and receive */
  229.     unsigned char CM_PTR buffer = NULL;    /* CPIC data buffer              */
  230.  
  231.     char        destination[MAX_DESTINATION];/* Partner destination          */
  232.     unsigned int max_size;                  /* size to receive               */
  233.  
  234.     char partner_major_version;
  235.     char partner_minor_version;
  236.  
  237.     cmaccp(cm_conv_id,                      /* Accept Conversation           */
  238.            &cm_rc);
  239.     /*
  240.      * Note that as we have used cmsltp to specify our local TP name,
  241.      * cmaccp may return asynchronously, so we must do a cmwait
  242.      */
  243.     if (cm_rc == CM_OPERATION_INCOMPLETE)                             /*WIN32*/
  244.     {                                                                 /*WIN32*/
  245.       cmwait(cm_conv_id, &cm_rc, &temp);                              /*WIN32*/
  246.     }                                                                 /*WIN32*/
  247.  
  248.     /*
  249.      * Create the next receive thread. Note if this fails, we will die
  250.      * horribly by kicking the main thread's wait event.
  251.      */
  252.     ThreadHandle = CreateThread(NULL,
  253.                                 16000,
  254.                                 (LPTHREAD_START_ROUTINE)ThreadStart,
  255.                                 NULL,
  256.                                 0,
  257.                                 &Tid);
  258.     if (ThreadHandle == NULL)
  259.     {
  260.       SetEvent(hWaitEvent);
  261.     }
  262.     else
  263.     {
  264.       CloseHandle(ThreadHandle);
  265.     }
  266.  
  267.     /*
  268.      * Fill in conversation information for CPI-C error reporting.
  269.      */
  270.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  271.  
  272.  
  273.     if (cm_rc != CM_OK) {
  274.         cpicerr_handle_rc(cpicerr, MSG_CMACCP, cm_rc);
  275.     } else {
  276.         CM_INT32 pln_length;
  277.         /*
  278.          * Extract the partner LU name and display it.
  279.          */
  280.         cmepln(cm_conv_id,
  281.                (unsigned char *)destination,
  282.                &pln_length,
  283.                &cm_rc );
  284.  
  285.         destination[(int)pln_length] = '\0';
  286.         write_output("\nContacted by partner: %s\n", destination);
  287.  
  288.     }
  289.  
  290.  
  291.     {
  292.     CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
  293.     cmsptr(cm_conv_id,                       /* Set prepare to receive type  */
  294.            &prep_to_receive,
  295.            &cm_rc);
  296.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
  297.     }
  298.  
  299.  
  300.     max_receive_len = max_size = MAX_SIZE;
  301.  
  302.     buffer = (unsigned char CM_PTR)alloc_cpic_buffer(max_size);
  303.                                             /* allocate a buffer             */
  304.  
  305.     cpicerr_exchange_version(cpicerr,
  306.                              cm_conv_id,
  307.                              CM_RECEIVE_STATE,
  308.                              &partner_major_version,
  309.                              &partner_minor_version);
  310.  
  311.     do {
  312.         unsigned long count;                /* number of consecutive         */
  313.                                             /* sends or receives             */
  314.         count = 0;                          /* initialize count of recvs     */
  315.         do {
  316.            cmrcv (cm_conv_id,               /* Receive Data                  */
  317.                   buffer,                   /* Data Pointer                  */
  318.                   &max_receive_len,         /* Size of Data Buffer           */
  319.                   &data_received,           /* returned - data received      */
  320.                   &received_len,            /* returned - length of data     */
  321.                   &status_received,         /* returned - status received    */
  322.                   &rts_received,            /* returned - request to send    */
  323.                   &cm_rc);
  324.  
  325.             if (data_received != CM_NO_DATA_RECEIVED) {
  326.                 count++;                    /* keep track of receives        */
  327.             }
  328.         } while ( (status_received != CM_SEND_RECEIVED) &&
  329.                   (status_received != CM_CONFIRM_RECEIVED) &&
  330.                    !cm_rc);
  331.         /*
  332.          * loop until we get permission to send data or until error
  333.          */
  334.  
  335.         if (cm_rc != CM_OK) {
  336.             if (cm_rc == CM_DEALLOCATED_NORMAL) {
  337.                 free_cpic_buffer( buffer );
  338.                 buffer = NULL;
  339.                 do_exit(EXIT_SUCCESS);
  340.             } else {
  341.                 cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  342.             }
  343.         }
  344.  
  345.         if (status_received != CM_CONFIRM_RECEIVED) {
  346.             /*
  347.              * count is now equal to the number of data blocks we received
  348.              * now we will send back the same number of data blocks of equal
  349.              * size
  350.              */
  351.             {
  352.             CM_SEND_TYPE send_type = CM_BUFFER_DATA;
  353.             cmsst(cm_conv_id,
  354.                   &send_type,
  355.                   &cm_rc);
  356.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  357.             }
  358.  
  359.                                  /* send back the same number except for one */
  360.             for ( count--; count && !cm_rc; count-- ) {
  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) {
  368.                     cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  369.                 }
  370.             }
  371.  
  372.             /*
  373.              * Set the send type to do a send and a prepare to receive.
  374.              * This will send both the data and the send permission indicator
  375.              * to our partner all at once.
  376.              */
  377.             {
  378.             CM_SEND_TYPE send_type = CM_SEND_AND_PREP_TO_RECEIVE;
  379.             cmsst(cm_conv_id,
  380.                   &send_type,
  381.                   &cm_rc);
  382.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  383.             }
  384.  
  385.             length = received_len;
  386.             cmsend(cm_conv_id,
  387.                    buffer,
  388.                    &length,
  389.                    &rts_received,
  390.                    &cm_rc);
  391.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  392.         } else {
  393.             /*
  394.              * The partner has requested one way data transfer only.
  395.              * We'll just issue Confirmed, then go back up to receive
  396.              * more data.
  397.              */
  398.             cmcfmd(cm_conv_id,
  399.                    &cm_rc);
  400.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMCFMD, cm_rc);
  401.         }
  402.     } while (cm_rc == CM_OK);
  403.  
  404.     if( buffer != NULL )
  405.     {
  406.         free_cpic_buffer( buffer );
  407.     }
  408.     /* destroy the object we created with cpicerr_new() */
  409.     cpicerr_destroy(cpicerr);
  410.  
  411.     do_exit(EXIT_SUCCESS);
  412.  
  413.     /* never executed, just to keep compiler happy */
  414.     return(0);
  415. }
  416.  
  417. /*****************************************************************************/
  418. /* The following code makes this TP invokable as an NT service. There are 3  */
  419. /* routines.                                                                 */
  420. /*                                                                           */
  421. /* 1. main. This is the entry point for the process, it sets up a service    */
  422. /*          table entry and then calls StartServiceCtrlDispatcher. This call */
  423. /*          doesn't return, but uses the thread which called it as a         */
  424. /*          control dispatcher for all the services implemented by this      */
  425. /*          process (in this case, just the TP itself).                      */
  426. /*                                                                           */
  427. /* 2. ServiceMain. This is the main entry point for the service itself, the  */
  428. /*          service control dispatcher creates a thread to start at this     */
  429. /*          routine. It must register a service control handler for the      */
  430. /*          service which will be called by the control dispatcher when it   */
  431. /*          has control instructions for the service. It then informs the    */
  432. /*          service control manager that the service is running and finally  */
  433. /*          calls the start of the TP itself. This routine should not return */
  434. /*          until the service is ready to die.                               */
  435. /*                                                                           */
  436. /* 3. ControlHandler. This routine is called by the control dispatcher when  */
  437. /*          it has instructions for the service. We do not respond to any    */
  438. /*          of the instructions as this service should be transitory and not */
  439. /*          actually run for more than a few seconds so we don't need to do  */
  440. /*          anything with the STOP or SHUTDOWN requests.                     */
  441. /*          Note that we MUST call SetServiceStatus, even if the status      */
  442. /*          hasn't changed.                                                  */
  443. /*****************************************************************************/
  444.  
  445. void __cdecl main( DWORD argc, LPSTR * argv)
  446. {
  447.   SERVICE_TABLE_ENTRY  stab[2];
  448.  
  449.   /***************************************************************************/
  450.   /* Start the control dispatcher. This call gives the SCManager this        */
  451.   /* thread for the entire period that this service is running, so that it   */
  452.   /* can call us back with service controls. It will spawn a new thread to   */
  453.   /* run the service itself, starting at entrypoint ServiceMain.             */
  454.   /***************************************************************************/
  455.   stab[0].lpServiceName = "APINGD\0";
  456.   stab[0].lpServiceProc = ServiceMain;
  457.  
  458.   stab[1].lpServiceName = NULL;
  459.   stab[1].lpServiceProc = NULL;
  460.  
  461.   StartServiceCtrlDispatcher(stab);
  462.  
  463. }
  464.  
  465.  
  466. /*****************************************************************************/
  467. /* This routine is the entry-point for the service itself the service        */
  468. /* control dispatcher creates a thread to start here when we issue           */
  469. /* StartServiceControlDispatcher.                                            */
  470. /*                                                                           */
  471. /* Inputs:  number of arguments to services, array of strings.               */
  472. /*                                                                           */
  473. /* Outputs: none                                                             */
  474. /*                                                                           */
  475. /*****************************************************************************/
  476. void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs)
  477. {
  478.  
  479.   DWORD rc;
  480.  
  481.   stat_hand = RegisterServiceCtrlHandler("APINGD\0", ControlHandler);
  482.   if (stat_hand == (SERVICE_STATUS_HANDLE)NULL)
  483.   {
  484.     rc = GetLastError();
  485.     DebugBreak();
  486.   }
  487.  
  488.   if ((hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL )) == NULL)
  489.   {
  490.     rc = GetLastError();
  491.     DebugBreak();
  492.   }
  493.  
  494.   /***************************************************************************/
  495.   /* Let the SCManager know that we are running.                             */
  496.   /***************************************************************************/
  497.   servstat.dwServiceType              = SERVICE_WIN32;
  498.   servstat.dwCurrentState             = SERVICE_RUNNING;
  499.   servstat.dwControlsAccepted         = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  500.   servstat.dwWin32ExitCode            = NO_ERROR;
  501.   servstat.dwServiceSpecificExitCode  = NO_ERROR;
  502.   servstat.dwCheckPoint               = 0;
  503.   servstat.dwWaitHint                 = 0;
  504.  
  505.   rc = SetServiceStatus(stat_hand, &servstat);
  506.   if (!rc)
  507.   {
  508.      rc = GetLastError();
  509.      DebugBreak();
  510.   }
  511.  
  512.   TPStart(dwNumServiceArgs, lpServiceArgs);
  513.  
  514.   servstat.dwCurrentState = SERVICE_STOPPED;
  515.   rc = SetServiceStatus(stat_hand, &servstat);
  516.   if (!rc)
  517.   {
  518.      rc = GetLastError();
  519.      DebugBreak();
  520.   }
  521.  
  522. }
  523.  
  524. /*****************************************************************************/
  525. /* This routine is the callback from the SCManager to handle specific        */
  526. /* service control requests. It MUST call SetServiceStatus before it         */
  527. /* returns, regardless of whether the status has changed.                    */
  528. /*                                                                           */
  529. /* Inputs: service control requested                                         */
  530. /*                                                                           */
  531. /* Outputs: none                                                             */
  532. /*                                                                           */
  533. /*****************************************************************************/
  534. VOID WINAPI ControlHandler(DWORD dwControl)
  535. {
  536.   DWORD rc;
  537.  
  538.   switch (dwControl)
  539.   {
  540.     case SERVICE_CONTROL_PAUSE :
  541.     case SERVICE_CONTROL_CONTINUE :
  542.     case SERVICE_CONTROL_INTERROGATE :
  543.       servstat.dwWaitHint     = 0;
  544.       break;
  545.  
  546.      case SERVICE_CONTROL_SHUTDOWN:
  547.     case SERVICE_CONTROL_STOP :
  548.       servstat.dwCurrentState = SERVICE_STOP_PENDING;
  549.       servstat.dwWaitHint     = 10000;
  550.         break;
  551.   }
  552.  
  553.   rc=SetServiceStatus(stat_hand, &servstat);
  554.   if (!rc)
  555.   {
  556.      rc=GetLastError();
  557.      DebugBreak();
  558.   }
  559.  
  560.   if ((dwControl == SERVICE_CONTROL_STOP) ||
  561.       (dwControl == SERVICE_CONTROL_SHUTDOWN))
  562.   {
  563.      if (!SetEvent(hWaitEvent))
  564.      {
  565.         rc=GetLastError();
  566.         DebugBreak();
  567.      }
  568.   }
  569. }
  570.