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 / msendrcv / msendrcv.c < prev    next >
Text File  |  1997-04-09  |  77KB  |  1,949 lines

  1. /* msendrcv.c */
  2. /* (C) COPYRIGHT DATA CONNECTION LIMITED 1994 */
  3.  
  4. /*****************************************************************************/
  5. /* Change History                                                            */
  6. /*                                                                           */
  7. /*       11/01/94 DK  Created                                                */
  8. /*       15/03/94 DK  Thread priorities added and signalled event goes to    */
  9. /*                    back of the list (for WaitForMultipleObjects)          */
  10. /*       14/04/94 DK  OutputResults fixed to not use global variable and     */
  11. /*                    so that output is done for received conversations only */
  12. /*****************************************************************************/
  13.  
  14. /*****************************************************************************/
  15. /* If you want internal tracing, #define SRTRC here                          */
  16. /*****************************************************************************/
  17. //#define SRTRC
  18.  
  19. /*****************************************************************************/
  20. /*                                                                           */
  21. /* ROUTINE : SEND and RECEIVE using event completion                         */
  22. /*                                                                           */
  23. /* FUNCTION: This file contains the routines for a multi-threaded routine    */
  24. /*           which uses asynchronous APPC calls with event completion        */
  25. /*           to send and receive data.                                       */
  26. /*                                                                           */
  27. /*           It requires another copy of itself on another machine to run    */
  28. /*           or it can send and receive to itself.                           */
  29. /*                                                                           */
  30. /* INPUTS  : MSENDRCV.CFG (file) (documented below)                          */
  31. /*                                                                           */
  32. /* OUTPUTS : MSENDRCV.OUT                                                    */
  33. /*           MSENDRCV.TRC                                                    */
  34. /*                                                                           */
  35. /*****************************************************************************/
  36.  
  37. /*****************************************************************************/
  38. /* Operation:                                                                */
  39. /*                                                                           */
  40. /* This is a Windows NT application which runs in a minimized window.        */
  41. /*                                                                           */
  42. /* Thread structure:                                                         */
  43. /*                                                                           */
  44. /*   A receive_allocate thread                                               */
  45. /*     This thread issues a receive_allocate and, when it completes, hands   */
  46. /*     it to a receive thread.  It then waits for the receive thread to      */
  47. /*     accept the conversation.  This thread uses event completion, but      */
  48. /*     its operation is essentially synchronous.                             */
  49. /*                                                                           */
  50. /*   A variable number of send threads                                       */
  51. /*     Each send thread processes a variable number of conversations and     */
  52. /*     issues a WaitForMultipleObjects to wait for completion of any of its  */
  53. /*     send operations.  Each conversation starts with TP_STARTED, followed  */
  54. /*     by MC_ALLOCATE and MC_CONFIRM.  Then it issues MC_SEND_DATA verbs     */
  55. /*     to send data.  MC_CONFIRMs are issued at configurable intervals.      */
  56. /*     If a confirm fails, an attempt is made to restart the conversation    */
  57. /*     after five seconds.                                                   */
  58. /*                                                                           */
  59. /*   A variable number of receive threads                                    */
  60. /*     Each receive thread processes a variable number of conversations and  */
  61. /*     issues a WaitForMultipleObjects call to wait for completion of any    */
  62. /*     one of its receive operations or for a request for a new conversation */
  63. /*     from the receive_allocate thread.  It sets a second event to tell the */
  64. /*     receive_allocate thread that it has accepted the conversation.        */
  65. /*     Each conversation issues MC_RECEIVE_AND_WAIT verbs to receive data.   */
  66. /*     If confirmation is requested, an MC_CONFIRM verb is issued.           */
  67. /*                                                                           */
  68. /*   Note:  this program is compatible with the single-threaded versions of  */
  69. /*   send and receive, which can be run for example on WIN16 clients.        */
  70. /*                                                                           */
  71. /*****************************************************************************/
  72.  
  73. /*****************************************************************************/
  74. /* Configuration file:                                                       */
  75. /*                                                                           */
  76. /* The configuration file is called MSENDRCV.CFG and must reside in the      */
  77. /* same directory as the program.  It contains the following, in any order.  */
  78. /* If any parameter is omitted, the default is assumed.                      */
  79. /*                                                                           */
  80. /* ResultFile = <Name of file for results, default MSENDRCV.OUT>             */
  81. /* TraceFile = <Name of file for tracing, default MSENDRCV.TRC>              */
  82. /* LocalTPName = <Name used for receive_allocate, default MSENDRCVTP>        */
  83. /* RemoteTPName = <Name used for allocate, default MSENDRCVTP>               */
  84. /* LocalLUAlias = <Alias for local LU, default SENDLU>                       */
  85. /* RemoteLUAlias = <Alias for remote LU, default RECVLU>                     */
  86. /* ModeName = <Mode Name, default #INTER>                                    */
  87. /*                                                                           */
  88. /* NumRcvConvs = <Number of conversations to be received, default = 4>       */
  89. /* NumRcvThreads = <Number of receive threads, default = 2>                  */
  90. /* NumSendConvs = <Number of conversations to be received, default = 4>      */
  91. /* NumSends = <number of SEND_DATA verbs per conversation, default = 8>      */
  92. /* ConfirmEvery = <number of SEND_DATA verbs between CONFIRMs, default = 2>  */
  93. /* SendSize = <number of bytes per SEND_DATA, default = 256>                 */
  94. /*                                                                           */
  95. /* The name used for TP_STARTED is fixed at MSENDRCV.                        */
  96. /*                                                                           */
  97. /* If NumRcvConvs is zero, the TP will keep issuing receive_allocates.       */
  98. /* If NumSends is zero, the TP will never DEALLOCATE a conversation.         */
  99. /* If ConfirmEvery is zero, the TP will not issue CONFIRM verbs except       */
  100. /*    after the MC_ALLOCATE.                                                 */
  101. /* If ConfirmEvery is non-zero, the TP issues a CONFIRM verbs ConfirmEvery   */
  102. /*    sends.                                                                 */
  103. /* If NumRcvConvs is non-zero and NumRcvThreads is greater than NumRcvConvs, */
  104. /*    NumRcvThreads is reduced to NumRcvConvs.                               */
  105. /* If NumRcvConvs is non-zero and NumRcvThreads*63 < NumRcvConvs,            */
  106. /*    NumRcvThreads is increased to NumRcvConvs / 63 + 1.                    */
  107. /*                                                                           */
  108. /* Configuration constants (in msendrcv.h)                                   */
  109. /*                                                                           */
  110. /* #define MAX_RECEIVE_THREADS  Max number of receive threads          (64)  */
  111. /* #define MAX_RCV_PER_THREAD   Max conversations per receive thread   (63)  */
  112. /* #define MAX_SEND_PER_THREAD  Max conversations per send thread      (64)  */
  113. /*                                                                           */
  114. /* MAX_RCV_PER_THREAD and MAX_SEND_PER_THREAD are constrained by the limit   */
  115. /* of 64 objects that can be waited for in WaitForMultipleObjects.           */
  116. /*                                                                           */
  117. /*****************************************************************************/
  118.  
  119. #include <windows.h>
  120. HINSTANCE hInst;
  121. BOOL verbs_started = FALSE;
  122. #include <stdio.h>
  123. #include <stdlib.h>
  124. #include <string.h>
  125. #include <winappc.h>
  126. #include <wincsv.h>
  127. #include "msendrcv.h"
  128.  
  129. /*****************************************************************************/
  130. /* Trace macros                                                              */
  131. /*****************************************************************************/
  132. #ifdef SRTRC
  133. #define SRTROPEN() t = fopen(TraceFile,"w");
  134. #define SRTRFLUSH() fflush(t);
  135. #define SRTRCLOSE() fclose(t);
  136. #define SRTRACE fprintf
  137. #else
  138. #define SRTROPEN()
  139. #define SRTRFLUSH()
  140. #define SRTRCLOSE()
  141. #define SRTRACE 1 ? (void) 0 : fprintf
  142. #endif
  143.  
  144. /*****************************************************************************/
  145. /* WinMain - reads initialization info and controls message loop             */
  146. /*           NT version                                                      */
  147. /*****************************************************************************/
  148. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  149.                    LPSTR lpCmdLine, int nCmdShow)
  150. {
  151.  
  152.   MSG msg;
  153.   DWORD Tid;
  154.   int i;
  155.   DWORD NumConvs;
  156.   HANDLE ThreadHandle;
  157.  
  158.   hInst = hInstance;
  159.  
  160.   InitializeMain();
  161.  
  162.   if (!InitializeWinMain(hInstance))
  163.   {
  164.     return (FALSE);
  165.   }
  166.  
  167.   ReadConfig();
  168.   SRTROPEN()
  169.  
  170.   /***************************************************************************/
  171.   /* Create two events for each receive thread                               */
  172.   /***************************************************************************/
  173.   for (i = 0; i < NumRcvThreads; i++)
  174.   {
  175.     /*************************************************************************/
  176.     /* Create an event for kicking the receive thread                        */
  177.     /*************************************************************************/
  178.     RcvThreadArray[i].convptr = NULL;
  179.     RcvThreadArray[i].event1 = CreateEvent(NULL,FALSE,FALSE,NULL);
  180.     RcvThreadArray[i].event2 = CreateEvent(NULL,FALSE,FALSE,NULL);
  181.   }
  182.  
  183.   /***************************************************************************/
  184.   /* Create receive threads                                                  */
  185.   /***************************************************************************/
  186.   for (i = 0; i < NumRcvThreads; i++)
  187.   {
  188.     SRTRACE(t,"Created event handles %p %p for receive thread %d\n",
  189.             RcvThreadArray[i].event1, RcvThreadArray[i].event2,i);
  190.  
  191.     /*************************************************************************/
  192.     /* Create the thread                                                     */
  193.     /*************************************************************************/
  194.     ThreadHandle = CreateThread(NULL,
  195.                                 16000,
  196.                                 (LPTHREAD_START_ROUTINE)ReceiveThread,
  197.                                 (void *)i,
  198.                                 0,
  199.                                 &Tid);
  200.     if (ThreadHandle == NULL)
  201.     {
  202.       GetLastError();
  203.       DebugBreak();
  204.     }
  205.     SetThreadPriority(ThreadHandle,THREAD_PRIORITY_LOWEST);
  206.     SRTRACE(t,"Created receive thread %d with priority %d\n",
  207.             i,GetThreadPriority(ThreadHandle));
  208.     CloseHandle(ThreadHandle);
  209.   }
  210.  
  211.   /***************************************************************************/
  212.   /* Create receive_allocate thread                                          */
  213.   /***************************************************************************/
  214.   if (NumRcvThreads > 0)
  215.   {
  216.     ThreadHandle = CreateThread(NULL,
  217.                                 16000,
  218.                                 (LPTHREAD_START_ROUTINE)RcvAllocThread,
  219.                                 NULL,
  220.                                 0,
  221.                                 &Tid);
  222.     if (ThreadHandle == NULL)
  223.     {
  224.       GetLastError();
  225.       DebugBreak();
  226.     }
  227.     SetThreadPriority(ThreadHandle,THREAD_PRIORITY_NORMAL);
  228.     SRTRACE(t,"Created receive allocate thread with priority %d\n",
  229.             GetThreadPriority(ThreadHandle));
  230.     CloseHandle(ThreadHandle);
  231.   }
  232.  
  233.   /***************************************************************************/
  234.   /* Create enough send threads to process conversations                     */
  235.   /***************************************************************************/
  236.   i = NumSendConvs;
  237.   while (i > 0)
  238.   {
  239.     NumConvs = (i > 64) ? 64 : i;
  240.     ThreadHandle = CreateThread(NULL,
  241.                                 16000,
  242.                                 (LPTHREAD_START_ROUTINE)SendThread,
  243.                                 (void *)NumConvs,
  244.                                 0,
  245.                                 &Tid);
  246.     if (ThreadHandle == NULL)
  247.     {
  248.       GetLastError();
  249.       DebugBreak();
  250.     }
  251.     SetThreadPriority(ThreadHandle,THREAD_PRIORITY_BELOW_NORMAL);
  252.     SRTRACE(t,"Created send thread with %d conversations and priority %d\n",
  253.             NumConvs,GetThreadPriority(ThreadHandle));
  254.     CloseHandle(ThreadHandle);
  255.     i -= NumConvs;
  256.   }
  257.  
  258.   /***************************************************************************/
  259.   /* Windows processing loop                                                 */
  260.   /***************************************************************************/
  261.   while(GetMessage(&msg,NULL,0,0))
  262.   {
  263.     TranslateMessage(&msg);
  264.     DispatchMessage(&msg);
  265.   }
  266.  
  267.   WinAPPCCleanup();
  268.   OutputResults();
  269.   SRTRFLUSH()
  270.   SRTRCLOSE()
  271.   DeleteCriticalSection(&runsem);
  272.   return msg.wParam;         /* save exit parameter for return               */
  273.  
  274. }
  275.  
  276. /*****************************************************************************/
  277. /* RcvAllocThread - separate thread for receive_allocates                    */
  278. /*****************************************************************************/
  279. DWORD WINAPI RcvAllocThread()
  280. {
  281.   /***************************************************************************/
  282.   /* Local variables                                                         */
  283.   /***************************************************************************/
  284.   CONVCB * convptr;
  285.   struct appc_hdr * vcbptr;
  286.   unsigned short ThreadNo;
  287.   unsigned short NextReceive = 0;
  288.   BOOL   RcvAllocEnded = FALSE;
  289.   DWORD rc;
  290.   SYSTEMTIME st;
  291.  
  292.   /***************************************************************************/
  293.   /* Count threads within critical section                                   */
  294.   /***************************************************************************/
  295.   EnterCriticalSection(&runsem);
  296.   ThreadCount++;
  297.   ThreadNo = ThreadCount;
  298.   LeaveCriticalSection(&runsem);
  299.  
  300.   SRTRACE(t,"Thread %d (ralc) Started\n",ThreadNo);
  301.  
  302.   /***************************************************************************/
  303.   /* Loop round until the required number of conversations have been         */
  304.   /* allocated                                                               */
  305.   /***************************************************************************/
  306.   while ((NumRcvConvs == 0) || (NumRalcs < NumRcvConvs))
  307.   {
  308.     /*************************************************************************/
  309.     /* Make a conversation control block                                     */
  310.     /*************************************************************************/
  311.     convptr = malloc (sizeof(CONVCB));
  312.     convptr->thread       = ThreadNo;
  313.     convptr->conv         = 0;
  314.     convptr->TPid[0]      = '\0';
  315.     convptr->Convid       = 0;
  316.     convptr->async_corr   = 0;
  317.     convptr->SendCount    = 0;
  318.     convptr->RcvCount     = 0;
  319.     convptr->ConfirmCount = 0;
  320.     convptr->TPEnded      = FALSE;
  321.     convptr->Deallocated  = FALSE;
  322.     convptr->DataPtr      = malloc(RcvSize);
  323.     vcbptr = (struct appc_hdr *) &convptr->vcb;
  324.     memset(vcbptr,0,sizeof(VCB));
  325.     strcpy (convptr->type,"ralc");
  326.  
  327.     /*************************************************************************/
  328.     /* Create an event                                                       */
  329.     /*************************************************************************/
  330.     convptr->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  331.     SRTRACE(t,"Thread %d (ralc) convptr %p\n",ThreadNo,convptr);
  332.     SRTRACE(t,"Thread %d (ralc) event handle %p\n",ThreadNo,convptr->hEvent);
  333.  
  334.     /*************************************************************************/
  335.     /* Build a receive_allocate                                              */
  336.     /*************************************************************************/
  337.     Build_RECEIVE_ALLOCATE (convptr);
  338.  
  339.     /*************************************************************************/
  340.     /* Issue receive_allocate using event notification                       */
  341.     /*************************************************************************/
  342.     convptr->async_corr = WinAsyncAPPCEx(convptr->hEvent,
  343.                                          (long)(char *)(vcbptr));
  344. //  SRTRACE(t,"Thread %d (ralc) Receive_Allocate issued corr %p\n",
  345. //          ThreadNo,convptr->async_corr);
  346.     SRTRFLUSH()
  347.     if (convptr->async_corr == 0)
  348.     {
  349.       SRTRACE(t,"Thread %d (ralc) WinAsync call %x failed zero corr %p\n",
  350.               ThreadNo,vcbptr->opcode,convptr->async_corr);
  351.       break;
  352.     }
  353.     else
  354.     {
  355.       /***********************************************************************/
  356.       /* Wait for event completion                                           */
  357.       /***********************************************************************/
  358.       rc = WaitForSingleObject(convptr->hEvent,INFINITE);
  359.       if (rc == WAIT_FAILED)
  360.       {
  361.         rc = GetLastError();
  362.         SRTRACE(t,"Thread %d (ralc) wait for event_1 %p failed with rc %d\n",
  363.                 ThreadNo,convptr->hEvent,rc);
  364.         break;
  365.       }
  366.       if (vcbptr->primary_rc != AP_OK)
  367.       {
  368.         SRTRACE(t,"Thread %d (ralc) WinAsync error: %s prc %4.4x src %8.8x\n",
  369.                 ThreadNo,VerbName[vcbptr->opcode],
  370.                 APPC_FLIPI(vcbptr->primary_rc),
  371.                 APPC_FLIPL(vcbptr->secondary_rc));
  372.         break;
  373.       }
  374.       else
  375.       {
  376.         NumRalcs++;
  377.         SRTRACE(t,"Thread %d (ralc) Receive_Allocate %d completed\n",
  378.                 ThreadNo,NumRalcs);
  379.  
  380.         /*********************************************************************/
  381.         /* give it to a receive thread by kicking event 1                    */
  382.         /*********************************************************************/
  383.         RcvThreadArray[NextReceive].convptr = convptr;
  384. //      SRTRACE(t,"Thread %d (ralc) convptr %p\n",ThreadNo,convptr);
  385. //      SRTRACE(t,"Thread %d (ralc) kicking receive thread %d\n",
  386. //              ThreadNo,NextReceive);
  387. //      SRTRACE(t,"Thread %d (ralc) setting event_1 %p\n",ThreadNo,
  388. //              RcvThreadArray[NextReceive].event1);
  389.         rc = SetEvent (RcvThreadArray[NextReceive].event1);
  390.         if (rc == FALSE)
  391.         {
  392.           rc = GetLastError();
  393.           SRTRACE(t,"Thread %d (ralc) setting event_1 %p failed with rc %d\n",
  394.                   ThreadNo,RcvThreadArray[NextReceive].event1,rc);
  395.           break;
  396.         }
  397.  
  398.         /*********************************************************************/
  399.         /* wait for receive thread to release event 2                        */
  400.         /*********************************************************************/
  401. //      SRTRACE(t,"Thread %d (ralc) waiting for event_2 %d\n",ThreadNo,
  402. //              RcvThreadArray[NextReceive].event2);
  403.         rc = WaitForSingleObject(RcvThreadArray[NextReceive].event2,INFINITE);
  404.         if (rc == WAIT_FAILED)
  405.         {
  406.           rc = GetLastError();
  407.           SRTRACE(t,"Thread %d (ralc) wait for event_2 %p failed with rc %d\n",
  408.                   ThreadNo,RcvThreadArray[NextReceive].event2,rc);
  409.           break;
  410.         }
  411.  
  412.         /*********************************************************************/
  413.         /* ready for next receive allocate                                   */
  414.         /*********************************************************************/
  415.         NextReceive++;
  416.         if (NextReceive == NumRcvThreads)
  417.         {
  418.           NextReceive = 0;
  419.         }
  420.       }
  421.     }
  422.   }
  423.  
  424.   /***************************************************************************/
  425.   /* Kick receive threads for last time in case they are idle                */
  426.   /* convptr is set to NULL to indicate this final kick                      */
  427.   /***************************************************************************/
  428.   SRTRACE(t,"Thread %d (ralc) last kicks\n",ThreadNo);
  429.   for (NextReceive = 0; NextReceive < NumRcvThreads; NextReceive++)
  430.   {
  431.     RcvThreadArray[NextReceive].convptr = NULL;
  432.     rc = SetEvent (RcvThreadArray[NextReceive].event1);
  433.   }
  434.  
  435.   /***************************************************************************/
  436.   /* Count threads within critical section                                   */
  437.   /***************************************************************************/
  438.   EnterCriticalSection(&runsem);
  439.   ThreadCount--;
  440.   GetLocalTime(&st);
  441.   SRTRACE(t,"Thread %d (ralc) Exit at %d:%d:%d: ThreadCount %d\n",
  442.           ThreadNo,st.wHour,st.wMinute,st.wSecond,ThreadCount);
  443.   if (ThreadCount == 0)
  444.   {
  445.     PostMessage(hWndMain, WM_CLOSE, 0, 0);
  446.   }
  447.   LeaveCriticalSection(&runsem);
  448.   return(0);
  449. }
  450.  
  451. /*****************************************************************************/
  452. /* ReceiveThread - service thread which processes multiple conversations     */
  453. /*****************************************************************************/
  454. DWORD WINAPI ReceiveThread(DWORD k)
  455. {
  456.   /***************************************************************************/
  457.   /* Separate variables for each instance of this thread                     */
  458.   /***************************************************************************/
  459.   DWORD ObjIndex;
  460.   DWORD i;
  461.   DWORD j;
  462.   DWORD rc;
  463.   unsigned short NumConvs = 0;
  464.   unsigned short RcvMax = 0;
  465.   unsigned short ThreadNo;
  466.   unsigned short RcvThreadNo;
  467.   CONVCB * ConvptrArray [MAX_RCV_PER_THREAD+2];
  468.   HANDLE EventArray [MAX_RCV_PER_THREAD+2];
  469.   SYSTEMTIME st;
  470.  
  471.   EventArray[0] = RcvThreadArray[k].event1;
  472.   ConvptrArray[0] = NULL;
  473.   for (i = 1; i < MAX_RCV_PER_THREAD+2; i++)
  474.   {
  475.     EventArray[i] = NULL;
  476.     ConvptrArray[i] = NULL;
  477.   }
  478.  
  479.   /***************************************************************************/
  480.   /* Count threads                                                           */
  481.   /***************************************************************************/
  482.   EnterCriticalSection(&runsem);
  483.   ThreadCount++;
  484.   RcvThreads++;
  485.   ThreadNo = ThreadCount;
  486.   RcvThreadNo = RcvThreads;
  487.   OUTPUTNUMBER
  488.   LeaveCriticalSection(&runsem);
  489.  
  490.   SRTRACE(t,"Thread %d (recv) Started\n",k);
  491.   SRTRACE(t,"Thread %d (recv) has event handles %p %p\n",k,
  492.           RcvThreadArray[k].event1,RcvThreadArray[k].event2);
  493.  
  494.   /***************************************************************************/
  495.   /* Loop round until finished                                               */
  496.   /***************************************************************************/
  497.   while (TRUE)
  498.   {
  499.     /*************************************************************************/
  500.     /* Wait for event completion                                             */
  501.     /*************************************************************************/
  502. //  SRTRACE(t,"Thread %d (recv) waiting for %d events to complete\n",
  503. //          k,NumConvs+1);
  504.     ObjIndex = WaitForMultipleObjects(NumConvs+1,EventArray,FALSE,INFINITE);
  505.     if (ObjIndex == WAIT_FAILED)
  506.     {
  507.       rc = GetLastError();
  508.       SRTRACE(t,"Thread %d (recv) wait for %d events failed with rc %d\n",
  509.               k,NumConvs+1,rc);
  510.       for (j = 0; j <= NumConvs; j++)
  511.       {
  512.         SRTRACE(t,"Thread %d (recv) event %d has handle %p\n",
  513.                 k,j,EventArray[j]);
  514.       }
  515.       break;
  516.     }
  517.     ObjIndex -= WAIT_OBJECT_0;
  518. //  SRTRACE(t,"Thread %d (recv) event %d has completed\n",k,ObjIndex);
  519.     if (ObjIndex == 0)
  520.     {
  521.       /***********************************************************************/
  522.       /* final kick from receive_allocate thread - terminate if idle         */
  523.       /***********************************************************************/
  524.       if (RcvThreadArray[k].convptr == NULL)
  525.       {
  526.         SRTRACE(t,"Thread %d (recv) ralc thread terminating\n",k);
  527.         SRTRACE(t,"Thread %d (recv) NumRalcs %d NumRcvConvs %d NumConvs %d\n",
  528.                 k,NumRalcs,NumRcvConvs,NumConvs);
  529.         if (NumConvs == 0)
  530.         {
  531.           break;
  532.         }
  533.         else
  534.         {
  535.           continue;
  536.         }
  537.       }
  538.       else
  539.       {
  540.         /*********************************************************************/
  541.         /* new conversation - save convptr and release rcv_alloc thread      */
  542.         /*********************************************************************/
  543.         SRTRACE(t,"Thread %d (recv) new conversation\n",k);
  544.  
  545.         /*********************************************************************/
  546.         /* select next entry in the convptr array as conversation index      */
  547.         /*********************************************************************/
  548.         NumConvs++;
  549.         i = NumConvs;
  550.  
  551.         /*********************************************************************/
  552.         /* set up convptr array                                              */
  553.         /* save service thread number and slot number in convcb for tracing  */
  554.         /* add event to event array                                          */
  555.         /*********************************************************************/
  556.         ConvptrArray[i] = RcvThreadArray[k].convptr;
  557. //      SRTRACE(t,"Thread %d:%d (recv) using convptr %p\n",k,i,ConvptrArray[i]);
  558.         ConvptrArray[i]->thread = (unsigned short)k;
  559.         ConvptrArray[i]->conv   = (unsigned short)i;
  560.         strcpy (ConvptrArray[i]->type,"recv");
  561.         EventArray[i] = ConvptrArray[i]->hEvent;
  562.         EnterCriticalSection(&runsem);
  563.         SimRcvConvs++;
  564.         OUTPUTNUMBER
  565.         SRTRACE(t,"Thread %d:%d (recv) NumConvs %d SimRcvConvs %d\n",
  566.                 k,i,NumConvs,SimRcvConvs);
  567.         LeaveCriticalSection(&runsem);
  568.  
  569.         /*********************************************************************/
  570.         /* release receive_allocate thread                                   */
  571.         /*********************************************************************/
  572. //      SRTRACE(t,"Thread %d:%d (recv) setting event_2 %p\n",
  573. //              k,i,RcvThreadArray[k].event2);
  574.         rc = SetEvent (RcvThreadArray[k].event2);
  575.         if (rc == FALSE)
  576.         {
  577.           rc = GetLastError();
  578.           SRTRACE(t,"Thread %d:%d (recv) setting event_2 %p failed with rc %d\n",
  579.                   k,i,RcvThreadArray[k].event2,rc);
  580.           break;
  581.         }
  582.       }
  583.     }
  584.     else
  585.     {
  586.       /***********************************************************************/
  587.       /* Object index locates existing conversation                          */
  588.       /***********************************************************************/
  589.       i = ObjIndex;
  590.     }
  591.  
  592.     /*************************************************************************/
  593.     /* Issue the next verb                                                   */
  594.     /*************************************************************************/
  595. //  SRTRACE(t,"Thread %d:%d (recv) issuing next verb\n",
  596. //          k,ConvptrArray[i]->conv);
  597.     ConvptrArray[i]->TPEnded = IssueRcvVerb(ConvptrArray[i]);
  598.     if (ConvptrArray[i]->TPEnded)
  599.     {
  600.       /***********************************************************************/
  601.       /* end of conversation                                                 */
  602.       /***********************************************************************/
  603.       SRTRACE(t,"Thread %d:%d (recv) conversation completed\n",
  604.               k,ConvptrArray[i]->conv);
  605.       NumConvs--;
  606.       EnterCriticalSection(&runsem);
  607.       SimRcvConvs--;
  608.       RcvConvs++;
  609.       OUTPUTNUMBER
  610.       SRTRACE(t,"Thread %d:%d (recv) NumConvs %d SimRcvConvs %d RcvConvs %d\n",
  611.               k,ConvptrArray[i]->conv,NumConvs,SimRcvConvs,RcvConvs);
  612.       SRTRACE(t,"Thread %d:%d (recv) NumRalcs %d NumRcvConvs %d NumConvs %d\n",
  613.               k,ConvptrArray[i]->conv,NumRalcs,NumRcvConvs,NumConvs);
  614.       LeaveCriticalSection(&runsem);
  615.  
  616.       /***********************************************************************/
  617.       /* free resources                                                      */
  618.       /***********************************************************************/
  619.       SRTRACE(t,"Thread %d:%d (recv) clearing entry %d\n",
  620.               k,ConvptrArray[i]->conv,i);
  621.       CloseHandle(ConvptrArray[i]->hEvent);
  622.       free (ConvptrArray[i]->DataPtr);
  623.       free (ConvptrArray[i]);
  624.       ConvptrArray[i] = NULL;
  625.       EventArray[i]   = NULL;
  626.  
  627.       /***********************************************************************/
  628.       /* if the required number of conversations have been allocated and     */
  629.       /* this thread has just finished its last conversation, end loop       */
  630.       /***********************************************************************/
  631.       if ((NumRcvConvs > 0) && (NumRalcs == NumRcvConvs) && (NumConvs == 0))
  632.       {
  633.         break;
  634.       }
  635.  
  636.       /***********************************************************************/
  637.       /* the event array cannot have holes in it, so shuffle up the          */
  638.       /* pointers and events                                                 */
  639.       /* note that this means convptr->conv no longer matches i              */
  640.       /* which is why tracing uses ConvptrArray[i]->conv                     */
  641.       /***********************************************************************/
  642.       for (j = i; j <= NumConvs; j++)
  643.       {
  644.         ConvptrArray [j] = ConvptrArray [j+1];
  645.         EventArray [j] = EventArray [j+1];
  646.       }
  647.       ConvptrArray [NumConvs+1] = NULL;
  648.       EventArray [NumConvs+1] = NULL;
  649.     }
  650.     else
  651.     {
  652.       /***********************************************************************/
  653.       /* to stop one conversation getting an unfair share of the time,       */
  654.       /* move this conversation to the end and shuffle up the pointers.      */
  655.       /* note that this means convptr->conv no longer matches i              */
  656.       /* which is why tracing uses ConvptrArray[i]->conv                     */
  657.       /***********************************************************************/
  658.       ConvptrArray [NumConvs+1] = ConvptrArray [i];
  659.       EventArray [NumConvs+1] = EventArray [i];
  660.       for (j = i; j <= NumConvs; j++)
  661.       {
  662.         ConvptrArray [j] = ConvptrArray [j+1];
  663.         EventArray [j] = EventArray [j+1];
  664.       }
  665.       ConvptrArray [NumConvs+1] = NULL;
  666.       EventArray [NumConvs+1] = NULL;
  667.     }
  668.   }
  669.  
  670.   /***************************************************************************/
  671.   /* Count threads within critical section                                   */
  672.   /***************************************************************************/
  673.   EnterCriticalSection(&runsem);
  674.   ThreadCount--;
  675.   RcvThreads--;
  676.   GetLocalTime(&st);
  677.   SRTRACE(t,"Thread %d (recv) Exit at %d:%d:%d: ThreadCount %d\n",
  678.           k,st.wHour,st.wMinute,st.wSecond,ThreadCount);
  679.   OUTPUTNUMBER
  680.   if (ThreadCount == 0)
  681.   {
  682.     PostMessage(hWndMain, WM_CLOSE, 0, 0);
  683.   }
  684.   LeaveCriticalSection(&runsem);
  685.   return(0);
  686. }
  687.  
  688. /*****************************************************************************/
  689. /* SendThread - thread which processes multiple conversations                */
  690. /*****************************************************************************/
  691. DWORD WINAPI SendThread(DWORD NumConvs)
  692. {
  693.   /***************************************************************************/
  694.   /* Separate variables for each instance of this thread                     */
  695.   /***************************************************************************/
  696.   CONVCB * convptr;
  697.   struct appc_hdr * vcbptr;
  698.   unsigned short ThreadNo;
  699.   unsigned short SendThreadNo;
  700.   DWORD ObjIndex;
  701.   DWORD i;
  702.   DWORD j;
  703.   DWORD rc;
  704.   CONVCB * ConvptrArray [MAX_SEND_PER_THREAD+1];
  705.   HANDLE EventArray [MAX_SEND_PER_THREAD+1];
  706.   SYSTEMTIME st;
  707.  
  708.   for (i = 0; i < MAX_SEND_PER_THREAD+1; i++)
  709.   {
  710.     ConvptrArray[i] = NULL;
  711.     EventArray[i] = NULL;
  712.   }
  713.  
  714.   /***************************************************************************/
  715.   /* Count threads within critical section                                   */
  716.   /***************************************************************************/
  717.   EnterCriticalSection(&runsem);
  718.   ThreadCount++;
  719.   SendThreads++;
  720.   ThreadNo = ThreadCount;
  721.   SendThreadNo = SendThreads;
  722.   OUTPUTNUMBER
  723.   LeaveCriticalSection(&runsem);
  724.  
  725.   for (i = 0; i < NumConvs; i++)
  726.   {
  727.     /*************************************************************************/
  728.     /* Make a conversation control block                                     */
  729.     /*************************************************************************/
  730.     convptr = malloc (sizeof(CONVCB));
  731.     convptr->thread       = SendThreadNo;
  732.     convptr->conv         = (unsigned short)i;
  733.     convptr->async_corr   = 0;
  734.     convptr->TPid[0]      = '\0';
  735.     convptr->Convid       = 0;
  736.     convptr->SendCount    = 0;
  737.     convptr->ConfirmCount = 0;
  738.     convptr->TPEnded      = FALSE;
  739.     convptr->Deallocated  = FALSE;
  740.     convptr->Counted      = FALSE;
  741.     convptr->SendSize     = SendSize;
  742.     convptr->DataPtr      = malloc(convptr->SendSize);
  743.     vcbptr = (struct appc_hdr *) &convptr->vcb;
  744.     memset(vcbptr,0,sizeof(VCB));
  745.     strcpy (convptr->type,"send");
  746. //  SRTRACE(t,"Thread %d:%d (send) has convptr %p\n",
  747. //          SendThreadNo,i,convptr);
  748.  
  749.     /*************************************************************************/
  750.     /* Create an event                                                       */
  751.     /*************************************************************************/
  752.     convptr->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  753.     SRTRACE(t,"Thread %d:%d (send) has event handle %p\n",
  754.             SendThreadNo,i,convptr->hEvent);
  755.  
  756.     /*************************************************************************/
  757.     /* Add to arrays                                                         */
  758.     /*************************************************************************/
  759.     ConvptrArray[i] = convptr;
  760.     EventArray[i]   = convptr->hEvent;
  761.  
  762.     /*************************************************************************/
  763.     /* Build a tp_started                                                    */
  764.     /*************************************************************************/
  765.     Build_TP_STARTED(convptr);
  766.     SRTRFLUSH()
  767.  
  768.     /*************************************************************************/
  769.     /*PERF* Don't re-generate data each time we issue a send!                */
  770.     /*************************************************************************/
  771.     GenerateData(convptr);
  772.  
  773.     /*************************************************************************/
  774.     /* Issue tp_started                                                      */
  775.     /*************************************************************************/
  776.     convptr->async_corr = WinAsyncAPPCEx(convptr->hEvent,
  777.                                          (long)(char *)(vcbptr));
  778. //  SRTRACE(t,"Thread %d:%d (send) tp_started issued corr %p\n",
  779. //          SendThreadNo,i,convptr->async_corr);
  780.     SRTRFLUSH()
  781.     if (convptr->async_corr == 0)
  782.     {
  783.       SRTRACE(t,"Thread %d:%d (send) WinAsync call %x failed corr %p\n",
  784.               SendThreadNo,i,vcbptr->opcode,convptr->async_corr);
  785.       convptr->TPEnded = TRUE;
  786.     }
  787.   }
  788.  
  789.   /***************************************************************************/
  790.   /* Loop round until finished                                               */
  791.   /***************************************************************************/
  792.   while (TRUE)
  793.   {
  794.     /*************************************************************************/
  795.     /* Wait for event completion                                             */
  796.     /*************************************************************************/
  797. //  SRTRACE(t,"Thread %d (send) waiting for %d events to complete\n",
  798. //          SendThreadNo,NumConvs);
  799.     ObjIndex = WaitForMultipleObjects(NumConvs,EventArray,FALSE,INFINITE);
  800.     if (ObjIndex == WAIT_FAILED)
  801.     {
  802.       rc = GetLastError();
  803.       SRTRACE(t,"Thread %d (send) wait for %d events failed with rc %d\n",
  804.               SendThreadNo,NumConvs,rc);
  805.       for (j = 0; j < NumConvs; j++)
  806.       {
  807.         SRTRACE(t,"Thread %d (send) event %d has handle %p\n",
  808.                 SendThreadNo,j,EventArray[j]);
  809.       }
  810.       break;
  811.     }
  812.  
  813.     /*************************************************************************/
  814.     /* Get index to conversation array                                       */
  815.     /*************************************************************************/
  816.     i = ObjIndex - WAIT_OBJECT_0;
  817. //  SRTRACE(t,"Thread %d:%d (send) event %d has completed\n",
  818. //          SendThreadNo,ConvptrArray[i]->conv,i);
  819.  
  820.     /*************************************************************************/
  821.     /* Issue the next verb                                                   */
  822.     /*************************************************************************/
  823. //  SRTRACE(t,"Thread %d:%d (send) issuing next send verb\n",
  824. //          SendThreadNo,ConvptrArray[i]->conv);
  825.     ConvptrArray[i]->TPEnded = IssueSendVerb(ConvptrArray[i]);
  826.  
  827.     if (ConvptrArray[i]->TPEnded)
  828.     {
  829.       /***********************************************************************/
  830.       /* end of conversation                                                 */
  831.       /***********************************************************************/
  832.       NumConvs--;
  833.       SRTRACE(t,"Thread %d:%d (send) conversation completed: NumConvs %d\n",
  834.               SendThreadNo,ConvptrArray[i]->conv,NumConvs);
  835.  
  836.       /***********************************************************************/
  837.       /* free resources                                                      */
  838.       /***********************************************************************/
  839.       CloseHandle(ConvptrArray[i]->hEvent);
  840.       free (ConvptrArray[i]->DataPtr);
  841.       free (ConvptrArray[i]);
  842.       ConvptrArray[i] = NULL;
  843.       EventArray[i]   = NULL;
  844.  
  845.       /***********************************************************************/
  846.       /* if all conversations have completed, end loop                       */
  847.       /***********************************************************************/
  848.       if (NumConvs == 0)
  849.       {
  850.         break;
  851.       }
  852.       /***********************************************************************/
  853.       /* the event array cannot have holes in it, so shuffle up the          */
  854.       /* pointers and events                                                 */
  855.       /* note that this means convptr->conv no longer matches i              */
  856.       /* which is why tracing uses ConvptrArray[i]->conv                     */
  857.       /***********************************************************************/
  858.       for (j = i; j < MAX_SEND_PER_THREAD - 1; j++)
  859.       {
  860.         ConvptrArray [j] = ConvptrArray [j+1];
  861.         EventArray [j] = EventArray [j+1];
  862.       }
  863.       ConvptrArray [MAX_SEND_PER_THREAD-1] = NULL;
  864.       EventArray [MAX_SEND_PER_THREAD-1] = NULL;
  865.     }
  866.     else
  867.     {
  868.       /***********************************************************************/
  869.       /* to stop one conversation getting an unfair share of the time,       */
  870.       /* move this conversation to the end and shuffle up the pointers.      */
  871.       /* note that this means convptr->conv no longer matches i              */
  872.       /* which is why tracing uses ConvptrArray[i]->conv                     */
  873.       /***********************************************************************/
  874.       ConvptrArray [NumConvs] = ConvptrArray [i];
  875.       EventArray [NumConvs] = EventArray [i];
  876.       for (j = i; j < NumConvs; j++)
  877.       {
  878.         ConvptrArray [j] = ConvptrArray [j+1];
  879.         EventArray [j] = EventArray [j+1];
  880.       }
  881.       ConvptrArray [NumConvs] = NULL;
  882.       EventArray [NumConvs] = NULL;
  883.     }
  884.   }
  885.  
  886.   /***************************************************************************/
  887.   /* Count threads within critical section                                   */
  888.   /***************************************************************************/
  889.   EnterCriticalSection(&runsem);
  890.   ThreadCount--;
  891.   SendThreads--;
  892.   GetLocalTime(&st);
  893.   SRTRACE(t,"Thread %d (send) Exit at %d:%d:%d: ThreadCount %d\n",
  894.           SendThreadNo,st.wHour,st.wMinute,st.wSecond,ThreadCount);
  895.   OUTPUTNUMBER
  896.   if (ThreadCount == 0)
  897.   {
  898.     PostMessage(hWndMain, WM_CLOSE, 0, 0);
  899.   }
  900.   LeaveCriticalSection(&runsem);
  901.   return(0);
  902. }
  903.  
  904. /*****************************************************************************/
  905. /* InitializeWinMain - does the windows bits of initialisation               */
  906. /*****************************************************************************/
  907. BOOL InitializeWinMain(HINSTANCE hInstance)
  908. {
  909.   WAPPCDATA APPCData;
  910.   WNDCLASS class;
  911.   #define WinAPPCVERSION  0x0001
  912.  
  913.   /***************************************************************************/
  914.   /* Startup WinAPPC                                                         */
  915.   /***************************************************************************/
  916.   if (WinAPPCStartup(WinAPPCVERSION,&APPCData))
  917.   {
  918.     return (FALSE);
  919.   }
  920.  
  921.   /***************************************************************************/
  922.   /* Register Window Class for our icon                                      */
  923.   /***************************************************************************/
  924.  
  925.   class.style = 0;
  926.   class.lpfnWndProc   = (WNDPROC)TPWndProc;
  927.   class.cbClsExtra    = (DWORD)0;
  928.   class.cbWndExtra    = (DWORD)0;
  929.   class.hInstance     = hInstance;
  930.   class.hIcon         = LoadIcon(hInstance,"MainIcon");
  931.   class.hCursor       = LoadCursor(NULL, IDC_ARROW);
  932.   class.hbrBackground = GetStockObject(WHITE_BRUSH);
  933.   class.lpszMenuName  = (LPSTR) NULL;
  934.   class.lpszClassName = (LPSTR) "MSENDRCV\0";
  935.  
  936.   if (!RegisterClass(&class))
  937.   {
  938.     return (FALSE);
  939.   }
  940.  
  941.   /***************************************************************************/
  942.   /* Create the window                                                       */
  943.   /***************************************************************************/
  944.   sprintf(title,"APPC Send/Receive TP\0");
  945.  
  946.   if ((hWndMain = CreateWindow("MSENDRCV\0",      /* window class            */
  947.       title,                                      /* window name             */
  948.       WS_MINIMIZE|WS_OVERLAPPEDWINDOW,            /* window style            */
  949.       0,                                          /* x position              */
  950.       0,                                          /* y position              */
  951.       10,                                         /* width                   */
  952.       10,                                         /* height                  */
  953.       NULL,                                       /* parent handle           */
  954.       NULL,                                       /* menu or child ID        */
  955.       hInstance,                                  /* instance                */
  956.       NULL))                                      /* additional info         */
  957.       == NULL)
  958.   {
  959.     return (FALSE);
  960.   }
  961.  
  962.   ShowWindow(hWndMain, SW_MINIMIZE);
  963.  
  964.   return(TRUE);
  965.  
  966. }
  967.  
  968. /*****************************************************************************/
  969. /* Window proc for the iconised window                                       */
  970. /*****************************************************************************/
  971. LONG PASCAL TPWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
  972. {
  973.   switch (message)
  974.   {
  975.     case WM_CREATE:
  976.       break;
  977.  
  978.     case WM_QUERYOPEN:
  979.       /***********************************************************************/
  980.       /* Prevent the window being opened                                     */
  981.       /***********************************************************************/
  982.       break;
  983.  
  984.     case WM_CLOSE:
  985.       return DefWindowProc(hWnd, message, wParam, lParam);
  986.       break;
  987.  
  988.     case WM_DESTROY:
  989.       PostQuitMessage(0);
  990.       break;
  991.  
  992.     default:
  993.       return DefWindowProc(hWnd, message, wParam, lParam);
  994.       break;
  995.   }
  996.   return 0l;
  997. }
  998.  
  999. /*****************************************************************************/
  1000. /* InitializeMain - blanks out variables not set in ReadConfig               */
  1001. /*****************************************************************************/
  1002. void InitializeMain()
  1003. {
  1004.   RcvThreads  = 0;
  1005.   SendThreads = 0;
  1006.   ThreadCount = 0;
  1007.   NumResults  = 0;
  1008.   cnvtptr     = (char *)&cnvt;
  1009.  
  1010.   datach      = 'A';
  1011.  
  1012.   InitializeCriticalSection(&runsem);
  1013. }
  1014.  
  1015. /*****************************************************************************/
  1016. /* IssueSendVerb - looks at the verb which has just completed and does the   */
  1017. /*                 next one                                                  */
  1018. /*****************************************************************************/
  1019. BOOL IssueSendVerb(CONVCB * convptr)
  1020. {
  1021.   BOOL TPEnded;
  1022.   struct appc_hdr * vcbptr;
  1023.  
  1024. //SRTRACE(t,"Thread %d (send) IssueSendVerb\n",convptr->thread);
  1025.   TPEnded = FALSE;
  1026.   vcbptr = (struct appc_hdr *) &convptr->vcb;
  1027.   if (vcbptr->opcode != 0x0000)
  1028.   {
  1029.     TPEnded = ProcessReturns(convptr);
  1030.   }
  1031.   if (!TPEnded)
  1032.   {
  1033.     switch (vcbptr->opcode)
  1034.     {
  1035.       case 0x0000:
  1036.         Build_TP_STARTED(convptr);
  1037.  
  1038.         /*********************************************************************/
  1039.         /*PERF* Don't re-generate data each time we issue a send!            */
  1040.         /*********************************************************************/
  1041.         GenerateData(convptr);
  1042.         break;
  1043.  
  1044.       case AP_TP_STARTED:
  1045.         Build_MC_ALLOCATE(convptr);
  1046.         break;
  1047.  
  1048.       case AP_M_ALLOCATE:
  1049.         if (vcbptr->primary_rc == AP_OK)
  1050.         {
  1051.           /*******************************************************************/
  1052.           /* confirm before the first send to find out if anyone there       */
  1053.           /*******************************************************************/
  1054.           Build_MC_CONFIRM(convptr);
  1055.         }
  1056.         else
  1057.         {
  1058.           /*******************************************************************/
  1059.           /* allocate timed out or connection is for incoming call           */
  1060.           /* if there are no conversations active, try again in 5 seconds    */
  1061.           /* otherwise retry immediately - someone must be out there         */
  1062.           /*******************************************************************/
  1063.           if (SimSendConvs == 0)
  1064.           {
  1065.             SRTRACE(t,"Thread %d:%d (send) wait 5 seconds before retry\n",
  1066.                     convptr->thread,convptr->conv);
  1067.             Sleep (5000);
  1068.           }
  1069.           SRTRACE(t,"Thread %d:%d (send) retrying\n",
  1070.                   convptr->thread,convptr->conv);
  1071.           Build_MC_ALLOCATE(convptr);
  1072.         }
  1073.         break;
  1074.  
  1075.       case AP_M_SEND_DATA:
  1076.         convptr->SendCount++;
  1077.         convptr->ConfirmCount++;
  1078.         if ((NumSends != 0) && (convptr->SendCount == NumSends))
  1079.         {
  1080.           /*******************************************************************/
  1081.           /* all sends done - deallocate                                     */
  1082.           /*******************************************************************/
  1083.           Build_MC_DEALLOCATE(convptr);
  1084.         }
  1085.         else if ((ConfirmEvery != 0) &&
  1086.                  (convptr->ConfirmCount == ConfirmEvery))
  1087.         {
  1088.           /*******************************************************************/
  1089.           /* time to confirm                                                 */
  1090.           /*******************************************************************/
  1091.           Build_MC_CONFIRM(convptr);
  1092.         }
  1093.         else
  1094.         {
  1095.           /*******************************************************************/
  1096.           /* just send more data                                             */
  1097.           /*******************************************************************/
  1098.           Build_MC_SEND_DATA(convptr);
  1099.         }
  1100.         break;
  1101.  
  1102.       case AP_M_CONFIRM:
  1103.         if (vcbptr->primary_rc == AP_OK)
  1104.         {
  1105.           if (convptr->SendCount == 0)
  1106.           {
  1107.             convptr->Counted = TRUE;
  1108.             EnterCriticalSection(&runsem);
  1109.             SimSendConvs++;
  1110.             OUTPUTNUMBER
  1111.             SRTRACE(t,"Thread %d (send) SimSendConvs %d\n",
  1112.                     convptr->thread,SimSendConvs);
  1113.             LeaveCriticalSection(&runsem);
  1114.           }
  1115.           convptr->ConfirmCount=0;
  1116.           Build_MC_SEND_DATA(convptr);
  1117.         }
  1118.         else
  1119.         {
  1120.           /*******************************************************************/
  1121.           /* if there are no conversations active, try again in 5 seconds    */
  1122.           /* otherwise retry immediately - someone must be out there         */
  1123.           /*******************************************************************/
  1124.           if (SimSendConvs == 0)
  1125.           {
  1126.             SRTRACE(t,"Thread %d:%d (send) wait 5 seconds before retry\n",
  1127.                     convptr->thread,convptr->conv);
  1128.             Sleep (5000);
  1129.           }
  1130.           SRTRACE(t,"Thread %d:%d (send) retrying\n",
  1131.                   convptr->thread,convptr->conv);
  1132.           Build_MC_ALLOCATE(convptr);
  1133.         }
  1134.         break;
  1135.  
  1136.       case AP_M_DEALLOCATE:
  1137.         Build_TP_ENDED(convptr);
  1138.         break;
  1139.  
  1140.       case AP_TP_ENDED:
  1141.         /*********************************************************************/
  1142.         /* quit                                                              */
  1143.         /*********************************************************************/
  1144.         TPEnded = TRUE;
  1145.         break;
  1146.  
  1147.       default:
  1148.         /*********************************************************************/
  1149.         /* What is this verb then ??                                         */
  1150.         /*********************************************************************/
  1151.         TPEnded = TRUE;
  1152.         DebugBreak();
  1153.         break;
  1154.  
  1155.     } /* Op-code switch */
  1156.  
  1157.   }
  1158.  
  1159.   /***************************************************************************/
  1160.   /* If send conversation has finished and was counted, count it down        */
  1161.   /***************************************************************************/
  1162.   if (TPEnded && convptr->Counted)
  1163.   {
  1164.     EnterCriticalSection(&runsem);
  1165.     SimSendConvs--;
  1166.     OUTPUTNUMBER
  1167.     SRTRACE(t,"Thread %d (send) SimSendConvs %d\n",
  1168.             convptr->thread,SimSendConvs);
  1169.     LeaveCriticalSection(&runsem);
  1170.   }
  1171.  
  1172.   /***************************************************************************/
  1173.   /* Now go ahead and issue the verb, if we're not finished                  */
  1174.   /***************************************************************************/
  1175.   if (!TPEnded)
  1176.   {
  1177.     convptr->async_corr = WinAsyncAPPCEx(convptr->hEvent,
  1178.                                          (long)(char *)(vcbptr));
  1179.     if (convptr->async_corr == 0)
  1180.       {
  1181.         SRTRACE(t,"Thread %d (send) WinAsync call %x failed corr %p\n",
  1182.                 convptr->thread,vcbptr->opcode,
  1183.                 convptr->async_corr);
  1184.         convptr->TPEnded = TRUE;
  1185.       }
  1186.   }
  1187.  
  1188.   SRTRFLUSH()
  1189.   return(TPEnded);
  1190.  
  1191. } /* Issue send verb */
  1192.  
  1193. /*****************************************************************************/
  1194. /* IssueRcvVerb - looks at the verb which has just completed and does the    */
  1195. /*                 next one                                                  */
  1196. /*****************************************************************************/
  1197. BOOL IssueRcvVerb(CONVCB * convptr)
  1198. {
  1199.   BOOL TPEnded;
  1200.   struct appc_hdr * vcbptr;
  1201.  
  1202. //SRTRACE(t,"Thread %d:%d (recv) IssueRcvVerb\n",
  1203. //        convptr->thread,convptr->conv);
  1204.   TPEnded = FALSE;
  1205.   vcbptr = (struct appc_hdr *) &convptr->vcb;
  1206.   if (vcbptr->opcode != 0x0000)
  1207.   {
  1208.     TPEnded = ProcessReturns(convptr);
  1209.   }
  1210.   if (!TPEnded)
  1211.   {
  1212.     switch (vcbptr->opcode)
  1213.     {
  1214.       case 0x0000:
  1215.         Build_RECEIVE_ALLOCATE(convptr);
  1216.         break;
  1217.  
  1218.       case AP_RECEIVE_ALLOCATE:
  1219.         StartConversation(convptr);
  1220.         Build_MC_RECEIVE_AND_WAIT(convptr);
  1221.         break;
  1222.  
  1223.       case AP_M_RECEIVE_AND_WAIT:
  1224.         if ((P_M_RAW(vcbptr)->what_rcvd == AP_DATA_COMPLETE) ||
  1225.             (P_M_RAW(vcbptr)->what_rcvd == AP_DATA_COMPLETE_CONFIRM) ||
  1226.             (P_M_RAW(vcbptr)->what_rcvd == AP_DATA_COMPLETE_CONFIRM_DEALL))
  1227.         {
  1228.           convptr->RcvCount++;
  1229.         }
  1230.         if ((P_M_RAW(vcbptr)->primary_rc == AP_DEALLOC_NORMAL))
  1231.         {
  1232.           /*******************************************************************/
  1233.           /* Issue TP_ENDED every time conversation deallocated              */
  1234.           /*******************************************************************/
  1235.           EndConversation(convptr);
  1236.           Build_TP_ENDED(convptr);
  1237.         }
  1238.         else if ((P_M_RAW(vcbptr)->what_rcvd == AP_CONFIRM_WHAT_RECEIVED) ||
  1239.                  (P_M_RAW(vcbptr)->what_rcvd == AP_DATA_COMPLETE_CONFIRM))
  1240.         {
  1241.           Build_MC_CONFIRMED(convptr);
  1242.           convptr->Deallocated = FALSE;
  1243.         }
  1244.         else if ((P_M_RAW(vcbptr)->what_rcvd == AP_CONFIRM_DEALLOCATE) ||
  1245.                  (P_M_RAW(vcbptr)->what_rcvd == AP_DATA_COMPLETE_CONFIRM_DEALL))
  1246.         {
  1247.           Build_MC_CONFIRMED(convptr);
  1248.           convptr->Deallocated = TRUE;
  1249.         }
  1250.         else
  1251.         {
  1252.           Build_MC_RECEIVE_AND_WAIT(convptr);
  1253.         }
  1254.         break;
  1255.  
  1256.       case AP_M_CONFIRMED:
  1257.         if (convptr->Deallocated)
  1258.         {
  1259.           /*******************************************************************/
  1260.           /* Issue TP_ENDED every time conversation deallocated              */
  1261.           /*******************************************************************/
  1262.           EndConversation(convptr);
  1263.           Build_TP_ENDED(convptr);
  1264.         }
  1265.         else
  1266.         {
  1267.           Build_MC_RECEIVE_AND_WAIT(convptr);
  1268.         }
  1269.         break;
  1270.  
  1271.       case AP_TP_ENDED:
  1272.         /*********************************************************************/
  1273.         /* set TPEnded                                                       */
  1274.         /*********************************************************************/
  1275.         TPEnded = TRUE;
  1276.         break;
  1277.  
  1278.       default:
  1279.         /*********************************************************************/
  1280.         /* What is this verb then ??                                         */
  1281.         /*********************************************************************/
  1282.         TPEnded = TRUE;
  1283.         DebugBreak();
  1284.         break;
  1285.  
  1286.     } /* Op-code switch */
  1287.     SRTRFLUSH()
  1288.  
  1289.   }
  1290.  
  1291.   /***************************************************************************/
  1292.   /* Now go ahead and issue the verb, if we're not finished                  */
  1293.   /***************************************************************************/
  1294.   if (!TPEnded)
  1295.   {
  1296.     convptr->async_corr = WinAsyncAPPCEx(convptr->hEvent,
  1297.                           (long)(char *)(vcbptr));
  1298.     if (convptr->async_corr == 0)
  1299.     {
  1300.       SRTRACE(t,"Thread %d:%d (recv) WinAsync call %x failed corr %p\n",
  1301.               convptr->thread,convptr->conv,
  1302.               vcbptr->opcode,convptr->async_corr);
  1303.       convptr->TPEnded = TRUE;
  1304.     }
  1305.   }
  1306.  
  1307.   SRTRFLUSH()
  1308.   return(TPEnded);
  1309.  
  1310. } /* Issue receive verb */
  1311.  
  1312. /*****************************************************************************/
  1313. /* Build routines to build all required verbs                                */
  1314. /*****************************************************************************/
  1315.  
  1316. void Build_TP_STARTED(CONVCB * convptr)
  1317. {
  1318.   TP_STARTED * vcbptr;
  1319.   SRTRACE(t,"Thread %d:%d (%s) Build_TP_Started\n",
  1320.           convptr->thread,convptr->conv,convptr->type);
  1321.   vcbptr = (TP_STARTED *) &(convptr->vcb);
  1322.  
  1323.   CLEARVCB
  1324.  
  1325.   vcbptr->opcode = AP_TP_STARTED;
  1326.   memcpy(&(vcbptr->lu_alias), LocalLUAlias, 8);
  1327.   memcpy(&(vcbptr->tp_name), TPName, 64);
  1328. }
  1329.  
  1330. void Build_TP_ENDED(CONVCB * convptr)
  1331. {
  1332.   TP_ENDED * vcbptr;
  1333.   SRTRACE(t,"Thread %d:%d (%s) Build_TP_Ended\n",
  1334.           convptr->thread,convptr->conv,convptr->type);
  1335.   vcbptr = (TP_ENDED *) &(convptr->vcb);
  1336.  
  1337.   CLEARVCB
  1338.  
  1339.   vcbptr->opcode = AP_TP_ENDED;
  1340.   memcpy(&(vcbptr->tp_id), convptr->TPid, 8);
  1341.   vcbptr->type = AP_SOFT;
  1342. }
  1343.  
  1344. void Build_RECEIVE_ALLOCATE(CONVCB * convptr)
  1345. {
  1346.   RECEIVE_ALLOCATE * vcbptr;
  1347.   SRTRACE(t,"Thread %d:%d (%s) Build_Receive_Allocate\n",
  1348.           convptr->thread,convptr->conv,convptr->type);
  1349.   vcbptr = (RECEIVE_ALLOCATE *) &(convptr->vcb);
  1350.  
  1351.   CLEARVCB
  1352.  
  1353.   vcbptr->opcode = AP_RECEIVE_ALLOCATE;
  1354.   memcpy(vcbptr->tp_name, LocalTPName, 64);
  1355. }
  1356.  
  1357. void Build_MC_ALLOCATE(CONVCB * convptr)
  1358. {
  1359.   MC_ALLOCATE * vcbptr;
  1360.   SRTRACE(t,"Thread %d:%d (%s) Build_MC_Allocate\n",
  1361.           convptr->thread,convptr->conv,convptr->type);
  1362.   vcbptr = (MC_ALLOCATE *) &(convptr->vcb);
  1363.  
  1364.   CLEARVCB
  1365.  
  1366.   vcbptr->opcode = AP_M_ALLOCATE;
  1367.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  1368.   memcpy(vcbptr->tp_id,convptr->TPid, 8);
  1369.   vcbptr->sync_level = AP_CONFIRM_SYNC_LEVEL;
  1370.   vcbptr->rtn_ctl = AP_WHEN_SESSION_ALLOCATED;
  1371.   memcpy(vcbptr->plu_alias, RemoteLUAlias, 8);
  1372.   memcpy(vcbptr->mode_name, ModeName, 8);
  1373.   memcpy(vcbptr->tp_name, RemoteTPName, 64);
  1374.   vcbptr->security = AP_NONE;
  1375. }
  1376.  
  1377. void Build_MC_CONFIRM(CONVCB * convptr)
  1378. {
  1379.   MC_CONFIRM * vcbptr;
  1380. //SRTRACE(t,"Thread %d:%d (%s) Build_MC_Confirm\n",
  1381. //        convptr->thread,convptr->conv,convptr->type);
  1382.   vcbptr = (MC_CONFIRM *) &(convptr->vcb);
  1383.  
  1384.   CLEARVCB
  1385.  
  1386.   vcbptr->opcode = AP_M_CONFIRM;
  1387.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  1388.   memcpy(vcbptr->tp_id,convptr->TPid, 8);
  1389.   vcbptr->conv_id = convptr->Convid;
  1390. }
  1391.  
  1392. void Build_MC_CONFIRMED(CONVCB * convptr)
  1393. {
  1394.   MC_CONFIRMED * vcbptr;
  1395. //SRTRACE(t,"Thread %d:%d (%s) Build_MC_Confirmed\n",
  1396. //        convptr->thread,convptr->conv,convptr->type);
  1397.   vcbptr = (MC_CONFIRMED *) &(convptr->vcb);
  1398.  
  1399.   CLEARVCB
  1400.  
  1401.   vcbptr->opcode = AP_M_CONFIRMED;
  1402.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  1403.   memcpy(&(vcbptr->tp_id),convptr->TPid, 8);
  1404.   vcbptr->conv_id = convptr->Convid;
  1405. }
  1406.  
  1407. void Build_MC_DEALLOCATE(CONVCB * convptr)
  1408. {
  1409.   MC_DEALLOCATE * vcbptr;
  1410.   SRTRACE(t,"Thread %d:%d (%s) Build_MC_Deallocate\n",
  1411.           convptr->thread,convptr->conv,convptr->type);
  1412.   vcbptr = (MC_DEALLOCATE *) &(convptr->vcb);
  1413.  
  1414.   CLEARVCB
  1415.  
  1416.   vcbptr->opcode = AP_M_DEALLOCATE;
  1417.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  1418.   memcpy(&(vcbptr->tp_id),convptr->TPid, 8);
  1419.   vcbptr->conv_id = convptr->Convid;
  1420.   if (ConfirmEvery == 0)
  1421.   {
  1422.      vcbptr->dealloc_type = AP_FLUSH;
  1423.   }
  1424.   else
  1425.   {
  1426.      vcbptr->dealloc_type = AP_SYNC_LEVEL;
  1427.   }
  1428. }
  1429.  
  1430. void Build_MC_RECEIVE_AND_WAIT(CONVCB * convptr)
  1431. {
  1432.   MC_RECEIVE_AND_WAIT * vcbptr;
  1433. //SRTRACE(t,"Thread %d:%d (%s) Build_MC_Receive_And_Wait\n",
  1434. //        convptr->thread,convptr->conv,convptr->type);
  1435.   vcbptr = (MC_RECEIVE_AND_WAIT *) &(convptr->vcb);
  1436.  
  1437.   CLEARVCB
  1438.  
  1439.   vcbptr->opcode = AP_M_RECEIVE_AND_WAIT;
  1440.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  1441.   memcpy(&(vcbptr->tp_id),convptr->TPid, 8);
  1442.   vcbptr->conv_id = convptr->Convid;
  1443.   vcbptr->rtn_status = AP_YES;
  1444.   vcbptr->max_len = RcvSize;
  1445.   vcbptr->dptr = convptr->DataPtr;
  1446. }
  1447.  
  1448. void Build_MC_SEND_DATA(CONVCB * convptr)
  1449. {
  1450.   MC_SEND_DATA * vcbptr;
  1451. //SRTRACE(t,"Thread %d:%d (%s) Build_MC_Send_Data\n",
  1452. //        convptr->thread,convptr->conv,convptr->type);
  1453.   vcbptr = (MC_SEND_DATA *) &(convptr->vcb);
  1454.  
  1455.   CLEARVCB
  1456.  
  1457.   //  PERF - GenerateData();
  1458.  
  1459.   vcbptr->opcode = AP_M_SEND_DATA;
  1460.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  1461.   memcpy(&(vcbptr->tp_id),convptr->TPid, 8);
  1462.   vcbptr->conv_id = convptr->Convid;
  1463.   vcbptr->dlen = convptr->SendSize;
  1464.   vcbptr->dptr = convptr->DataPtr;
  1465.   vcbptr->type = AP_NONE;
  1466. }
  1467.  
  1468. /*****************************************************************************/
  1469. /* ProcessReturns - Checks return codes from the last verb to complete and   */
  1470. /*                  saves conversation id and tp id in the conversation cb   */
  1471. /*****************************************************************************/
  1472. BOOL ProcessReturns(CONVCB * convptr)
  1473. {
  1474.   BOOL TPEnded = FALSE;
  1475.   struct appc_hdr * vcbptr;
  1476.   SYSTEMTIME st;
  1477.  
  1478. //SRTRACE(t,"Thread %d:%d (%s) ProcessReturns\n",
  1479. //        convptr->thread,convptr->conv,convptr->type);
  1480.   vcbptr = (struct appc_hdr *) &(convptr->vcb);
  1481.  
  1482.   GetLocalTime(&st);
  1483.   if (vcbptr->primary_rc != AP_OK)
  1484.   {
  1485.     SRTRACE(t,"Thread %d:%d (%s) error: %s prc %4.4x src %8.8x at %d:%d:%d\n",
  1486.             convptr->thread,convptr->conv,convptr->type,
  1487.             VerbName[vcbptr->opcode],
  1488.             APPC_FLIPI(vcbptr->primary_rc),APPC_FLIPL(vcbptr->secondary_rc),
  1489.             st.wHour,st.wMinute,st.wSecond);
  1490.     if ((vcbptr->opcode == AP_M_RECEIVE_AND_WAIT) &&
  1491.         (vcbptr->primary_rc == AP_DEALLOC_NORMAL))
  1492.     {
  1493.       SRTRACE(t,"Thread %d:%d (%s) MC_RECEIVE_AND_WAIT completed with DEALLOC_NORMAL\n",\
  1494.               convptr->thread,convptr->conv,convptr->type);
  1495.     }
  1496.     else if ((vcbptr->opcode == AP_M_CONFIRM) &&
  1497.              (vcbptr->primary_rc == AP_ALLOCATION_ERROR))
  1498.     {
  1499.       SRTRACE(t,"Thread %d:%d (%s) MC_CONFIRM completed with ALLOCATION_ERROR\n",
  1500.               convptr->thread,convptr->conv,convptr->type);
  1501.     }
  1502.     else if ((vcbptr->opcode == AP_M_ALLOCATE) &&
  1503.              (vcbptr->primary_rc == AP_ALLOCATION_ERROR))
  1504.     {
  1505.       SRTRACE(t,"Thread %d:%d (%s) MC_ALLOCATE completed with ALLOCATION_ERROR\n",
  1506.               convptr->thread,convptr->conv,convptr->type);
  1507.     }
  1508.     else
  1509.     {
  1510.       TPEnded = TRUE;
  1511.       SRTRACE(t,"Thread %d:%d (%s) unexpected error on %s - set TPEnded\n",
  1512.               convptr->thread,convptr->conv,convptr->type,
  1513.               VerbName[vcbptr->opcode]);
  1514.     }
  1515.   }
  1516.   else
  1517.   {
  1518.     switch (vcbptr->opcode)
  1519.     {
  1520.       case AP_TP_STARTED:
  1521.         SRTRACE(t,"Thread %d:%d (%s) TP_Started completed at %d:%d:%d\n",
  1522.                 convptr->thread,convptr->conv,convptr->type,
  1523.                 st.wHour,st.wMinute,st.wSecond);
  1524.         memcpy(convptr->TPid,&(P_TPS(vcbptr)->tp_id),8);
  1525.         break;
  1526.  
  1527.       case AP_TP_ENDED:
  1528.         SRTRACE(t,"Thread %d:%d (%s) TP_Ended completed at %d:%d:%d\n",
  1529.                 convptr->thread,convptr->conv,convptr->type,
  1530.                 st.wHour,st.wMinute,st.wSecond);
  1531.         break;
  1532.  
  1533.       case AP_RECEIVE_ALLOCATE:
  1534.         SRTRACE(t,"Thread %d:%d (%s) Receive_Allocate completed at %d:%d:%d\n",
  1535.                 convptr->thread,convptr->conv,convptr->type,
  1536.                 st.wHour,st.wMinute,st.wSecond);
  1537.         memcpy(convptr->TPid,&(P_RAL(vcbptr)->tp_id),8);
  1538.         convptr->Convid = P_RAL(vcbptr)->conv_id;
  1539.         break;
  1540.  
  1541.       case AP_M_ALLOCATE:
  1542.         SRTRACE(t,"Thread %d:%d (%s) MC_Allocate completed at %d:%d:%d\n",
  1543.                 convptr->thread,convptr->conv,convptr->type,
  1544.                 st.wHour,st.wMinute,st.wSecond);
  1545.         convptr->Convid = P_M_ALC(vcbptr)->conv_id;
  1546.         break;
  1547.  
  1548.       case AP_M_SEND_DATA:
  1549. //      SRTRACE(t,"Thread %d:%d (%s) MC_Send_Data completed at %d:%d:%d\n",
  1550. //              convptr->thread,convptr->conv,convptr->type,
  1551. //              st.wHour,st.wMinute,st.wSecond);
  1552.         break;
  1553.  
  1554.       case AP_M_DEALLOCATE:
  1555. SRTRACE(t,"Thread %d:%d (%s) MC_Deallocate completed at %d:%d:%d: send count %d\n",
  1556.                 convptr->thread,convptr->conv,convptr->type,
  1557.                 st.wHour,st.wMinute,st.wSecond,
  1558.                 convptr->SendCount);
  1559.         convptr->Convid = 0;
  1560.         break;
  1561.  
  1562.       case AP_M_CONFIRM:
  1563. SRTRACE(t,"Thread %d:%d (%s) MC_Confirm completed at %d:%d:%d: send count %d\n",
  1564.                 convptr->thread,convptr->conv,convptr->type,
  1565.                 st.wHour,st.wMinute,st.wSecond,
  1566.                 convptr->SendCount);
  1567.         break;
  1568.  
  1569.       case AP_M_RECEIVE_AND_WAIT:
  1570. //      SRTRACE(t,"Thread %d:%d (%s) MC_Receive_And_Wait completed at %d:%d:%d\n",
  1571. //              convptr->thread,convptr->conv,convptr->type,
  1572. //              st.wHour,st.wMinute,st.wSecond);
  1573.         break;
  1574.  
  1575.       case AP_M_CONFIRMED:
  1576. SRTRACE(t,"Thread %d:%d (%s) MC_Confirmed completed at %d:%d:%d: receive count %d\n",
  1577.                 convptr->thread,convptr->conv,convptr->type,
  1578.                 st.wHour,st.wMinute,st.wSecond,
  1579.                 convptr->RcvCount);
  1580.         break;
  1581.  
  1582.       default:
  1583.         SRTRACE(t,"Thread %d:%d (%s) UNKNOWN opcode - set TPEnded\n",
  1584.                 convptr->thread,convptr->conv,convptr->type);
  1585.         TPEnded = TRUE;
  1586.         DebugBreak();
  1587.         break;
  1588.     }
  1589.   }
  1590.   SRTRFLUSH()
  1591.   return(TPEnded);
  1592. }
  1593.  
  1594. /*****************************************************************************/
  1595. /* ReadConfig - Reads config info from MSENDRCV.CFG and allocates buffer for */
  1596. /*              sending                                                      */
  1597. /*****************************************************************************/
  1598. void ReadConfig()
  1599. {
  1600.   char buffer[200];
  1601.  
  1602.   if (!ReadString("ResultFile",FileName,60))
  1603.   {
  1604.     strcpy(FileName,"MSENDRCV.OUT");
  1605.   }
  1606.  
  1607.   if (!ReadString("TraceFile",TraceFile,60))
  1608.   {
  1609.     strcpy(TraceFile,"MSENDRCV.TRC");
  1610.   }
  1611.  
  1612.   strcpy(TPName,"MSENDRCV");
  1613.   PadString(TPName,64);
  1614.   CONV_A_TO_E(TPName,64);
  1615.  
  1616.   if (!ReadString("LocalTPName",LocalTPName,64))
  1617.   {
  1618.     strcpy(LocalTPName,"MSENDRCVTP");
  1619.   }
  1620.   PadString(LocalTPName,64);
  1621.   CONV_A_TO_E(LocalTPName,64);
  1622.  
  1623.   if (!ReadString("RemoteTPName",RemoteTPName,64))
  1624.   {
  1625.     strcpy(RemoteTPName,"MSENDRCVTP");
  1626.   }
  1627.   PadString(RemoteTPName,64);
  1628.   CONV_A_TO_E(RemoteTPName,64);
  1629.  
  1630.   if (!ReadString("LocalLUAlias",LocalLUAlias,8))
  1631.   {
  1632.     strcpy(LocalLUAlias,"SENDLU");
  1633.   }
  1634.   PadString(LocalLUAlias,8);
  1635.  
  1636.   if (!ReadString("RemoteLUAlias",RemoteLUAlias,8))
  1637.   {
  1638.     strcpy(RemoteLUAlias,"RECVLU");
  1639.   }
  1640.   PadString(RemoteLUAlias,8);
  1641.  
  1642.   if (!ReadString("ModeName",ModeName,8))
  1643.   {
  1644.     strcpy(ModeName,"#INTER");
  1645.   }
  1646.   PadString(ModeName,8);
  1647.   CONV_A_TO_E(ModeName,8);
  1648.  
  1649.   NumSends=8;
  1650.   if (ReadString("NumSends",buffer,200))
  1651.   {
  1652.     NumSends=atoi(buffer);
  1653.   }
  1654.  
  1655.   ConfirmEvery=2;
  1656.   if (ReadString("ConfirmEvery",buffer,200))
  1657.   {
  1658.     ConfirmEvery=atoi(buffer);
  1659.   }
  1660.  
  1661.   SendSize=256;
  1662.   if (ReadString("SendSize",buffer,200))
  1663.   {
  1664.     SendSize=atoi(buffer);
  1665.   }
  1666.  
  1667.   RcvSize=4096;
  1668.   if (ReadString("RcvSize",buffer,200))
  1669.   {
  1670.     RcvSize=atoi(buffer);
  1671.   }
  1672.  
  1673.   NumRcvThreads = 2;
  1674.   if (ReadString("NumRcvThreads",buffer,200))
  1675.   {
  1676.     NumRcvThreads=atoi(buffer);
  1677.   }
  1678.  
  1679.   NumSendConvs = 4;
  1680.   if (ReadString("NumSendConvs",buffer,200))
  1681.   {
  1682.     NumSendConvs=atoi(buffer);
  1683.   }
  1684.  
  1685.   NumRcvConvs = 4;
  1686.   if (ReadString("NumRcvConvs",buffer,200))
  1687.   {
  1688.     NumRcvConvs=atoi(buffer);
  1689.   }
  1690.   NumRalcs = 0;
  1691.   RcvConvs = 0;
  1692.  
  1693.   ResultBuf = (NumRcvConvs == 0) ?
  1694.               NULL : malloc(NumRcvConvs * sizeof(RESULT));
  1695.   ResultPtr = ResultBuf;
  1696.  
  1697.   if (NumRcvConvs > 0 && NumRcvThreads * 63 < NumRcvConvs)
  1698.   {
  1699.     NumRcvThreads = NumRcvConvs / 63 + 1;
  1700.   }
  1701.  
  1702.   if (NumRcvConvs > 0 && NumRcvThreads > NumRcvConvs)
  1703.   {
  1704.     NumRcvThreads = NumRcvConvs;
  1705.   }
  1706. }
  1707.  
  1708. /*****************************************************************************/
  1709. /* CONV_A_TO_E - ASCII to EBCDIC conversion routine                          */
  1710. /*****************************************************************************/
  1711. void CONV_A_TO_E(char * string,int length)
  1712. {
  1713.   memset(cnvtptr,0,sizeof(cnvt));
  1714.  
  1715.   cnvt.opcode       = SV_CONVERT;
  1716.   cnvt.direction    = SV_ASCII_TO_EBCDIC;
  1717.   cnvt.char_set     = SV_AE;
  1718.  
  1719.   cnvt.len          = length;
  1720.   cnvt.source       = string;
  1721.   cnvt.target       = string;
  1722.  
  1723.   ACSSVC_C((long)(char *) (cnvtptr));
  1724. }
  1725.  
  1726. /*****************************************************************************/
  1727. /* CONV_E_TO_A - EBCDIC to ASCII conversion routine                          */
  1728. /*****************************************************************************/
  1729. void CONV_E_TO_A(char * string,int length)
  1730. {
  1731.   memset(cnvtptr,0,sizeof(cnvt));
  1732.  
  1733.   cnvt.opcode       = SV_CONVERT;
  1734.   cnvt.direction    = SV_EBCDIC_TO_ASCII;
  1735.   cnvt.char_set     = SV_AE;
  1736.   cnvt.len          = length;
  1737.   cnvt.source       = string;
  1738.   cnvt.target       = string;
  1739.  
  1740.   ACSSVC_C((long)(char *) (cnvtptr));
  1741. }
  1742.  
  1743. /*****************************************************************************/
  1744. /* StartConversation - Record start time for this conversation               */
  1745. /*****************************************************************************/
  1746. void StartConversation(CONVCB * convptr)
  1747. {
  1748.   convptr->ConvStarted = GetTickCount();
  1749. }
  1750.  
  1751. /*****************************************************************************/
  1752. /* EndConversation - Calculate elapsed time for this conversation            */
  1753. /*****************************************************************************/
  1754. void EndConversation(CONVCB * convptr)
  1755. {
  1756.   if (ResultPtr != NULL)
  1757.   {
  1758.     /*************************************************************************/
  1759.     /* Make sure we don't go over the end of the allocated area              */
  1760.     /*************************************************************************/
  1761.     if (NumResults < NumRcvConvs)
  1762.     {
  1763.       *ResultPtr++ = (GetTickCount() - convptr->ConvStarted);
  1764.       NumResults++;
  1765.     }
  1766.     else
  1767.     {
  1768.       SRTRACE(t,"Thread %d:%d Too many calls to EndConversation\n",
  1769.               convptr->thread,convptr->conv);
  1770.     }
  1771.   }
  1772. }
  1773.  
  1774. /*****************************************************************************/
  1775. /* GenerateData    - Fill in data buffer                                     */
  1776. /*****************************************************************************/
  1777. void GenerateData(CONVCB * convptr)
  1778. {
  1779.   int i;
  1780.   int div;
  1781.   int rem;
  1782.   char * dptr;
  1783.  
  1784.   dptr = convptr->DataPtr;
  1785.   div = convptr->SendSize / 5;
  1786.   rem = convptr->SendSize % 5;
  1787.  
  1788.   for (; div--;)
  1789.   {
  1790.     for (i=4; i--; *dptr++ = datach);
  1791.     *dptr++ = '.';
  1792.   }
  1793.   for (; rem--; *dptr++ = datach);
  1794.  
  1795.   EnterCriticalSection(&runsem);
  1796.   datach = (datach=='Z' ? 'A' : datach + 1);
  1797.   LeaveCriticalSection(&runsem);
  1798. }
  1799.  
  1800. /*****************************************************************************/
  1801. /* OutputResults - dump the times of conversations to file                   */
  1802. /*****************************************************************************/
  1803. void OutputResults()
  1804. {
  1805.   FILE *h = NULL;
  1806.   RESULT * ptr = NULL;
  1807.   unsigned short i = 0;
  1808.  
  1809.   h = fopen(FileName,"w");
  1810.   if (h != NULL)
  1811.   {
  1812.     fprintf(h,"\nMSENDRCV Results\n----------------\n\n");
  1813.     CONV_E_TO_A(LocalTPName,64);
  1814.     fprintf(h,"Local TP Name              = %.64s\n",LocalTPName);
  1815.     CONV_E_TO_A(RemoteTPName,64);
  1816.     fprintf(h,"Remote TP Name             = %.64s\n",RemoteTPName);
  1817.     fprintf(h,"Local LU Alias             = %.8s\n",LocalLUAlias);
  1818.     fprintf(h,"Remote LU Alias            = %.8s\n",RemoteLUAlias);
  1819.     CONV_E_TO_A(ModeName,8);
  1820.     fprintf(h,"ModeName                   = %.8s\n",ModeName);
  1821.     fprintf(h,"No. of receive threads     = %d\n",NumRcvThreads);
  1822.     fprintf(h,"No. of send conversations  = %d\n",NumSendConvs);
  1823.     fprintf(h,"Sends per conversation     = %d\n",NumSends);
  1824.     fprintf(h,"Sends between confirms     = %d\n",ConfirmEvery);
  1825.     fprintf(h,"Bytes per send             = %d\n",SendSize);
  1826.     fprintf(h,"No. of rcv convs started   = %d\n",NumRalcs);
  1827.     fprintf(h,"No. of rcv convs completed = %d\n",RcvConvs);
  1828.     fprintf(h,"\n");
  1829.  
  1830.     ptr = ResultBuf;
  1831.     while (ptr < ResultPtr)
  1832.     {
  1833.       fprintf(h,"Conversation number %d, time = %.3f seconds\n",i++,
  1834.                                                 (((float) *ptr++) / 1000.0 ));
  1835.     }
  1836.     fclose(h);
  1837.   }
  1838. }
  1839.  
  1840. /*****************************************************************************/
  1841. /* ReadString - Get a line of text from the config file                      */
  1842. /*****************************************************************************/
  1843. int ReadString(char * lpValueName,char * lpData, int maxlen)
  1844. {
  1845.   char       buffer[200];
  1846.   char      *p = NULL;
  1847.   FILE      *h = NULL;
  1848.   BOOL       match = FALSE;
  1849.   BOOL       eof   = FALSE;
  1850.   int        rc = 0;
  1851.   int        ch = 0;
  1852.   int        i = 0;
  1853.   BOOL       gotdata = FALSE;
  1854.   char       separators[] = " =\t\n";
  1855.  
  1856.   GetModuleFileName( hInst, buffer, sizeof(buffer) );
  1857.   lstrcpy( buffer+lstrlen(buffer) - 4, ".CFG" );
  1858.   h = fopen( buffer, "r" );
  1859.   buffer[0] = '\0';
  1860.  
  1861.   lpValueName=strupr(lpValueName);
  1862.  
  1863.   if (h != NULL)
  1864.   {
  1865.     while ((!match) && (!eof))
  1866.     {
  1867.       /***********************************************************************/
  1868.       /* Use fgetc to read a line of text from the file                      */
  1869.       /***********************************************************************/
  1870.       for (i=0; (i<sizeof(buffer))     &&
  1871.                 ((ch=getc(h)) != EOF)  &&
  1872.                 ((char)ch != '\n');
  1873.                                    i++)
  1874.       {
  1875.         buffer[i] = (char)ch;
  1876.       }
  1877.       if ((char)ch == '\n')
  1878.       {
  1879.         buffer[i++] = (char)ch;
  1880.       }
  1881.       if (ch == EOF)
  1882.       {
  1883.         eof = TRUE;
  1884.       }
  1885.       else
  1886.       {
  1887.         /*********************************************************************/
  1888.         /* Compare the first token in the line read with the requested parm  */
  1889.         /*********************************************************************/
  1890.         if (!strcmpi(strupr(strtok(buffer, separators)), lpValueName))
  1891.         {
  1892.           match = TRUE;
  1893.           /*******************************************************************/
  1894.           /* Get a pointer to the second token (the value we want)           */
  1895.           /*******************************************************************/
  1896.           p = strtok(NULL, separators);
  1897.  
  1898.           /*******************************************************************/
  1899.           /* Copy the data IF there is some                                  */
  1900.           /*******************************************************************/
  1901.           if (p != NULL)
  1902.           {
  1903.             /*****************************************************************/
  1904.             /* Force a NULL after the second token                           */
  1905.             /*****************************************************************/
  1906.             strtok(NULL, separators);
  1907.  
  1908.             /*****************************************************************/
  1909.             /* Copy the data                                                 */
  1910.             /*****************************************************************/
  1911.             strncpy(lpData, p, maxlen);
  1912.             gotdata = TRUE;
  1913.           }
  1914.           else
  1915.           {
  1916.             gotdata = FALSE;
  1917.           }
  1918.         }
  1919.       }
  1920.     }
  1921.  
  1922.     if (gotdata)
  1923.     {
  1924.       rc = 1;
  1925.     }
  1926.  
  1927.     fclose(h);
  1928.  
  1929.   }
  1930.  
  1931.   return(rc);
  1932. }
  1933.  
  1934. /*****************************************************************************/
  1935. /* PadString - Remove terminating NULL  and pad on the right with spaces     */
  1936. /*****************************************************************************/
  1937. void PadString(char * string,int length)
  1938. {
  1939.   char * p;
  1940.   if ((p=memchr(string,'\0',length)) != NULL)
  1941.   {
  1942.     while (p < string+length)
  1943.     {
  1944.       *p++=' ';
  1945.     }
  1946.   }
  1947. }
  1948.  
  1949.