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 / arexec / arexecd.c < prev    next >
Text File  |  1997-04-09  |  17KB  |  399 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME : AREXECD.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:  This module is the server side of AREXEC.  This module
  29.  *             will execute a specified command and route the output
  30.  *             back to the AREXEC transaction program.
  31.  *
  32.  *  AVAILABILITY:
  33.  *             These sample programs and source are also available on
  34.  *             CompuServe through the APPC Information Exchange.  To get
  35.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  36.  *             prompt.  The samples are available in the Sample Programs
  37.  *             library section.  Just search on the keyword CPICPGMS to
  38.  *             find all the samples in this series.
  39.  *
  40.  *             Updates for the sample programs and support for many more
  41.  *             CPI-C platforms will also be made available on CompuServe.
  42.  *
  43.  *  RELATED FILES:
  44.  *             See AREXEC.DOC for usage instructions.
  45.  *
  46.  *  CHANGE HISTORY:
  47.  *  Date       Description
  48.  *  06/15/92   NS/DOS accepts version 2.02 into system test.
  49.  *  08/05/92   Version 2.31 released to CompuServe
  50.  *             This version was also distributed at the APPC/APPN Platform
  51.  *             Developer's Conference held in Raleigh, NC.
  52.  *  08/13/92   Changed all printf and fprintf calls to use a write_*() call.
  53.  *  08/24/92   Version 2.32 released to CompuServe.
  54.  *  09/22/92   Version 2.33 released to CompuServe.
  55.  *  11/17/92   Supports sending operating system string - see CPICERR.C
  56.  *             Version 2.34 released to CompuServe
  57.  *  01/07/93   Version 2.35
  58.  *             Fixed a number of problems when compiling with IBM C Set/2
  59.  *                password input was displayed
  60.  *                timer resolution was 1 second
  61.  *                arexecd server did not function properly
  62.  *
  63.  *****************************************************************************/
  64.  
  65. #ifdef WIN32                                                           /*WIN32*/
  66. #include <windows.h>                                                   /*WIN32*/
  67. SERVICE_STATUS_HANDLE stat_hand;                                       /*WIN32*/
  68. SERVICE_STATUS servstat;                                               /*WIN32*/
  69. #endif                                                                 /*WIN32*/
  70.  
  71. #include "wincpic.h"
  72.  
  73. /* standard C include files */
  74. #include <string.h>
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <stddef.h>
  78.  
  79. /* Set up constant declarations */
  80. #include "cpicdefs.h"
  81.  
  82. /* Collection of routines with special ported version for each platform */
  83. #include "cpicport.h"
  84.  
  85. #define  MAX_COMMAND_LENGTH   500
  86.  
  87. /*--------------------------------------------------------------------------*/
  88. /*      CPI-C Error Handling Global Variables                               */
  89. /*--------------------------------------------------------------------------*/
  90. #include "cpicerrs.h"                        /* CPI-C error handling vars.   */
  91. CPICERR * cpicerr;
  92.  
  93. /* Define these here so we can make changes throughout the code. */
  94. /*
  95.  * The PROGRAM_INFO string should be kept in sync with the
  96.  * MAJOR_VERSION and MINOR_VERSION constants.  Although the
  97.  * cpicerr_exchange_version() call will support values up to 255,
  98.  * values for MINOR_VERSION should be from 00-99 to maintain the
  99.  * two character format in the version string.
  100.  */
  101. #define  PROGRAM_NAME      "AREXECD"
  102. #define  PROGRAM_INFO      "version 2.35"
  103. #define  MAJOR_VERSION     (2)
  104. #define  MINOR_VERSION     (35)
  105. #define  LOG_FILE_NAME     "arexecd.err"
  106. #define  LOG_FILE_PATH     "$LOGPATH"
  107.  
  108.  
  109. char * intro[] = {
  110.     PROGRAM_NAME " " PROGRAM_INFO " - Remote execution of a command. (Server)",
  111.     NULL
  112.     };
  113.  
  114.  
  115. void
  116. TPStart(void)
  117. {
  118.     /* Variables used for CPI-C calls */
  119.     unsigned char cm_conv_id[8];            /* CPI-C conversation ID         */
  120.     CM_INT32    temp;                                                 /*WIN32*/
  121.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  122.     CM_INT32    length;                     /* generic length variable       */
  123.     CM_INT32    rts_received;               /* request to send received      */
  124.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  125.     CM_INT32    what_received;              /* What received parm from CMRCV */
  126.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  127.     CM_INT32    status_received;            /* Status from CMRCV             */
  128.  
  129.     /* Data buffer for send and receive */
  130.     char        buffer[MAX_COMMAND_LENGTH]; /* CPIC data buffer              */
  131.  
  132.     char partner_major_version;
  133.     char partner_minor_version;
  134.  
  135.     unsigned char destination[MAX_FQPLU_NAME];
  136.  
  137.     show_info(intro);
  138.  
  139. #ifdef WIN32
  140.     {
  141.        /**********************************************************************/
  142.        /* Initialisation for WinCPIC                                         */
  143.        /**********************************************************************/
  144.        unsigned short WinCPICVERSION = 0x0001;
  145.        WCPICDATA CPICData;
  146.        if (WinCPICStartup(WinCPICVERSION,&CPICData))
  147.        {
  148.          return;
  149.        }
  150.        /**********************************************************************/
  151.        /* Set our local TP Name                                              */
  152.        /**********************************************************************/
  153.        temp=7;
  154.        cmsltp("AREXECD",&temp,&cm_rc);
  155.     }
  156. #endif
  157.  
  158.     /*
  159.      * Initialize the CPICERR structure.  This is done before the CMINIT
  160.      * call so that we can use CPICERR for help with errors on CMINIT.
  161.      * The procedure is in CPICERR.C
  162.      */
  163.     cpicerr = cpicerr_new();
  164.     cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
  165.     cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
  166.     cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
  167.     cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
  168.     cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
  169.     cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
  170.  
  171.     cmaccp(cm_conv_id,
  172.            &cm_rc);
  173.     /*
  174.      * Note that as we have used cmsltp to specify our local TP name,
  175.      * cmaccp may return asynchronously, so we must do a cmwait
  176.      */
  177.     if (cm_rc == CM_OPERATION_INCOMPLETE)                             /*WIN32*/
  178.     {                                                                 /*WIN32*/
  179.       cmwait(cm_conv_id, &cm_rc, &temp);                              /*WIN32*/
  180.     }                                                                 /*WIN32*/
  181.  
  182.    /*------------------------------------------------------------------------*
  183.     * Fill in conversation information for CPI-C error reporting.
  184.     *------------------------------------------------------------------------*/
  185.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  186.  
  187.     if (cm_rc != CM_OK) {
  188.         cpicerr_handle_rc(cpicerr, MSG_CMACCP, cm_rc);
  189.     } else {
  190.         length = 17;
  191.         cmepln(cm_conv_id,
  192.                destination,
  193.                &length,
  194.                &cm_rc );
  195.         destination[(unsigned int)length] = '\0';
  196.         write_output("\nContacted by partner: ");
  197.         write_output("%s", destination);
  198.         write_output("\n");
  199.     }
  200.  
  201.     cpicerr_exchange_version(cpicerr,
  202.                              cm_conv_id,
  203.                              CM_RECEIVE_STATE,
  204.                              &partner_major_version,
  205.                              &partner_minor_version);
  206.  
  207.     {
  208.     CM_SEND_TYPE send_type = CM_SEND_AND_FLUSH;
  209.     cmsst(cm_conv_id,                       /* Set send type                 */
  210.           &send_type,
  211.           &cm_rc);
  212.     }
  213.  
  214.     max_receive_len = MAX_COMMAND_LENGTH-1;
  215.  
  216.     cmrcv(cm_conv_id,                       /* Receive Data                  */
  217.           (unsigned char *) buffer,         /* Data Pointer                  */
  218.           &max_receive_len,                 /* Size of Data Buffer           */
  219.           &what_received,                   /* returned - what received      */
  220.           &received_len,                    /* returned - length of data     */
  221.           &status_received,                 /* returned - status received    */
  222.           &rts_received,                    /* returned - request to send    */
  223.           &cm_rc);
  224.  
  225.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  226.  
  227.     buffer[(unsigned int)received_len] = '\0';
  228.  
  229.     convert_from_ascii(buffer, strlen(buffer));
  230.  
  231.     write_output("The command is:\n%s\n\n", buffer);
  232.  
  233.     execute_and_send_output(buffer,
  234.                             cm_conv_id,
  235.                             cpicerr);
  236.  
  237.     {
  238.     CM_DEALLOCATE_TYPE deallocate_type = CM_DEALLOCATE_FLUSH;
  239.  
  240.     cmsdt(cm_conv_id,
  241.           &deallocate_type,
  242.           &cm_rc);
  243.     }
  244.  
  245.     cmdeal(cm_conv_id,
  246.            &cm_rc);
  247.     if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMDEAL, cm_rc);
  248.  
  249.     /* destroy the object we created with cpicerr_new() */
  250.     cpicerr_destroy(cpicerr);
  251.  
  252.     exit(EXIT_SUCCESS);
  253.  
  254. }
  255.  
  256. #ifdef WIN32
  257. /*****************************************************************************/
  258. /* The following code makes this TP invokable as an NT service. There are 3  */
  259. /* routines.                                                                 */
  260. /*                                                                           */
  261. /* 1. main. This is the entry point for the process, it sets up a service    */
  262. /*          table entry and then calls StartServiceCtrlDispatcher. This call */
  263. /*          doesn't return, but uses the thread which called it as a         */
  264. /*          control dispatcher for all the services implemented by this      */
  265. /*          process (in this case, just the TP itself).                      */
  266. /*                                                                           */
  267. /* 2. ServiceMain. This is the main entry point for the service itself, the  */
  268. /*          service control dispatcher creates a thread to start at this     */
  269. /*          routine. It must register a service control handler for the      */
  270. /*          service which will be called by the control dispatcher when it   */
  271. /*          has control instructions for the service. It then informs the    */
  272. /*          service control manager that the service is running and finally  */
  273. /*          calls the start of the TP itself. This routine should not return */
  274. /*          until the service is ready to die.                               */
  275. /*                                                                           */
  276. /* 3. ControlHandler. This routine is called by the control dispatcher when  */
  277. /*          it has instructions for the service. We do not respond to any    */
  278. /*          of the instructions as this service should be transitory and not */
  279. /*          actually run for more than a few seconds so we don't need to do  */
  280. /*          anything with the STOP or SHUTDOWN requests.                     */
  281. /*          Note that we MUST call SetServiceStatus, even if the status      */
  282. /*          hasn't changed.                                                  */
  283. /*****************************************************************************/
  284.  
  285. void __cdecl main( DWORD argc, LPSTR * argv);
  286. void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs);
  287. VOID WINAPI ControlHandler(DWORD dwControl);
  288. SERVICE_STATUS_HANDLE stat_hand;
  289. SERVICE_STATUS servstat;
  290.  
  291. void __cdecl main( DWORD argc, LPSTR * argv)
  292. {
  293.   SERVICE_TABLE_ENTRY  stab[2];
  294.  
  295.   /***************************************************************************/
  296.   /* Start the control dispatcher. This call gives the SCManager this        */
  297.   /* thread for the entire period that this service is running, so that it   */
  298.   /* can call us back with service controls. It will spawn a new thread to   */
  299.   /* run the service itself, starting at entrypoint ServiceMain.             */
  300.   /***************************************************************************/
  301.   stab[0].lpServiceName = "AREXECD\0";
  302.   stab[0].lpServiceProc = ServiceMain;
  303.  
  304.   stab[1].lpServiceName = NULL;
  305.   stab[1].lpServiceProc = NULL;
  306.  
  307.   StartServiceCtrlDispatcher(stab);
  308.  
  309. }
  310.  
  311.  
  312. /*****************************************************************************/
  313. /* This routine is the entry-point for the service itself the service        */
  314. /* control dispatcher creates a thread to start here when we issue           */
  315. /* StartServiceControlDispatcher.                                            */
  316. /*                                                                           */
  317. /* Inputs:  number of arguments to services, array of strings.               */
  318. /*                                                                           */
  319. /* Outputs: none                                                             */
  320. /*                                                                           */
  321. /*****************************************************************************/
  322. void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs)
  323. {
  324.  
  325.   DWORD rc;
  326.  
  327.   stat_hand = RegisterServiceCtrlHandler("AREXECD\0", ControlHandler);
  328.   if (stat_hand == (SERVICE_STATUS_HANDLE)NULL)
  329.   {
  330.     rc = GetLastError();
  331.     DebugBreak();
  332.   }
  333.  
  334.   /***************************************************************************/
  335.   /* Let the SCManager know that we are running.                             */
  336.   /***************************************************************************/
  337.   servstat.dwServiceType              = SERVICE_WIN32;
  338.   servstat.dwCurrentState             = SERVICE_RUNNING;
  339.   servstat.dwControlsAccepted         = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  340.   servstat.dwWin32ExitCode            = NO_ERROR;
  341.   servstat.dwServiceSpecificExitCode  = NO_ERROR;
  342.   servstat.dwCheckPoint               = 0;
  343.   servstat.dwWaitHint                 = 0;
  344.  
  345.   rc = SetServiceStatus(stat_hand, &servstat);
  346.   if (!rc)
  347.   {
  348.      rc = GetLastError();
  349.      DebugBreak();
  350.   }
  351.  
  352.   TPStart();
  353.  
  354. }
  355.  
  356. /*****************************************************************************/
  357. /* This routine is the callback from the SCManager to handle specific        */
  358. /* service control requests. It MUST call SetServiceStatus before it         */
  359. /* returns, regardless of whether the status has changed.                    */
  360. /*                                                                           */
  361. /* Inputs: service control requested                                         */
  362. /*                                                                           */
  363. /* Outputs: none                                                             */
  364. /*                                                                           */
  365. /*****************************************************************************/
  366. VOID WINAPI ControlHandler(DWORD dwControl)
  367. {
  368.   DWORD rc;
  369.  
  370.   switch (dwControl)
  371.   {
  372.     case SERVICE_CONTROL_STOP :
  373.       servstat.dwCurrentState = SERVICE_STOP_PENDING;
  374.       servstat.dwWaitHint     = 24000;
  375.       break;
  376.  
  377.     case SERVICE_CONTROL_PAUSE :
  378.     case SERVICE_CONTROL_CONTINUE :
  379.     case SERVICE_CONTROL_INTERROGATE :
  380.       servstat.dwWaitHint     = 0;
  381.       break;
  382.  
  383.      case SERVICE_CONTROL_SHUTDOWN:
  384.       servstat.dwCurrentState = SERVICE_STOP_PENDING;
  385.       servstat.dwWaitHint     = 10000;
  386.         break;
  387.   }
  388.  
  389.   rc=SetServiceStatus(stat_hand, &servstat);
  390.   if (!rc)
  391.   {
  392.      rc=GetLastError();
  393.   }
  394.  
  395. }
  396.  
  397. #endif
  398. 
  399.