home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- *
- * MODULE NAME: APINGD.C
- *
- * COPYRIGHTS:
- * This module contains code made available by IBM
- * Corporation on an AS IS basis. Any one receiving the
- * module is considered to be licensed under IBM copyrights
- * to use the IBM-provided source code in any way he or she
- * deems fit, including copying it, compiling it, modifying
- * it, and redistributing it, with or without
- * modifications. No license under any IBM patents or
- * patent applications is to be implied from this copyright
- * license.
- *
- * A user of the module should understand that IBM cannot
- * provide technical support for the module and will not be
- * responsible for any consequences of use of the program.
- *
- * Any notices, including this one, are not to be removed
- * from the module without the prior written consent of
- * IBM.
- *
- * AUTHOR: Peter J. Schwaller
- * VNET: PJS at RALVM6 Tie Line: 444-4376
- * Internet: pjs@ralvm6.vnet.ibm.com (919) 254-4376
- *
- * FUNCTION: Perform an echo test to a specified LU.
- * APING can be used when you are first installing APPC on
- * your computer to make sure you can connect to another
- * computer in the network. APING can also be used to
- * get an estimate of the delay time or throughput to another
- * computer in the network.
- *
- * APINGD echos whatever is sent by APING.
- * Keep receiving until you get permission to send
- * Send the same number of same size records
- *
- * AVAILABILITY:
- * These sample programs and source are also available on
- * CompuServe through the APPC Information Exchange. To get
- * to the APPC forum just type 'GO APPC' from any CompuServe
- * prompt. The samples are available in the Sample Programs
- * library section. Just search on the keyword CPICPGMS to
- * find all the samples in this series.
- *
- * Updates for the sample programs and support for many more
- * CPI-C platforms will also be made available on CompuServe.
- *
- * RELATED FILES:
- * See APING.DOC for usage instructions.
- *
- * PORTABILIITY NOTES:
- * The APINGD server program is completely portable. In fact,
- * all of the source modules can be compiled without #define-ing
- * any platform constant value.
- *
- * To take advantage of a performance optimization on the
- * OS/2 platform, the alloc_cpic_buffer() is used. If the
- * OS/2 platform is specified (#define of OS2, FAPI, or OS2_20)
- * alloc_cpic_buffer() will return a shared memory buffer.
- * If not, a buffer allocated with malloc() will be returned.
- *
- * If you are porting to a platform that can take advantage
- * of a specially allocated memory buffer, you should
- * add this support to the alloc_cpic_buffer() call in the
- * CPICPORT.C file.
- *
- * CHANGE HISTORY:
- * Date Description
- * 06/15/92 NS/DOS accepts version 2.02 into system test.
- * 08/05/92 Version 2.31 released to CompuServe
- * This version was also distributed at the APPC/APPN Platform
- * Developer's Conference held in Raleigh, NC.
- * 08/13/92 Changed all printf and fprintf calls to use a write_*() call.
- * 08/24/92 Version 2.32 released to CompuServe.
- * 09/22/92 Version 2.33 released to CompuServe.
- * 11/17/92 Supports sending operating system string - see CPICERR.C
- * Version 2.34 released to CompuServe
- * 01/07/93 Version 2.35
- * Fixed a number of problems when compiling with IBM C Set/2
- * password input was displayed
- * timer resolution was 1 second
- *
- *****************************************************************************/
-
- #ifdef WIN32 /*WIN32*/
- #include <windows.h> /*WIN32*/
- SERVICE_STATUS_HANDLE stat_hand; /*WIN32*/
- SERVICE_STATUS servstat; /*WIN32*/
- #endif /*WIN32*/
-
- #include "wincpic.h"
-
- /* standard C include files */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- /* Set up constant declarations */
- #include "cpicdefs.h"
-
- /* Collection of routines with special ported version for each platform */
- #include "cpicport.h"
-
- /* CPI-C error handling routines */
- /* This file is supplied with APINGD */
- #include "cpicerrs.h"
-
- /* CPI-C initialization routines */
- /* This file is supplied with APINGD */
- #include "cpicinit.h"
-
- /* Argument processing procedure */
- /* This file is supplied with APINGD */
- #include "getopt.h"
-
- /* CPI-C error handling info */
- CPICERR * cpicerr;
-
- /*
- * Max size of a data buffer. This is the largest size buffer that can
- * be specified on a call to CPI-C.
- */
- #define MAX_SIZE (0x7FFF)
-
- /* Define these here so we can make changes throughout the code. */
- /*
- * The PROGRAM_INFO string should be kept in sync with the
- * MAJOR_VERSION and MINOR_VERSION constants. Although the
- * cpicerr_exchange_version() call will support values up to 255,
- * values for MINOR_VERSION should be from 00-99 to maintain the
- * two character format in the version string.
- */
- #define PROGRAM_NAME "APINGD"
- #define PROGRAM_INFO "version 2.35"
- #define MAJOR_VERSION (2)
- #define MINOR_VERSION (35)
- #define LOG_FILE_NAME "apingd.err"
- #define LOG_FILE_PATH "$LOGPATH"
-
- /*
- * Message displayed with show_info() when APINGD is started.
- */
- char * intro[] = {
- PROGRAM_NAME " " PROGRAM_INFO " - APPC loopback server",
- NULL
- };
-
- char * log_file_name = NULL;
-
- void TPStart( DWORD argc, LPSTR *argv) /*WIN32*/
- {
- /* Variables used for CPI-C calls */
- unsigned char cm_conv_id[8]; /* CPI-C conversation ID */
- CM_INT32 temp; /*WIN32*/
- CM_INT32 cm_rc; /* CPI-C return code */
- CM_INT32 length; /* generic length variable */
- CM_INT32 rts_received; /* request to send received */
- CM_INT32 max_receive_len; /* Max receive length on CMRCV */
- CM_INT32 data_received; /* Data received parm from CMRCV */
- CM_INT32 received_len; /* Amount of data rcvd on CMRCV */
- CM_INT32 status_received; /* Status from CMRCV */
-
- /* Data buffer for send and receive */
- unsigned char CM_PTR buffer; /* CPIC data buffer */
-
- char destination[MAX_DESTINATION];/* Partner destination */
- unsigned int max_size; /* size to receive */
- int c; /* flag specifed, used w/getopt */
-
- char partner_major_version;
- char partner_minor_version;
-
-
- show_info(intro); /* display intro information */
-
- #ifdef WIN32
- {
- /**********************************************************************/
- /* Initialisation for WinCPIC */
- /**********************************************************************/
- unsigned short WinCPICVERSION = 0x0001;
- WCPICDATA CPICData;
- if (WinCPICStartup(WinCPICVERSION,&CPICData))
- {
- return;
- }
- /**********************************************************************/
- /* Set our local TP Name */
- /**********************************************************************/
- temp=6;
- cmsltp("APINGD",&temp,&cm_rc);
- }
- #endif
-
- while ((DWORD)optind != argc) {
- c = getopt(argc, argv, "?l:");
- switch (c) {
- case EOF:
- optind++;
- break;
- case 'l':
- case 'L':
- write_output("\nIncoming partner LU names will be logged to: %s\n",
- optarg);
- log_file_name = optarg;
- break;
- } /* endswitch */
- } /* endwhile */
-
- /*
- * Initialize the CPICERR structure. This is done before the CMACCP
- * call so that we can use CPICERR for help with errors on CMACCP.
- * The procedure is in CPICERR.C
- */
- cpicerr = cpicerr_new();
- cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
- cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
- cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
- cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
- cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
- cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
-
- cmaccp(cm_conv_id, /* Accept Conversation */
- &cm_rc);
- /*
- * Note that as we have used cmsltp to specify our local TP name,
- * cmaccp may return asynchronously, so we must do a cmwait
- */
- if (cm_rc == CM_OPERATION_INCOMPLETE) /*WIN32*/
- { /*WIN32*/
- cmwait(cm_conv_id, &cm_rc, &temp); /*WIN32*/
- } /*WIN32*/
-
- /*
- * Fill in conversation information for CPI-C error reporting.
- */
- cpicerr_set_conv_id(cpicerr, cm_conv_id);
-
-
- if (cm_rc != CM_OK) {
- cpicerr_handle_rc(cpicerr, MSG_CMACCP, cm_rc);
- } else {
- CM_INT32 pln_length;
- /*
- * Extract the partner LU name and display it.
- */
- cmepln(cm_conv_id,
- (unsigned char *)destination,
- &pln_length,
- &cm_rc );
-
- destination[(int)pln_length] = '\0';
- write_output("\nContacted by partner: %s\n", destination);
-
- if (log_file_name != NULL) {
- FILE * file;
- file = fopen(log_file_name, "a");
- if (file != NULL) {
- write_log(file, "\nContacted by partner: %s\n", destination);
- fclose(file);
- }
- }
-
- }
-
-
- {
- CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
- cmsptr(cm_conv_id, /* Set prepare to receive type */
- &prep_to_receive,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
- }
-
-
- max_receive_len = max_size = MAX_SIZE;
-
- buffer = (unsigned char CM_PTR)alloc_cpic_buffer(max_size);
- /* allocate a buffer */
-
- cpicerr_exchange_version(cpicerr,
- cm_conv_id,
- CM_RECEIVE_STATE,
- &partner_major_version,
- &partner_minor_version);
-
- do {
- unsigned long count; /* number of consecutive */
- /* sends or receives */
- count = 0; /* initialize count of recvs */
- do {
- cmrcv (cm_conv_id, /* Receive Data */
- buffer, /* Data Pointer */
- &max_receive_len, /* Size of Data Buffer */
- &data_received, /* returned - data received */
- &received_len, /* returned - length of data */
- &status_received, /* returned - status received */
- &rts_received, /* returned - request to send */
- &cm_rc);
-
- if (data_received != CM_NO_DATA_RECEIVED) {
- count++; /* keep track of receives */
- }
- } while ( (status_received != CM_SEND_RECEIVED) &&
- (status_received != CM_CONFIRM_RECEIVED) &&
- !cm_rc);
- /*
- * loop until we get permission to send data or until error
- */
-
- if (cm_rc != CM_OK) {
- if (cm_rc == CM_DEALLOCATED_NORMAL) {
- do_exit(EXIT_SUCCESS);
- } else {
- cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
- }
- }
-
- if (status_received != CM_CONFIRM_RECEIVED) {
- /*
- * count is now equal to the number of data blocks we received
- * now we will send back the same number of data blocks of equal
- * size
- */
- {
- CM_SEND_TYPE send_type = CM_BUFFER_DATA;
- cmsst(cm_conv_id,
- &send_type,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
- }
-
- /* send back the same number except for one */
- for ( count--; count && !cm_rc; count-- ) {
- length = received_len;
- cmsend(cm_conv_id,
- buffer,
- &length,
- &rts_received,
- &cm_rc);
- if (cm_rc != CM_OK) {
- cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
- }
- }
-
- /*
- * Set the send type to do a send and a prepare to receive.
- * This will send both the data and the send permission indicator
- * to our partner all at once.
- */
- {
- CM_SEND_TYPE send_type = CM_SEND_AND_PREP_TO_RECEIVE;
- cmsst(cm_conv_id,
- &send_type,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
- }
-
- length = received_len;
- cmsend(cm_conv_id,
- buffer,
- &length,
- &rts_received,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
- } else {
- /*
- * The partner has requested one way data transfer only.
- * We'll just issue Confirmed, then go back up to receive
- * more data.
- */
- cmcfmd(cm_conv_id,
- &cm_rc);
- if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMCFMD, cm_rc);
- }
- } while (cm_rc == CM_OK);
-
-
- /* destroy the object we created with cpicerr_new() */
- cpicerr_destroy(cpicerr);
-
- do_exit(EXIT_SUCCESS);
- }
-
- #ifdef WIN32
- /*****************************************************************************/
- /* The following code makes this TP invokable as an NT service. There are 3 */
- /* routines. */
- /* */
- /* 1. main. This is the entry point for the process, it sets up a service */
- /* table entry and then calls StartServiceCtrlDispatcher. This call */
- /* doesn't return, but uses the thread which called it as a */
- /* control dispatcher for all the services implemented by this */
- /* process (in this case, just the TP itself). */
- /* */
- /* 2. ServiceMain. This is the main entry point for the service itself, the */
- /* service control dispatcher creates a thread to start at this */
- /* routine. It must register a service control handler for the */
- /* service which will be called by the control dispatcher when it */
- /* has control instructions for the service. It then informs the */
- /* service control manager that the service is running and finally */
- /* calls the start of the TP itself. This routine should not return */
- /* until the service is ready to die. */
- /* */
- /* 3. ControlHandler. This routine is called by the control dispatcher when */
- /* it has instructions for the service. We do not respond to any */
- /* of the instructions as this service should be transitory and not */
- /* actually run for more than a few seconds so we don't need to do */
- /* anything with the STOP or SHUTDOWN requests. */
- /* Note that we MUST call SetServiceStatus, even if the status */
- /* hasn't changed. */
- /*****************************************************************************/
-
- void __cdecl main( DWORD argc, LPSTR * argv);
- void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs);
- VOID WINAPI ControlHandler(DWORD dwControl);
- SERVICE_STATUS_HANDLE stat_hand;
- SERVICE_STATUS servstat;
-
- void __cdecl main( DWORD argc, LPSTR * argv)
- {
- SERVICE_TABLE_ENTRY stab[2];
-
- /***************************************************************************/
- /* Start the control dispatcher. This call gives the SCManager this */
- /* thread for the entire period that this service is running, so that it */
- /* can call us back with service controls. It will spawn a new thread to */
- /* run the service itself, starting at entrypoint ServiceMain. */
- /***************************************************************************/
- stab[0].lpServiceName = "APINGD\0";
- stab[0].lpServiceProc = ServiceMain;
-
- stab[1].lpServiceName = NULL;
- stab[1].lpServiceProc = NULL;
-
- StartServiceCtrlDispatcher(stab);
-
- }
-
-
- /*****************************************************************************/
- /* This routine is the entry-point for the service itself the service */
- /* control dispatcher creates a thread to start here when we issue */
- /* StartServiceControlDispatcher. */
- /* */
- /* Inputs: number of arguments to services, array of strings. */
- /* */
- /* Outputs: none */
- /* */
- /*****************************************************************************/
- void WINAPI ServiceMain(DWORD dwNumServiceArgs, LPTSTR * lpServiceArgs)
- {
-
- DWORD rc;
-
- stat_hand = RegisterServiceCtrlHandler("APINGD\0", ControlHandler);
- if (stat_hand == (SERVICE_STATUS_HANDLE)NULL)
- {
- rc = GetLastError();
- DebugBreak();
- }
-
- /***************************************************************************/
- /* Let the SCManager know that we are running. */
- /***************************************************************************/
- servstat.dwServiceType = SERVICE_WIN32;
- servstat.dwCurrentState = SERVICE_RUNNING;
- servstat.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- servstat.dwWin32ExitCode = NO_ERROR;
- servstat.dwServiceSpecificExitCode = NO_ERROR;
- servstat.dwCheckPoint = 0;
- servstat.dwWaitHint = 0;
-
- rc = SetServiceStatus(stat_hand, &servstat);
- if (!rc)
- {
- rc = GetLastError();
- DebugBreak();
- }
-
- TPStart(dwNumServiceArgs, lpServiceArgs);
-
- }
-
- /*****************************************************************************/
- /* This routine is the callback from the SCManager to handle specific */
- /* service control requests. It MUST call SetServiceStatus before it */
- /* returns, regardless of whether the status has changed. */
- /* */
- /* Inputs: service control requested */
- /* */
- /* Outputs: none */
- /* */
- /*****************************************************************************/
- VOID WINAPI ControlHandler(DWORD dwControl)
- {
- DWORD rc;
-
- switch (dwControl)
- {
- case SERVICE_CONTROL_STOP :
- servstat.dwCurrentState = SERVICE_STOP_PENDING;
- servstat.dwWaitHint = 24000;
- break;
-
- case SERVICE_CONTROL_PAUSE :
- case SERVICE_CONTROL_CONTINUE :
- case SERVICE_CONTROL_INTERROGATE :
- servstat.dwWaitHint = 0;
- break;
-
- case SERVICE_CONTROL_SHUTDOWN:
- servstat.dwCurrentState = SERVICE_STOP_PENDING;
- servstat.dwWaitHint = 10000;
- break;
- }
-
- rc=SetServiceStatus(stat_hand, &servstat);
- if (!rc)
- {
- rc=GetLastError();
- }
-
- }
-
- #endif