SENDRECV.C

/* sendrecv.c */ 
/* (C) COPYRIGHT DATA CONNECTION LIMITED 1993 */

/*****************************************************************************/
/* Change History */
/* */
/* 04/05/93 NGR Created. */
/* TPED 26/05/93 SW RECVTP must issue TP_ENDED after each conversation */
/* PERF 24/06/93 SW Don't regenerate data for each SEND verb */
/* FILE 02/07/93 NGR Don't attempt to close NULL file handle */
/* PATH 10/08/93 NGR Gord's changes to get config from current directory */
/*****************************************************************************/

/*****************************************************************************/
/* */
/* ROUTINE : SENDRECV */
/* */
/* FUNCTION: This file contains the main routines for a simple bulk data */
/* sending and receiving TPs SENDTP and RECVTP */
/* */
/* INPUTS : SENDTP.CFG (file) (documented below) */
/* RECVTP.CFG (file) (documented below) */
/* */
/* OUTPUTS : SENDTP.OUT */
/* RECVTP.OUT */
/* */
/*****************************************************************************/

/*****************************************************************************/
/* Operation: */
/* */
/* SENDTP */
/* DOS and OS/2. Simple command line TP which simply allocates, does the */
/* specified number of send_data and then deallocates. Done via a while loop */
/* which makes calls to IssueNextVerb. */
/* */
/* RECVTP */
/* As SENDTP, but it receive_allocates, then receive_and_waits until it gets */
/* deallocated. Repeat this NumConversation times. */
/* */
/* NT and Win16. Simple windows apps which use the async verbs and control */
/* operation via the window proc of a minimised window. This proc makes */
/* calls to IssueNextVerb on receipt of an async_complete message */
/* */
/* IssueNextVerb uses the opcode of the verb which just completed to */
/* decide what to issue next, and calls the appropriate do_ routine to fill */
/* in the vcb, it then calls the appropriate APPC entry point. */
/* */
/* Send TP will initially issue a SEND_CONVERSATION verb in order to send */
/* the number of conversations to be done to the Recv TP which expect this */
/* to be sent to it. */
/* */
/* The applications will terminate if they encounter an error and do not */
/* produce diagnostic output so the APPC API trace is the best place to look */
/*****************************************************************************/

/*****************************************************************************/
/* Configuration files: */
/* */
/* Configuration file is C:\SENDTP.CFG or RECVTP.CFG which contains */
/* the following, one per line in any order. If not present then the given */
/* default is assumed. */
/* */
/* ResultFile = <Name of file for results, default C:\(SEND/RECV)TP.OUT> */
/* LocalTPName = <Name to be used for TP started, default SENDTP/RECVTP> */
/* */
/* The following only apply to SENDTP */
/* */
/* NumConversations = <Number of conversations to be done, default = 1> */
/* LocalLUAlias = <Alias for local LU (!), default SENDLU> */
/* RemoteLUAlias = <Alias for remote LU (!!), default RECVLU> */
/* ModeName = <!?! default #INTER> */
/* RemoteTPName = <name of the TP, default RECVTP> */
/* NumSends = <number of SEND_DATA verbs per conversation, default = 2> */
/* ConfirmEvery = <number of SEND_DATA verbs between CONFIRMs, default = 1> */
/* SendSize = <number of bytes per SEND_DATA, default = 1024> */
/* SendConversation = <use the SEND_CONVERSATION verb, default = no> */
/* */
/* Note that if SendConversation is used then NumSends is irrelevant, the TP */
/* will simply do NumConversations SEND_CONVERSATION verbs */
/* If NumConversations is zero, then the TPs will do an infinite number of */
/* conversations. */
/* If NumSends is zero, then SENDTP will never DEALLOCATE the first */
/* conversation. */
/* If ConfirmEvery is zero, then SENDTP will not issue CONFIRM verbs. */
/*****************************************************************************/
#if (defined(WINDOWS)||defined(WIN32))
#include <windows.h>
HINSTANCE hInst;
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winappc.h>
#include <wincsv.h>
#include "sendrecv.h"

#if defined(DOS5) || defined(DOS)
#define SYNC
#endif

#ifdef WINDOWS
#define memset(x,y,z) _fmemset(x,y,z)
#define memchr(x,y,z) _fmemchr(x,y,z)
#define strupr(x) _fstrupr(x)
#define strcmpi(x,y) _fstricmp(x,y)
#define strncpy(x,y,z) _fstrncpy(x,y,z)
#endif

#ifdef SYNC
/*****************************************************************************/
/* main - reads initialisation info and creates threads */
/* DOS & OS\2 version */
/*****************************************************************************/
void main( int argc, char FAR * argv[])
{

#if defined(WIN32) || defined(WINDOWS)
WAPPCDATA APPCData;
WNDCLASS class;
#define WinAPPCVERSION 0x0001

/**************************************************************************/
/* Startup WinAPPC */
/**************************************************************************/
if (WinAPPCStartup(WinAPPCVERSION,&APPCData))
{
return (FALSE);
}
#endif

printf("\n\n\n\n\n\n\n");
#ifdef SENDTP
printf("SENDTP - APPC Bulk data send program to be used with RECVTP\n");
#else
printf("RECVTP - APPC Bulk data recv program to be used with SENDTP\n");
#endif
printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\n");


InitialiseMain();
ReadConfig();

while (!TPDead)
{
IssueNextVerb();
}
#ifdef SENDTP
OutputResults();
#endif

#if defined(WIN32) || defined(WINDOWS)
WinAPPCCleanup();
#endif

printf("Finished");

}
#else
/*****************************************************************************/
/* WinMain - reads initialisation info and controls message loop */
/* NT and Win16 version */
/*****************************************************************************/
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{

MSG msg;

hInst = hInstance;

InitialiseMain();

if (!InitialiseWinMain(hInstance))
{
return (FALSE);
}

ReadConfig();

while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return msg.wParam; /* save exit parameter for return */

}

/*****************************************************************************/
/* InitialiseWinMain - does the windows bits of initialisation */
/*****************************************************************************/
BOOL InitialiseWinMain(HINSTANCE hInstance)
{
WAPPCDATA APPCData;
WNDCLASS class;
#define WinAPPCVERSION 0x0001

/**************************************************************************/
/* Startup WinAPPC */
/**************************************************************************/
if (WinAPPCStartup(WinAPPCVERSION,&APPCData))
{
return (FALSE);
}

if ( (ASYNC_COMPLETE =
RegisterWindowMessage(WIN_APPC_ASYNC_COMPLETE_MESSAGE)) == 0 )
{
return (0);
}

async_corr=0;

/**************************************************************************/
/* Register Window Class for our icon */
/**************************************************************************/

class.style = 0;
class.lpfnWndProc = (WNDPROC)TPWndProc;
class.cbClsExtra = (DWORD)0;
class.cbWndExtra = (DWORD)0;
class.hInstance = hInstance;
class.hIcon = LoadIcon(hInstance,"MainIcon");
class.hCursor = LoadCursor(NULL, IDC_ARROW);
class.hbrBackground = GetStockObject(WHITE_BRUSH);
class.lpszMenuName = (LPSTR) NULL;
class.lpszClassName = (LPSTR) "SENDRECV\0";

if (!RegisterClass(&class))
{
return (FALSE);
}

/**************************************************************************/
/* Create the window */
/**************************************************************************/
#ifdef SENDTP
sprintf(title,"APPC Send TP\0");
#else
sprintf(title,"APPC Receive TP\0");
#endif

if ((hWndMain = CreateWindow("SENDRECV\0", /* window class */
title, /* window name */
WS_MINIMIZE|WS_OVERLAPPEDWINDOW, /* window style */
0, /* x position */
0, /* y position */
10, /* width */
10, /* height */
NULL, /* parent handle */
NULL, /* menu or child ID */
hInstance, /* instance */
NULL)) /* additional info */
== NULL)
{
return (FALSE);
}

ShowWindow(hWndMain, SW_MINIMIZE);

return(TRUE);

}

/*****************************************************************************/
/* Window proc for the iconised window */
/*****************************************************************************/
LONG FAR PASCAL TPWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
if (message == ASYNC_COMPLETE)
{
if (wParam != (WPARAM) async_corr)
{
/*****************************************************************/
/* This is not the correlator we were expecting, so we must die. */
/*****************************************************************/
TPDead = TRUE;
#ifdef WIN32
DebugBreak();
#endif
}
else
{
#ifdef SENDTP
IssueNextVerb();
#else
if (!GotNumConv)
{
/*****************************************************************/
/* We are still in the process of getting the number of convs to */
/* be done, so do the next stage of this. Note if all is not OK */
/* then we just die. */
/*****************************************************************/
Get_Run_Details();
if (TPDead)
{
PostMessage(hWndMain, WM_CLOSE, 0, 0);
}
}
else
{
IssueNextVerb();
}
#endif
}
}
else
{
switch (message)
{
case WM_CREATE:
/*****************************************************************/
/* Post a message to ourselves to kick off the first verb */
/*****************************************************************/
vcb.hdr.opcode = 0x0000;
async_corr = 0;
PostMessage(hWnd, ASYNC_COMPLETE, (WPARAM)async_corr,
(LPARAM)(char FAR *)(vcbptr));
break;

case WM_QUERYOPEN:
/*****************************************************************/
/* Prevent the window being opened */
/*****************************************************************/
break;

case WM_CLOSE:
TPDead = TRUE;
WinAPPCCleanup();
#ifdef SENDTP
OutputResults();
#endif
return DefWindowProc(hWnd, message, wParam, lParam);
break;

case WM_DESTROY:
if( DataPtr != NULL )
{
#ifdef WINDOWS
GlobalUnlock(LOWORD(GlobalHandle(SELECTOROF(DataPtr))));
GlobalFree(LOWORD(GlobalHandle(SELECTOROF(DataPtr))));
#else
#ifdef WIN32
free(DataPtr);
#else
DosFreeSeg(selector);
#endif
#endif
}
PostQuitMessage(0);
break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
}
return 0l;
}

#endif

/*****************************************************************************/
/* InitialiseMain - blanks out variables. */
/*****************************************************************************/
void InitialiseMain()
{
NumConversations=0;
FirstConv=TRUE;
memset(LocalTPName,0,64);
ConvCount=0;
Convid=0;
SendSize=0;
memset(TPid,0,8);
TPDead=FALSE;
vcbptr=(char *)&vcb;
cnvtptr=(char *)&cnvt;

#ifdef SENDTP
NumSends=0;
SendConversation=0;
ConfirmEvery=0;
SendCount=0;
ConfirmCount=0;
datach='A';

memset(LocalLUAlias,0,8);
memset(RemoteLUAlias,0,8);
memset(ModeName,0,8);
memset(RemoteTPName,0,64);
#else
GotNumConv = FALSE;
GetStage = 0;
#endif


}

/*****************************************************************************/
/* IssueNextVerb - looks at the verb which has just completed and does the */
/* next one */
/*****************************************************************************/
void IssueNextVerb()
{
if (vcb.hdr.opcode != 0x0000)
{
ProcessReturns();
}
if (!TPDead)
{
switch (vcb.hdr.opcode)
{
case 0x0000:
#ifdef SENDTP
Build_TP_STARTED();

/**************************************************************/
/*PERF* Don't re-generate data each time we issue a send! */
/**************************************************************/
GenerateData();

#else
Build_RECEIVE_ALLOCATE();
#endif
break;

#ifdef SENDTP
case AP_TP_STARTED:
if (ConvCount == 0)
{
Send_Run_Details();
}
if (!TPDead)
{
NewConversation();
if (SendConversation)
{
Build_MC_SEND_CONVERSATION();
}
else
{
Build_MC_ALLOCATE();
}
}
break;

case AP_M_ALLOCATE:
Build_MC_SEND_DATA();
break;

case AP_M_SEND_DATA:
SendCount++;
ConfirmCount++;
if ((NumSends != 0) && (SendCount == NumSends))
{
Build_MC_DEALLOCATE();
}
else if ((ConfirmEvery != 0) && (ConfirmCount == ConfirmEvery))
{
Build_MC_CONFIRM();
}
else
{
Build_MC_SEND_DATA();
}
break;

case AP_M_SEND_CONVERSATION:
if ((NumConversations != 0) && (ConvCount == NumConversations))
{
NewConversation();
Build_TP_ENDED();
}
else
{
NewConversation();
Build_MC_SEND_CONVERSATION();
}
break;

case AP_M_CONFIRM:
ConfirmCount=0;
Build_MC_SEND_DATA();
break;

case AP_M_DEALLOCATE:
if ((NumConversations !=0) && (ConvCount == NumConversations))
{
NewConversation();
Build_TP_ENDED();
}
else
{
NewConversation();
Build_MC_ALLOCATE();
}
break;

case AP_TP_ENDED:
/**************************************************************/
/*TPED* Quit out and die if SENDTP */
/**************************************************************/
TPDead = TRUE;
break;
#else
case AP_RECEIVE_ALLOCATE:
NewConversation();
Build_MC_RECEIVE_AND_WAIT();
break;

case AP_M_RECEIVE_AND_WAIT:
if ((vcb.rcvwait.primary_rc == AP_DEALLOC_NORMAL))
{
/*************************************************************/
/*TPED* Issue TP_ENDED every time conversation deallocated */
/*************************************************************/
Build_TP_ENDED();
}
else if ((vcb.rcvwait.what_rcvd == AP_CONFIRM_WHAT_RECEIVED) ||
(vcb.rcvwait.what_rcvd == AP_DATA_COMPLETE_CONFIRM))
{
Build_MC_CONFIRMED();
Deallocated = FALSE;
}
else if ((vcb.rcvwait.what_rcvd == AP_CONFIRM_DEALLOCATE) ||
(vcb.rcvwait.what_rcvd == AP_DATA_COMPLETE_CONFIRM_DEALL))
{
Build_MC_CONFIRMED();
Deallocated = TRUE;
}
else
{
Build_MC_RECEIVE_AND_WAIT();
}
break;

case AP_M_CONFIRMED:
if (Deallocated)
{
/*************************************************************/
/*TPED* Issue TP_ENDED every time conversation deallocated */
/*************************************************************/
Build_TP_ENDED();
}
else
{
Build_MC_RECEIVE_AND_WAIT();
}
break;

case AP_TP_ENDED:
/**************************************************************/
/*TPED* If not completed all conversations, issue RCV_ALLOC */
/**************************************************************/
if ((NumConversations != 0) && (ConvCount < NumConversations))
{
Build_RECEIVE_ALLOCATE();
}
else
{
TPDead = TRUE;
}
break;
#endif

default:
/*****************************************************************/
/* What is this verb then ?? */
/*****************************************************************/
TPDead = TRUE;
#ifdef WIN32
DebugBreak();
#endif
break;

} /* Op-code switch */

} /* TPDead after previous verb */

/**************************************************************************/
/* Now go ahead and issue the verb, if we're not dead. */
/**************************************************************************/
if (!TPDead)
{
#ifdef SYNC
APPC((long)(vcbptr));
#else
async_corr=WinAsyncAPPC(hWndMain, (long)(char FAR *)(vcbptr));
#endif
}
#ifndef SYNC
else
{
PostMessage(hWndMain, WM_CLOSE, 0, 0);
}
#endif
} /* Issue next verb */

#ifdef SENDTP
void Build_TP_STARTED()
{
CLEARVCB

vcb.tpstart.opcode = AP_TP_STARTED;
memcpy(&(vcb.tpstart.lu_alias), LocalLUAlias, 8);
memcpy(&(vcb.tpstart.tp_name), LocalTPName, 64);

}

void Build_MC_ALLOCATE()
{
CLEARVCB

vcb.allocate.opcode = AP_M_ALLOCATE;
vcb.allocate.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.allocate.tp_id),TPid, 8);
vcb.allocate.sync_level = AP_CONFIRM_SYNC_LEVEL;
vcb.allocate.rtn_ctl = AP_WHEN_SESSION_ALLOCATED;
memcpy(&(vcb.allocate.plu_alias), RemoteLUAlias, 8);
memcpy(&(vcb.allocate.mode_name), ModeName, 8);
memcpy(&(vcb.allocate.tp_name), RemoteTPName, 64);
vcb.allocate.security = AP_NONE;

}

void Build_MC_DEALLOCATE()
{
CLEARVCB

vcb.deallocate.opcode = AP_M_DEALLOCATE;
vcb.deallocate.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.deallocate.tp_id), TPid, 8);
vcb.deallocate.conv_id = Convid;
if (ConfirmEvery == 0)
{
vcb.deallocate.dealloc_type = AP_FLUSH;
}
else
{
vcb.deallocate.dealloc_type = AP_SYNC_LEVEL;
}

}

void Build_MC_SEND_DATA()
{
CLEARVCB

// PERF - GenerateData();

vcb.snddata.opcode = AP_M_SEND_DATA;
vcb.snddata.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.snddata.tp_id), TPid, 8);
vcb.snddata.conv_id = Convid;
vcb.snddata.dlen = SendSize;
vcb.snddata.dptr = DataPtr;
vcb.snddata.type = AP_NONE;
}

void Build_MC_SEND_CONVERSATION()
{
CLEARVCB

// PERF - GenerateData();

vcb.sndconv.opcode = AP_M_SEND_CONVERSATION;
vcb.sndconv.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.sndconv.tp_id), TPid, 8);
vcb.sndconv.rtn_ctl = AP_WHEN_SESSION_ALLOCATED;
memcpy(&(vcb.sndconv.plu_alias), RemoteLUAlias, 8);
memcpy(&(vcb.sndconv.mode_name), ModeName, 8);
memcpy(&(vcb.sndconv.tp_name), RemoteTPName, 64);
vcb.sndconv.security = AP_NONE;
vcb.sndconv.dlen = SendSize;
vcb.sndconv.dptr = DataPtr;
}

void Build_MC_CONFIRM()
{
CLEARVCB

vcb.confirm.opcode = AP_M_CONFIRM;
vcb.confirm.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.confirm.tp_id), TPid, 8);
vcb.confirm.conv_id = Convid;
}
#else

void Build_RECEIVE_ALLOCATE()
{
CLEARVCB

vcb.rcvalloc.opcode = AP_RECEIVE_ALLOCATE;
memcpy(&(vcb.rcvalloc.tp_name), LocalTPName, 64);
}

void Build_MC_RECEIVE_AND_WAIT()
{
CLEARVCB

vcb.rcvwait.opcode = AP_M_RECEIVE_AND_WAIT;
vcb.rcvwait.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.rcvwait.tp_id),TPid,8);
vcb.rcvwait.conv_id = Convid;
vcb.rcvwait.rtn_status = AP_YES;
vcb.rcvwait.max_len = 0xFFFF;
vcb.rcvwait.dptr = DataPtr;
}

void Build_MC_CONFIRMED()
{
CLEARVCB

vcb.confirmed.opcode = AP_M_CONFIRMED;
vcb.confirmed.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.confirmed.tp_id),TPid,8);
vcb.confirmed.conv_id = Convid;
}
#endif

void Build_TP_ENDED()
{
CLEARVCB

vcb.tpend.opcode = AP_TP_ENDED;
memcpy(&(vcb.tpend.tp_id), TPid, 8);
vcb.tpend.type = AP_SOFT;
}

#ifdef SENDTP
void Send_Run_Details()
{
/**************************************************************************/
/* Issues a Send_Conversation verb to send the number of conversations to */
/* be done to the other side. */
/**************************************************************************/
CLEARVCB

vcb.sndconv.opcode = AP_M_SEND_CONVERSATION;
vcb.sndconv.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.sndconv.tp_id), TPid, 8);
vcb.sndconv.rtn_ctl = AP_WHEN_SESSION_ALLOCATED;
memcpy(&(vcb.sndconv.plu_alias), RemoteLUAlias, 8);
memcpy(&(vcb.sndconv.mode_name), ModeName, 8);
memcpy(&(vcb.sndconv.tp_name), RemoteTPName, 64);
vcb.sndconv.security = AP_NONE;
vcb.sndconv.dlen = sizeof(unsigned short);
vcb.sndconv.dptr = DataPtr;
#ifdef WIN32
*((unsigned short UNALIGNED *) DataPtr) = NumConversations;
#else
*((unsigned short far *)DataPtr) = NumConversations;
#endif

APPC((long)(vcbptr));
if (vcb.sndconv.primary_rc != AP_OK)
{
TPDead = TRUE;
}
}
#else
void Get_Run_Details()
{
/**************************************************************************/
/* Issues a Receive_Allocate and Receive_and_wait verb to get the number */
/* of conversations to be done. */
/* Returns true if this was successful, false otherwise. */
/**************************************************************************/
switch (GetStage)
{
case 0:

CLEARVCB
vcb.rcvalloc.opcode = AP_RECEIVE_ALLOCATE;
memcpy(&(vcb.rcvalloc.tp_name), LocalTPName, 64);
async_corr=WinAsyncAPPC(hWndMain, (long)(char FAR *)(vcbptr));
GetStage = 1;
break;

case 1:

if (vcb.rcvalloc.primary_rc != AP_OK)
{
TPDead = TRUE;
}
else
{
memcpy(TPid,&(vcb.rcvalloc.tp_id),8);
Convid = vcb.rcvalloc.conv_id;
CLEARVCB
vcb.rcvwait.opcode = AP_M_RECEIVE_AND_WAIT;
vcb.rcvwait.opext = AP_MAPPED_CONVERSATION;
memcpy(&(vcb.rcvwait.tp_id),TPid,8);
vcb.rcvwait.conv_id = Convid;
vcb.rcvwait.rtn_status = AP_YES;
vcb.rcvwait.max_len = sizeof(unsigned short);
vcb.rcvwait.dptr = DataPtr;
async_corr=WinAsyncAPPC(hWndMain, (long)(char FAR *)(vcbptr));
GetStage = 2;
}
break;

case 2:

if (vcb.rcvwait.primary_rc != AP_DEALLOC_NORMAL)
{
TPDead = TRUE;
}
else
{
#ifdef WIN32
NumConversations = *((unsigned short UNALIGNED *)DataPtr);
#else
NumConversations = *((unsigned short far *)DataPtr);
#endif
CLEARVCB
vcb.tpend.opcode = AP_TP_ENDED;
memcpy(&(vcb.tpend.tp_id), TPid, 8);
vcb.tpend.type = AP_SOFT;
async_corr=WinAsyncAPPC(hWndMain, (long)(char FAR *)(vcbptr));
GetStage = 3;
}
break;

case 3:

if (vcb.tpend.primary_rc != AP_OK)
{
TPDead = TRUE;
}
else
{
GotNumConv = TRUE;
vcb.hdr.opcode = 0x0000;
async_corr = 0;
PostMessage(hWndMain, ASYNC_COMPLETE, (WPARAM)async_corr,
(LPARAM)(char FAR *)(vcbptr));
}
break;
}
}
#endif


/*****************************************************************************/
/* ProcessReturns - Checks return codes from the last verb to complete and */
/* saves off any useful information. If the return code is */
/* bad then we just die. */
/*****************************************************************************/

void ProcessReturns() 
{
if ( ( vcb.hdr.primary_rc != AP_OK) &&
!( (vcb.hdr.opcode == AP_M_RECEIVE_AND_WAIT)&&
(vcb.hdr.primary_rc == AP_DEALLOC_NORMAL) ) )
{
TPDead = TRUE;
}
else
{
switch (vcb.hdr.opcode)
{
case AP_TP_ENDED:
break;
#ifdef SENDTP
case AP_TP_STARTED:
memcpy(TPid,&(vcb.tpstart.tp_id),8);
break;

case AP_M_SEND_CONVERSATION:
break;

case AP_M_ALLOCATE:
Convid = vcb.allocate.conv_id;
break;

case AP_M_SEND_DATA:
break;

case AP_M_DEALLOCATE:
Convid = 0;
break;

case AP_M_CONFIRM:
break;
#else
case AP_RECEIVE_ALLOCATE:
memcpy(TPid,&(vcb.rcvalloc.tp_id),8);
Convid = vcb.rcvalloc.conv_id;
break;

case AP_M_RECEIVE_AND_WAIT:
break;

case AP_M_CONFIRMED:
break;
#endif
default:
TPDead = TRUE;
#ifdef WIN32
DebugBreak();
#endif
break;
}
}
}

/*****************************************************************************/
/* ReadConfig - Reads config info from SENDTP.CFG also allocates buffer for */
/* sending */
/*****************************************************************************/
void ReadConfig()
{
#ifdef SENDTP
char buffer[200];
#endif
#ifdef DOS5
unsigned short selector;
#endif

SendSize = 0xFFFF;

if (!ReadString("LocalTPName",LocalTPName,64))
{
#ifdef SENDTP
strncpy(LocalTPName,"SENDTP",6);
#else
strncpy(LocalTPName,"RECVTP",6);
#endif
}
PadString(LocalTPName,64);
CONV_A_TO_E(LocalTPName,64);

#ifdef SENDTP
if (!ReadString("ResultFile",FileName,60))
{
strcpy(FileName,"C:\\SENDTP.OUT");
}
NumConversations=1;
if (ReadString("NumConversations",buffer,200))
{
NumConversations=atoi(buffer);
}
if (!ReadString("LocalLUAlias",LocalLUAlias,8))
{
strncpy(LocalLUAlias,"SENDLU",8);
}
PadString(LocalLUAlias,8);
if (!ReadString("RemoteLUAlias",RemoteLUAlias,8))
{
strncpy(RemoteLUAlias,"RECVLU",8);
}
PadString(RemoteLUAlias,8);
if (!ReadString("ModeName",ModeName,8))
{
strncpy(ModeName,"#INTER",8);
}
PadString(ModeName,8);
CONV_A_TO_E(ModeName,8);
if (!ReadString("RemoteTPName",RemoteTPName,64))
{
strncpy(RemoteTPName,"RECVTP",6);
}
PadString(RemoteTPName,64);
CONV_A_TO_E(RemoteTPName,64);
NumSends=2;
if (ReadString("NumSends",buffer,200))
{
NumSends=atoi(buffer);
}
ConfirmEvery=1;
if (ReadString("ConfirmEvery",buffer,200))
{
ConfirmEvery=atoi(buffer);
}
SendSize=1024;
if (ReadString("SendSize",buffer,200))
{
SendSize=atoi(buffer);
}
SendConversation=FALSE;
if (ReadString("SendConversation",buffer,200))
{
SendConversation = (*(strupr(buffer)) == 'Y');
}
#endif
#ifdef DOS5
DosAllocSeg(SendSize,&selector,1);
DataPtr = MAKEP(selector,0);
#else
#ifdef WIN32
DataPtr = malloc(SendSize);
#else
DataPtr = (char far *)GlobalLock(GlobalAlloc(GPTR,SendSize));
#endif
#endif
ResultBuf = (NumConversations == 0) ?
NULL : malloc(NumConversations * sizeof(RESULT));
ResultPtr = ResultBuf;
}

/*****************************************************************************/
/* CONV_A_TO_E - ASCII to EBCDIC conversion routine. */
/*****************************************************************************/
void CONV_A_TO_E(char FAR * string,int length)
{
memset(cnvtptr,0,sizeof(cnvt));

cnvt.opcode = SV_CONVERT;
cnvt.direction = SV_ASCII_TO_EBCDIC;
cnvt.char_set = SV_AE;

cnvt.len = length;
cnvt.source = string;
cnvt.target = string;

ACSSVC_C((long)(char far *) (cnvtptr)); /* Call ACSSVC - go convert! */
}

/*****************************************************************************/
/* CONV_E_TO_A - EBCDIC to ASCII conversion routine. */
/*****************************************************************************/
void CONV_E_TO_A(char FAR * string,int length)
{
memset(cnvtptr,0,sizeof(cnvt));

cnvt.opcode = SV_CONVERT;
cnvt.direction = SV_EBCDIC_TO_ASCII;
cnvt.char_set = SV_AE;
cnvt.len = length;
cnvt.source = string;
cnvt.target = string;

ACSSVC_C((long)(char FAR *) (cnvtptr)); /* Call ACSSVC - go convert! */
}



/*****************************************************************************/
/* NewConversation - Reset and record timers for this conversation. */
/*****************************************************************************/
void NewConversation()
{
RESULT NewTime;

#ifdef SENDTP
SendCount = 0;
ConfirmCount =0;
#endif

if (FirstConv)
{
FirstConv = FALSE;
ConvStarted = GetTickCount();
}
else if (ResultPtr != NULL)
{
*ResultPtr++ = ((NewTime = GetTickCount()) - ConvStarted);
ConvStarted = NewTime;
}
ConvCount++;
OUTPUTNUMBER
}

#ifdef SENDTP
/*****************************************************************************/
/* GenerateData - Fill in data buffer */
/*****************************************************************************/
void GenerateData()
{
int i;
int div;
int rem;
char FAR * dptr;

dptr = DataPtr;
div = SendSize / 5;
rem = SendSize % 5;

for (; div--;)
{
for (i=4; i--; *dptr++ = datach);
*dptr++ = '.';
}
for (; rem--; *dptr++ = datach);

datach = (datach=='Z' ? 'A' : datach + 1);
}

/*****************************************************************************/
/* OutputResults - dump the times of conversations to file */
/*****************************************************************************/
void OutputResults()
{
FILE *h = NULL;
RESULT FAR * ptr = NULL;
unsigned short i = 0;
RESULT TotalTime=0;

h = fopen(FileName,"w");
if (h != NULL)
{
fprintf(h,"SENDTP Results\n--------------\n\n");
CONV_E_TO_A(LocalTPName,64);
fprintf(h,"Local TP Name = %.64s\n",LocalTPName);
CONV_E_TO_A(RemoteTPName,64);
fprintf(h,"Remote TP Name = %.64s\n",RemoteTPName);
fprintf(h,"Local LU Alias = %.8s\n",LocalLUAlias);
fprintf(h,"Remote LU Alias = %.8s\n",RemoteLUAlias);
CONV_E_TO_A(ModeName,8);
fprintf(h,"ModeName = %.8s\n",ModeName);
fprintf(h,"Number of conversations = %d\n",NumConversations);
if (!SendConversation)
{
fprintf(h,"Sends per conversation = %d\n",NumSends);
fprintf(h,"Sends between confirms = %d\n",ConfirmEvery);
}
fprintf(h,"Bytes per send = %d\n",SendSize);
fprintf(h,"Use SEND_CONVERSATION = %s\n",(SendConversation ? "Yes":"No"));
fprintf(h,"\n");

ptr = ResultBuf;
while (ptr < ResultPtr)
{
TotalTime += *ptr;
fprintf(h,"Conversation number %d, time = %.3f seconds\n",i++,
(((float) *ptr++) / 1000.0 ));

}
fprintf( h,"Total Time in Conversation = %.3f seconds\n",(((float)TotalTime)/1000.0) );
fclose(h); /*FILE*/
}
}

#endif

/*****************************************************************************/
/* ReadString - Get a line of text from the config file. */
/*****************************************************************************/
int ReadString(char FAR * lpValueName,char FAR * lpData, int maxlen)
{
char buffer[200];
char *p = NULL;
FILE *h = NULL;
BOOL match = FALSE;
BOOL eof = FALSE;
int rc = 0;
int ch = 0;
int i = 0;
BOOL gotdata = FALSE;
char separators[] = " =\t\n";

#if (defined(WINDOWS)||defined(WIN32)) /*PATH*/
/*PATH*/
GetModuleFileName( hInst, buffer, sizeof(buffer) ); /*PATH*/
lstrcpy( buffer+lstrlen(buffer) - 4, ".CFG" ); /*PATH*/
h = fopen( buffer, "r" ); /*PATH*/
buffer[0] = '\0'; /*PATH*/
/*PATH*/
#else /*PATH*/
#ifdef SENDTP
h = fopen("C:\\sendtp.cfg", "r");
#else
h = fopen("C:\\recvtp.cfg", "r");
#endif
#endif /*PATH*/

lpValueName=strupr(lpValueName);

if (h != NULL)
{
while ((!match) && (!eof))
{
/********************************************************************/
/* Use fgetc to read a line of text from the file. */
/********************************************************************/
for (i=0; (i<sizeof(buffer)) &&
((ch=getc(h)) != EOF) &&
((char)ch != '\n');
i++)
{
buffer[i] = (char)ch;
}
if ((char)ch == '\n')
{
buffer[i++] = (char)ch;
}
if (ch == EOF)
{
eof = TRUE;
}
else
{
/*****************************************************************/
/* Compare the 1st token in the line read with the requested */
/* param. */
/*****************************************************************/
if (!strcmpi(strupr(strtok(buffer, separators)), lpValueName))
{
match = TRUE;
/**************************************************************/
/* Get a pointer to the 2nd token (the value we want) */
/**************************************************************/
p = strtok(NULL, separators);

/**************************************************************/
/* Copy the data IF there is some. */
/**************************************************************/
if (p != NULL)
{
/***********************************************************/
/* Force a NULL after the 2nn token */
/***********************************************************/
strtok(NULL, separators);

/***********************************************************/
/* Copy the data */
/***********************************************************/
strncpy(lpData, p, maxlen);
gotdata = TRUE;
}
else
{
gotdata = FALSE;
}
}
}
}

if (gotdata)
{
rc = 1;
}

fclose(h);

}

return(rc);
}

/*****************************************************************************/
/* PadString - Remove terminating NULL and pad on the right with spaces */
/*****************************************************************************/
void PadString(char FAR * string,int length)
{
char FAR * p;
if ((p=memchr(string,'\0',length)) != NULL)
{
while (p < string+length)
{
*p++=' ';
}
}
}