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 / msend.c < prev    next >
Text File  |  1997-04-09  |  44KB  |  1,136 lines

  1. /* msend.c */
  2. /* (C) COPYRIGHT DATA CONNECTION LIMITED 1994 */
  3.  
  4. /*****************************************************************************/
  5. /* Change History                                                            */
  6. /*                                                                           */
  7. /*       21/02/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 removed                                  */
  11. /*****************************************************************************/
  12.  
  13. /*****************************************************************************/
  14. /* If you want internal tracing, #define SRTRC here                          */
  15. /*****************************************************************************/
  16. //#define SRTRC
  17.  
  18. /*****************************************************************************/
  19. /*                                                                           */
  20. /* ROUTINE : SEND using event completion                                     */
  21. /*                                                                           */
  22. /* FUNCTION: This file contains the routines for a multi-threaded routine    */
  23. /*           which uses asynchronous APPC calls with event completion        */
  24. /*           to send data.                                                   */
  25. /*                                                                           */
  26. /*           It runs with either the single-threaded or the multi-threaded   */
  27. /*           version of receive (mrcv or recvtp).                            */
  28. /*                                                                           */
  29. /* INPUTS  : MSEND.CFG (file) (documented below)                             */
  30. /*                                                                           */
  31. /* OUTPUTS : MSEND.OUT                                                       */
  32. /*           MSEND.TRC                                                       */
  33. /*                                                                           */
  34. /*****************************************************************************/
  35.  
  36. /*****************************************************************************/
  37. /* Operation:                                                                */
  38. /*                                                                           */
  39. /* This is a Windows NT application which runs in a minimized window.        */
  40. /*                                                                           */
  41. /* Thread structure:                                                         */
  42. /*                                                                           */
  43. /*   A variable number of send threads                                       */
  44. /*     Each send thread processes a variable number of conversations and     */
  45. /*     issues a WaitForMultipleObjects to wait for completion of any of its  */
  46. /*     send operations.  Each conversation starts with TP_STARTED, followed  */
  47. /*     by MC_ALLOCATE and MC_CONFIRM.  Then it issues MC_SEND_DATA verbs     */
  48. /*     to send data.  MC_CONFIRMs are issued at configurable intervals.      */
  49. /*     If a confirm fails, an attempt is made to restart the conversation    */
  50. /*     after five seconds.                                                   */
  51. /*                                                                           */
  52. /*   Note:  this program is compatible with the single-threaded version of   */
  53. /*   receive, which can be run for example on WIN16 clients.                 */
  54. /*                                                                           */
  55. /*****************************************************************************/
  56.  
  57. /*****************************************************************************/
  58. /* Configuration file:                                                       */
  59. /*                                                                           */
  60. /* The configuration file is called MSEND.CFG and must reside in the         */
  61. /* same directory as the program.  It contains the following, in any order.  */
  62. /* If any parameter is omitted, the default is assumed.                      */
  63. /*                                                                           */
  64. /* TraceFile = <Name of file for tracing, default MSEND.TRC>                 */
  65. /* RemoteTPName = <Name used for allocate, default MRCVTP>                   */
  66. /* LocalLUAlias = <Alias for local LU, default SENDLU>                       */
  67. /* RemoteLUAlias = <Alias for remote LU, default RECVLU>                     */
  68. /* ModeName = <Mode Name, default #INTER>                                    */
  69. /*                                                                           */
  70. /* NumSendConvs = <Number of conversations to be sent, default = 4>          */
  71. /* NumSends = <number of SEND_DATA verbs per conversation, default = 8>      */
  72. /* ConfirmEvery = <number of SEND_DATA verbs between CONFIRMs, default = 2>  */
  73. /* SendSize = <number of bytes per SEND_DATA, default = 256>                 */
  74. /*                                                                           */
  75. /* The name used for TP_STARTED is fixed at MSEND.                           */
  76. /*                                                                           */
  77. /* If NumSends is zero, the TP will never DEALLOCATE a conversation.         */
  78. /* If ConfirmEvery is zero, the TP will not issue CONFIRM verbs except       */
  79. /*    after the MC_ALLOCATE.                                                 */
  80. /* If ConfirmEvery is non-zero, the TP issues a CONFIRM verbs ConfirmEvery   */
  81. /*    sends.                                                                 */
  82. /*                                                                           */
  83. /* Configuration constants (in msend.h)                                      */
  84. /*                                                                           */
  85. /* #define MAX_SEND_PER_THREAD  Max conversations per send thread      (64)  */
  86. /*                                                                           */
  87. /* MAX_SEND_PER_THREAD is constrained by the limit of 64 objects that can be */
  88. /* waited for in WaitForMultipleObjects.                                     */
  89. /*                                                                           */
  90. /*****************************************************************************/
  91.  
  92. #include <windows.h>
  93. HINSTANCE hInst;
  94. BOOL verbs_started = FALSE;
  95. #include <stdio.h>
  96. #include <stdlib.h>
  97. #include <string.h>
  98. #include <winappc.h>
  99. #include <wincsv.h>
  100. #include "msend.h"
  101.  
  102. /*****************************************************************************/
  103. /* Trace macros                                                              */
  104. /*****************************************************************************/
  105. #ifdef SRTRC
  106. #define SRTROPEN() t = fopen(TraceFile,"w");
  107. #define SRTRFLUSH() fflush(t);
  108. #define SRTRCLOSE() fclose(t);
  109. #define SRTRACE fprintf
  110. #else
  111. #define SRTROPEN()
  112. #define SRTRFLUSH()
  113. #define SRTRCLOSE()
  114. #define SRTRACE 1 ? (void) 0 : fprintf
  115. #endif
  116.  
  117. /*****************************************************************************/
  118. /* WinMain - reads initialization info and controls message loop             */
  119. /*           NT version                                                      */
  120. /*****************************************************************************/
  121. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  122.                    LPSTR lpCmdLine, int nCmdShow)
  123. {
  124.  
  125.   MSG msg;
  126.   DWORD Tid;
  127.   int i;
  128.   DWORD NumConvs;
  129.   HANDLE ThreadHandle;
  130.  
  131.   hInst = hInstance;
  132.  
  133.   InitializeMain();
  134.  
  135.   if (!InitializeWinMain(hInstance))
  136.   {
  137.     return (FALSE);
  138.   }
  139.  
  140.   ReadConfig();
  141.   SRTROPEN()
  142.  
  143.   /***************************************************************************/
  144.   /* Create enough send threads to process conversations                     */
  145.   /***************************************************************************/
  146.   i = NumSendConvs;
  147.   while (i > 0)
  148.   {
  149.     NumConvs = (i > 64) ? 64 : i;
  150.     ThreadHandle = CreateThread(NULL,
  151.                                 16000,
  152.                                 (LPTHREAD_START_ROUTINE)SendThread,
  153.                                 (void *)NumConvs,
  154.                                 0,
  155.                                 &Tid);
  156.     if (ThreadHandle == NULL)
  157.     {
  158.       GetLastError();
  159.       DebugBreak();
  160.     }
  161.     SetThreadPriority(ThreadHandle,THREAD_PRIORITY_BELOW_NORMAL);
  162.     SRTRACE(t,"Created send thread with %d conversations and priority %d\n",
  163.             NumConvs,GetThreadPriority(ThreadHandle));
  164.     CloseHandle(ThreadHandle);
  165.     i -= NumConvs;
  166.   }
  167.  
  168.   /***************************************************************************/
  169.   /* Windows processing loop                                                 */
  170.   /***************************************************************************/
  171.   while(GetMessage(&msg,NULL,0,0))
  172.   {
  173.     TranslateMessage(&msg);
  174.     DispatchMessage(&msg);
  175.   }
  176.  
  177.   WinAPPCCleanup();
  178.   SRTRFLUSH()
  179.   SRTRCLOSE()
  180.   DeleteCriticalSection(&runsem);
  181.   return msg.wParam;         /* save exit parameter for return               */
  182.  
  183. }
  184.  
  185. /*****************************************************************************/
  186. /* SendThread - thread which processes multiple conversations                */
  187. /*****************************************************************************/
  188. DWORD WINAPI SendThread(DWORD NumConvs)
  189. {
  190.   /***************************************************************************/
  191.   /* Separate variables for each instance of this thread                     */
  192.   /***************************************************************************/
  193.   CONVCB * convptr;
  194.   struct appc_hdr * vcbptr;
  195.   unsigned short ThreadNo;
  196.   unsigned short SendThreadNo;
  197.   DWORD ObjIndex;
  198.   DWORD i;
  199.   DWORD j;
  200.   DWORD rc;
  201.   CONVCB * ConvptrArray [MAX_SEND_PER_THREAD+1];
  202.   HANDLE EventArray [MAX_SEND_PER_THREAD+1];
  203.   SYSTEMTIME st;
  204.  
  205.   for (i = 0; i < MAX_SEND_PER_THREAD+1; i++)
  206.   {
  207.     ConvptrArray[i] = NULL;
  208.     EventArray[i] = NULL;
  209.   }
  210.  
  211.   /***************************************************************************/
  212.   /* Count threads within critical section                                   */
  213.   /***************************************************************************/
  214.   EnterCriticalSection(&runsem);
  215.   ThreadCount++;
  216.   SendThreads++;
  217.   ThreadNo = ThreadCount;
  218.   SendThreadNo = SendThreads;
  219.   OUTPUTNUMBER
  220.   LeaveCriticalSection(&runsem);
  221.  
  222.   for (i = 0; i < NumConvs; i++)
  223.   {
  224.     /*************************************************************************/
  225.     /* Make a conversation control block                                     */
  226.     /*************************************************************************/
  227.     convptr = malloc (sizeof(CONVCB));
  228.     convptr->thread       = SendThreadNo;
  229.     convptr->conv         = (unsigned short)i;
  230.     convptr->async_corr   = 0;
  231.     convptr->TPid[0]      = '\0';
  232.     convptr->Convid       = 0;
  233.     convptr->SendCount    = 0;
  234.     convptr->ConfirmCount = 0;
  235.     convptr->TPEnded      = FALSE;
  236.     convptr->Deallocated  = FALSE;
  237.     convptr->Counted      = FALSE;
  238.     convptr->SendSize     = SendSize;
  239.     convptr->DataPtr      = malloc(convptr->SendSize);
  240.     vcbptr = (struct appc_hdr *) &convptr->vcb;
  241.     memset(vcbptr,0,sizeof(VCB));
  242.     strcpy (convptr->type,"send");
  243. //  SRTRACE(t,"Thread %d:%d (send) has convptr %p\n",
  244. //          SendThreadNo,i,convptr);
  245.  
  246.     /*************************************************************************/
  247.     /* Create an event                                                       */
  248.     /*************************************************************************/
  249.     convptr->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  250.     SRTRACE(t,"Thread %d:%d (send) has event handle %p\n",
  251.             SendThreadNo,i,convptr->hEvent);
  252.  
  253.     /*************************************************************************/
  254.     /* Add to arrays                                                         */
  255.     /*************************************************************************/
  256.     ConvptrArray[i] = convptr;
  257.     EventArray[i]   = convptr->hEvent;
  258.  
  259.     /*************************************************************************/
  260.     /* Build a tp_started                                                    */
  261.     /*************************************************************************/
  262.     Build_TP_STARTED(convptr);
  263.     SRTRFLUSH()
  264.  
  265.     /*************************************************************************/
  266.     /*PERF* Don't re-generate data each time we issue a send!                */
  267.     /*************************************************************************/
  268.     GenerateData(convptr);
  269.  
  270.     /*************************************************************************/
  271.     /* Issue tp_started                                                      */
  272.     /*************************************************************************/
  273.     convptr->async_corr = WinAsyncAPPCEx(convptr->hEvent,
  274.                                          (long)(char *)(vcbptr));
  275. //  SRTRACE(t,"Thread %d:%d (send) tp_started issued corr %p\n",
  276. //          SendThreadNo,i,convptr->async_corr);
  277.     SRTRFLUSH()
  278.     if (convptr->async_corr == 0)
  279.     {
  280.       SRTRACE(t,"Thread %d:%d (send) WinAsync call %x failed corr %p\n",
  281.               SendThreadNo,i,vcbptr->opcode,convptr->async_corr);
  282.       convptr->TPEnded = TRUE;
  283.     }
  284.   }
  285.  
  286.   /***************************************************************************/
  287.   /* Loop round until finished                                               */
  288.   /***************************************************************************/
  289.   while (TRUE)
  290.   {
  291.     /*************************************************************************/
  292.     /* Wait for event completion                                             */
  293.     /*************************************************************************/
  294. //  SRTRACE(t,"Thread %d (send) waiting for %d events to complete\n",
  295. //          SendThreadNo,NumConvs);
  296.     ObjIndex = WaitForMultipleObjects(NumConvs,EventArray,FALSE,INFINITE);
  297.     if (ObjIndex == WAIT_FAILED)
  298.     {
  299.       rc = GetLastError();
  300.       SRTRACE(t,"Thread %d (send) wait for %d events failed with rc %d\n",
  301.               SendThreadNo,NumConvs,rc);
  302.       for (j = 0; j < NumConvs; j++)
  303.       {
  304.         SRTRACE(t,"Thread %d (send) event %d has handle %p\n",
  305.                 SendThreadNo,j,EventArray[j]);
  306.       }
  307.       break;
  308.     }
  309.  
  310.     /*************************************************************************/
  311.     /* Get index to conversation array                                       */
  312.     /*************************************************************************/
  313.     i = ObjIndex - WAIT_OBJECT_0;
  314. //  SRTRACE(t,"Thread %d:%d (send) event %d has completed\n",
  315. //          SendThreadNo,ConvptrArray[i]->conv,i);
  316.  
  317.     /*************************************************************************/
  318.     /* Issue the next verb                                                   */
  319.     /*************************************************************************/
  320. //  SRTRACE(t,"Thread %d:%d (send) issuing next send verb\n",
  321. //          SendThreadNo,ConvptrArray[i]->conv);
  322.     ConvptrArray[i]->TPEnded = IssueSendVerb(ConvptrArray[i]);
  323.  
  324.     if (ConvptrArray[i]->TPEnded)
  325.     {
  326.       /***********************************************************************/
  327.       /* end of conversation                                                 */
  328.       /***********************************************************************/
  329.       NumConvs--;
  330.       SRTRACE(t,"Thread %d:%d (send) conversation completed: NumConvs %d\n",
  331.               SendThreadNo,ConvptrArray[i]->conv,NumConvs);
  332.       EnterCriticalSection(&runsem);
  333.       SendConvs++;
  334.       OUTPUTNUMBER
  335.       SRTRACE(t,"Thread %d:%d (send) NumConvs %d SendConvs %d\n",
  336.               SendThreadNo,ConvptrArray[i]->conv,NumConvs,SendConvs);
  337.       LeaveCriticalSection(&runsem);
  338.  
  339.       /***********************************************************************/
  340.       /* free resources                                                      */
  341.       /***********************************************************************/
  342.       CloseHandle(ConvptrArray[i]->hEvent);
  343.       free (ConvptrArray[i]->DataPtr);
  344.       free (ConvptrArray[i]);
  345.       ConvptrArray[i] = NULL;
  346.       EventArray[i]   = NULL;
  347.  
  348.       /***********************************************************************/
  349.       /* if all conversations have completed, end loop                       */
  350.       /***********************************************************************/
  351.       if (NumConvs == 0)
  352.       {
  353.         break;
  354.       }
  355.       /***********************************************************************/
  356.       /* the event array cannot have holes in it, so shuffle up the          */
  357.       /* pointers and events                                                 */
  358.       /* note that this means convptr->conv no longer matches i              */
  359.       /* which is why tracing uses ConvptrArray[i]->conv                     */
  360.       /***********************************************************************/
  361.       for (j = i; j < MAX_SEND_PER_THREAD - 1; j++)
  362.       {
  363.         ConvptrArray [j] = ConvptrArray [j+1];
  364.         EventArray [j] = EventArray [j+1];
  365.       }
  366.       ConvptrArray [MAX_SEND_PER_THREAD-1] = NULL;
  367.       EventArray [MAX_SEND_PER_THREAD-1] = NULL;
  368.     }
  369.     else
  370.     {
  371.       /***********************************************************************/
  372.       /* to stop one conversation getting an unfair share of the time,       */
  373.       /* move this conversation to the end and shuffle up the pointers.      */
  374.       /* note that this means convptr->conv no longer matches i              */
  375.       /* which is why tracing uses ConvptrArray[i]->conv                     */
  376.       /***********************************************************************/
  377.       ConvptrArray [NumConvs] = ConvptrArray [i];
  378.       EventArray [NumConvs] = EventArray [i];
  379.       for (j = i; j < NumConvs; j++)
  380.       {
  381.         ConvptrArray [j] = ConvptrArray [j+1];
  382.         EventArray [j] = EventArray [j+1];
  383.       }
  384.       ConvptrArray [NumConvs] = NULL;
  385.       EventArray [NumConvs] = NULL;
  386.     }
  387.   }
  388.  
  389.   /***************************************************************************/
  390.   /* Count threads within critical section                                   */
  391.   /***************************************************************************/
  392.   EnterCriticalSection(&runsem);
  393.   ThreadCount--;
  394.   SendThreads--;
  395.   GetLocalTime(&st);
  396.   SRTRACE(t,"Thread %d (send) Exit at %d:%d:%d: ThreadCount %d\n",
  397.           SendThreadNo,st.wHour,st.wMinute,st.wSecond,ThreadCount);
  398.   OUTPUTNUMBER
  399.   if (ThreadCount == 0)
  400.   {
  401.     PostMessage(hWndMain, WM_CLOSE, 0, 0);
  402.   }
  403.   LeaveCriticalSection(&runsem);
  404.   return(0);
  405. }
  406.  
  407. /*****************************************************************************/
  408. /* InitializeWinMain - does the windows bits of initialisation               */
  409. /*****************************************************************************/
  410. BOOL InitializeWinMain(HINSTANCE hInstance)
  411. {
  412.   WAPPCDATA APPCData;
  413.   WNDCLASS class;
  414.   #define WinAPPCVERSION  0x0001
  415.  
  416.   /***************************************************************************/
  417.   /* Startup WinAPPC                                                         */
  418.   /***************************************************************************/
  419.   if (WinAPPCStartup(WinAPPCVERSION,&APPCData))
  420.   {
  421.     return (FALSE);
  422.   }
  423.  
  424.   /***************************************************************************/
  425.   /* Register Window Class for our icon                                      */
  426.   /***************************************************************************/
  427.  
  428.   class.style = 0;
  429.   class.lpfnWndProc   = (WNDPROC)TPWndProc;
  430.   class.cbClsExtra    = (DWORD)0;
  431.   class.cbWndExtra    = (DWORD)0;
  432.   class.hInstance     = hInstance;
  433.   class.hIcon         = LoadIcon(hInstance,"MainIcon");
  434.   class.hCursor       = LoadCursor(NULL, IDC_ARROW);
  435.   class.hbrBackground = GetStockObject(WHITE_BRUSH);
  436.   class.lpszMenuName  = (LPSTR) NULL;
  437.   class.lpszClassName = (LPSTR) "MSEND\0";
  438.  
  439.   if (!RegisterClass(&class))
  440.   {
  441.     return (FALSE);
  442.   }
  443.  
  444.   /***************************************************************************/
  445.   /* Create the window                                                       */
  446.   /***************************************************************************/
  447.   sprintf(title,"APPC Send TP\0");
  448.  
  449.   if ((hWndMain = CreateWindow("MSEND\0",         /* window class            */
  450.       title,                                      /* window name             */
  451.       WS_MINIMIZE|WS_OVERLAPPEDWINDOW,            /* window style            */
  452.       0,                                          /* x position              */
  453.       0,                                          /* y position              */
  454.       10,                                         /* width                   */
  455.       10,                                         /* height                  */
  456.       NULL,                                       /* parent handle           */
  457.       NULL,                                       /* menu or child ID        */
  458.       hInstance,                                  /* instance                */
  459.       NULL))                                      /* additional info         */
  460.       == NULL)
  461.   {
  462.     return (FALSE);
  463.   }
  464.  
  465.   ShowWindow(hWndMain, SW_MINIMIZE);
  466.  
  467.   return(TRUE);
  468.  
  469. }
  470.  
  471. /*****************************************************************************/
  472. /* Window proc for the iconised window                                       */
  473. /*****************************************************************************/
  474. LONG PASCAL TPWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
  475. {
  476.   switch (message)
  477.   {
  478.     case WM_CREATE:
  479.       break;
  480.  
  481.     case WM_QUERYOPEN:
  482.       /***********************************************************************/
  483.       /* Prevent the window being opened                                     */
  484.       /***********************************************************************/
  485.       break;
  486.  
  487.     case WM_CLOSE:
  488.       return DefWindowProc(hWnd, message, wParam, lParam);
  489.       break;
  490.  
  491.     case WM_DESTROY:
  492.       PostQuitMessage(0);
  493.       break;
  494.  
  495.     default:
  496.       return DefWindowProc(hWnd, message, wParam, lParam);
  497.       break;
  498.   }
  499.   return 0l;
  500. }
  501.  
  502. /*****************************************************************************/
  503. /* InitializeMain - blanks out variables not set in ReadConfig               */
  504. /*****************************************************************************/
  505. void InitializeMain()
  506. {
  507.   SendThreads = 0;
  508.   ThreadCount = 0;
  509.   cnvtptr     = (char *)&cnvt;
  510.  
  511.   datach      = 'A';
  512.  
  513.   InitializeCriticalSection(&runsem);
  514. }
  515.  
  516. /*****************************************************************************/
  517. /* IssueSendVerb - looks at the verb which has just completed and does the   */
  518. /*                 next one                                                  */
  519. /*****************************************************************************/
  520. BOOL IssueSendVerb(CONVCB * convptr)
  521. {
  522.   BOOL TPEnded;
  523.   struct appc_hdr * vcbptr;
  524.  
  525. //SRTRACE(t,"Thread %d (send) IssueSendVerb\n",convptr->thread);
  526.   TPEnded = FALSE;
  527.   vcbptr = (struct appc_hdr *) &convptr->vcb;
  528.   if (vcbptr->opcode != 0x0000)
  529.   {
  530.     TPEnded = ProcessReturns(convptr);
  531.   }
  532.   if (!TPEnded)
  533.   {
  534.     switch (vcbptr->opcode)
  535.     {
  536.       case 0x0000:
  537.         Build_TP_STARTED(convptr);
  538.  
  539.         /*********************************************************************/
  540.         /*PERF* Don't re-generate data each time we issue a send!            */
  541.         /*********************************************************************/
  542.         GenerateData(convptr);
  543.         break;
  544.  
  545.       case AP_TP_STARTED:
  546.         Build_MC_ALLOCATE(convptr);
  547.         break;
  548.  
  549.       case AP_M_ALLOCATE:
  550.         if (vcbptr->primary_rc == AP_OK)
  551.         {
  552.           /*******************************************************************/
  553.           /* confirm before the first send to find out if anyone there       */
  554.           /*******************************************************************/
  555.           Build_MC_CONFIRM(convptr);
  556.         }
  557.         else
  558.         {
  559.           /*******************************************************************/
  560.           /* allocate timed out or connection is for incoming call           */
  561.           /* if there are no conversations active, try again in 5 seconds    */
  562.           /* otherwise retry immediately - someone must be out there         */
  563.           /*******************************************************************/
  564.           if (SimSendConvs == 0)
  565.           {
  566.             SRTRACE(t,"Thread %d:%d (send) wait 5 seconds before retry\n",
  567.                     convptr->thread,convptr->conv);
  568.             Sleep (5000);
  569.           }
  570.           SRTRACE(t,"Thread %d:%d (send) retrying\n",
  571.                   convptr->thread,convptr->conv);
  572.           Build_MC_ALLOCATE(convptr);
  573.         }
  574.         break;
  575.  
  576.       case AP_M_SEND_DATA:
  577.         convptr->SendCount++;
  578.         convptr->ConfirmCount++;
  579.         if ((NumSends != 0) && (convptr->SendCount == NumSends))
  580.         {
  581.           /*******************************************************************/
  582.           /* all sends done - deallocate                                     */
  583.           /*******************************************************************/
  584.           Build_MC_DEALLOCATE(convptr);
  585.         }
  586.         else if ((ConfirmEvery != 0) &&
  587.                  (convptr->ConfirmCount == ConfirmEvery))
  588.         {
  589.           /*******************************************************************/
  590.           /* time to confirm                                                 */
  591.           /*******************************************************************/
  592.           Build_MC_CONFIRM(convptr);
  593.         }
  594.         else
  595.         {
  596.           /*******************************************************************/
  597.           /* just send more data                                             */
  598.           /*******************************************************************/
  599.           Build_MC_SEND_DATA(convptr);
  600.         }
  601.         break;
  602.  
  603.       case AP_M_CONFIRM:
  604.         if (vcbptr->primary_rc == AP_OK)
  605.         {
  606.           if (convptr->SendCount == 0)
  607.           {
  608.             convptr->Counted = TRUE;
  609.             EnterCriticalSection(&runsem);
  610.             SimSendConvs++;
  611.             OUTPUTNUMBER
  612.             SRTRACE(t,"Thread %d (send) SimSendConvs %d\n",
  613.                     convptr->thread,SimSendConvs);
  614.             LeaveCriticalSection(&runsem);
  615.           }
  616.           convptr->ConfirmCount=0;
  617.           Build_MC_SEND_DATA(convptr);
  618.         }
  619.         else
  620.         {
  621.           /*******************************************************************/
  622.           /* if there are no conversations active, try again in 5 seconds    */
  623.           /* otherwise retry immediately - someone must be out there         */
  624.           /*******************************************************************/
  625.           if (SimSendConvs == 0)
  626.           {
  627.             SRTRACE(t,"Thread %d:%d (send) wait 5 seconds before retry\n",
  628.                     convptr->thread,convptr->conv);
  629.             Sleep (5000);
  630.           }
  631.           SRTRACE(t,"Thread %d:%d (send) retrying\n",
  632.                   convptr->thread,convptr->conv);
  633.           Build_MC_ALLOCATE(convptr);
  634.         }
  635.         break;
  636.  
  637.       case AP_M_DEALLOCATE:
  638.         Build_TP_ENDED(convptr);
  639.         break;
  640.  
  641.       case AP_TP_ENDED:
  642.         /*********************************************************************/
  643.         /* quit                                                              */
  644.         /*********************************************************************/
  645.         TPEnded = TRUE;
  646.         break;
  647.  
  648.       default:
  649.         /*********************************************************************/
  650.         /* What is this verb then ??                                         */
  651.         /*********************************************************************/
  652.         TPEnded = TRUE;
  653.         DebugBreak();
  654.         break;
  655.  
  656.     } /* Op-code switch */
  657.  
  658.   }
  659.  
  660.   /***************************************************************************/
  661.   /* If send conversation has finished and was counted, count it down        */
  662.   /***************************************************************************/
  663.   if (TPEnded && convptr->Counted)
  664.   {
  665.     EnterCriticalSection(&runsem);
  666.     SimSendConvs--;
  667.     OUTPUTNUMBER
  668.     SRTRACE(t,"Thread %d (send) SimSendConvs %d\n",
  669.             convptr->thread,SimSendConvs);
  670.     LeaveCriticalSection(&runsem);
  671.   }
  672.  
  673.   /***************************************************************************/
  674.   /* Now go ahead and issue the verb, if we're not finished                  */
  675.   /***************************************************************************/
  676.   if (!TPEnded)
  677.   {
  678.     convptr->async_corr = WinAsyncAPPCEx(convptr->hEvent,
  679.                                          (long)(char *)(vcbptr));
  680.     if (convptr->async_corr == 0)
  681.       {
  682.         SRTRACE(t,"Thread %d (send) WinAsync call %x failed corr %p\n",
  683.                 convptr->thread,vcbptr->opcode,
  684.                 convptr->async_corr);
  685.         convptr->TPEnded = TRUE;
  686.       }
  687.   }
  688.  
  689.   SRTRFLUSH()
  690.   return(TPEnded);
  691.  
  692. } /* Issue send verb */
  693.  
  694. /*****************************************************************************/
  695. /* Build routines to build all required verbs                                */
  696. /*****************************************************************************/
  697.  
  698. void Build_TP_STARTED(CONVCB * convptr)
  699. {
  700.   TP_STARTED * vcbptr;
  701.   SRTRACE(t,"Thread %d:%d (%s) Build_TP_Started\n",
  702.           convptr->thread,convptr->conv,convptr->type);
  703.   vcbptr = (TP_STARTED *) &(convptr->vcb);
  704.  
  705.   CLEARVCB
  706.  
  707.   vcbptr->opcode = AP_TP_STARTED;
  708.   memcpy(&(vcbptr->lu_alias), LocalLUAlias, 8);
  709.   memcpy(&(vcbptr->tp_name), TPName, 64);
  710. }
  711.  
  712. void Build_TP_ENDED(CONVCB * convptr)
  713. {
  714.   TP_ENDED * vcbptr;
  715.   SRTRACE(t,"Thread %d:%d (%s) Build_TP_Ended\n",
  716.           convptr->thread,convptr->conv,convptr->type);
  717.   vcbptr = (TP_ENDED *) &(convptr->vcb);
  718.  
  719.   CLEARVCB
  720.  
  721.   vcbptr->opcode = AP_TP_ENDED;
  722.   memcpy(&(vcbptr->tp_id), convptr->TPid, 8);
  723.   vcbptr->type = AP_SOFT;
  724. }
  725.  
  726. void Build_MC_ALLOCATE(CONVCB * convptr)
  727. {
  728.   MC_ALLOCATE * vcbptr;
  729.   SRTRACE(t,"Thread %d:%d (%s) Build_MC_Allocate\n",
  730.           convptr->thread,convptr->conv,convptr->type);
  731.   vcbptr = (MC_ALLOCATE *) &(convptr->vcb);
  732.  
  733.   CLEARVCB
  734.  
  735.   vcbptr->opcode = AP_M_ALLOCATE;
  736.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  737.   memcpy(vcbptr->tp_id,convptr->TPid, 8);
  738.   vcbptr->sync_level = AP_CONFIRM_SYNC_LEVEL;
  739.   vcbptr->rtn_ctl = AP_WHEN_SESSION_ALLOCATED;
  740.   memcpy(vcbptr->plu_alias, RemoteLUAlias, 8);
  741.   memcpy(vcbptr->mode_name, ModeName, 8);
  742.   memcpy(vcbptr->tp_name, RemoteTPName, 64);
  743.   vcbptr->security = AP_NONE;
  744. }
  745.  
  746. void Build_MC_CONFIRM(CONVCB * convptr)
  747. {
  748.   MC_CONFIRM * vcbptr;
  749. //SRTRACE(t,"Thread %d:%d (%s) Build_MC_Confirm\n",
  750. //        convptr->thread,convptr->conv,convptr->type);
  751.   vcbptr = (MC_CONFIRM *) &(convptr->vcb);
  752.  
  753.   CLEARVCB
  754.  
  755.   vcbptr->opcode = AP_M_CONFIRM;
  756.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  757.   memcpy(vcbptr->tp_id,convptr->TPid, 8);
  758.   vcbptr->conv_id = convptr->Convid;
  759. }
  760.  
  761. void Build_MC_DEALLOCATE(CONVCB * convptr)
  762. {
  763.   MC_DEALLOCATE * vcbptr;
  764.   SRTRACE(t,"Thread %d:%d (%s) Build_MC_Deallocate\n",
  765.           convptr->thread,convptr->conv,convptr->type);
  766.   vcbptr = (MC_DEALLOCATE *) &(convptr->vcb);
  767.  
  768.   CLEARVCB
  769.  
  770.   vcbptr->opcode = AP_M_DEALLOCATE;
  771.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  772.   memcpy(&(vcbptr->tp_id),convptr->TPid, 8);
  773.   vcbptr->conv_id = convptr->Convid;
  774.   if (ConfirmEvery == 0)
  775.   {
  776.      vcbptr->dealloc_type = AP_FLUSH;
  777.   }
  778.   else
  779.   {
  780.      vcbptr->dealloc_type = AP_SYNC_LEVEL;
  781.   }
  782. }
  783.  
  784. void Build_MC_SEND_DATA(CONVCB * convptr)
  785. {
  786.   MC_SEND_DATA * vcbptr;
  787. //SRTRACE(t,"Thread %d:%d (%s) Build_MC_Send_Data\n",
  788. //        convptr->thread,convptr->conv,convptr->type);
  789.   vcbptr = (MC_SEND_DATA *) &(convptr->vcb);
  790.  
  791.   CLEARVCB
  792.  
  793.   //  PERF - GenerateData();
  794.  
  795.   vcbptr->opcode = AP_M_SEND_DATA;
  796.   vcbptr->opext = AP_MAPPED_CONVERSATION;
  797.   memcpy(&(vcbptr->tp_id),convptr->TPid, 8);
  798.   vcbptr->conv_id = convptr->Convid;
  799.   vcbptr->dlen = convptr->SendSize;
  800.   vcbptr->dptr = convptr->DataPtr;
  801.   vcbptr->type = AP_NONE;
  802. }
  803.  
  804. /*****************************************************************************/
  805. /* ProcessReturns - Checks return codes from the last verb to complete and   */
  806. /*                  saves conversation id and tp id in the conversation cb   */
  807. /*****************************************************************************/
  808. BOOL ProcessReturns(CONVCB * convptr)
  809. {
  810.   BOOL TPEnded = FALSE;
  811.   struct appc_hdr * vcbptr;
  812.   SYSTEMTIME st;
  813.  
  814. //SRTRACE(t,"Thread %d:%d (%s) ProcessReturns\n",
  815. //        convptr->thread,convptr->conv,convptr->type);
  816.   vcbptr = (struct appc_hdr *) &(convptr->vcb);
  817.  
  818.   GetLocalTime(&st);
  819.   if (vcbptr->primary_rc != AP_OK)
  820.   {
  821.     SRTRACE(t,"Thread %d:%d (%s) error: %s prc %4.4x src %8.8x at %d:%d:%d\n",
  822.             convptr->thread,convptr->conv,convptr->type,
  823.             VerbName[vcbptr->opcode],
  824.             APPC_FLIPI(vcbptr->primary_rc),APPC_FLIPL(vcbptr->secondary_rc),
  825.             st.wHour,st.wMinute,st.wSecond);
  826.     if ((vcbptr->opcode == AP_M_CONFIRM) &&
  827.              (vcbptr->primary_rc == AP_ALLOCATION_ERROR))
  828.     {
  829.       SRTRACE(t,"Thread %d:%d (%s) MC_CONFIRM completed with ALLOCATION_ERROR\n",
  830.               convptr->thread,convptr->conv,convptr->type);
  831.     }
  832.     else
  833.     {
  834.       TPEnded = TRUE;
  835.       SRTRACE(t,"Thread %d:%d (%s) unexpected error on %s - set TPEnded\n",
  836.               convptr->thread,convptr->conv,convptr->type,
  837.               VerbName[vcbptr->opcode]);
  838.     }
  839.   }
  840.   else
  841.   {
  842.     switch (vcbptr->opcode)
  843.     {
  844.       case AP_TP_STARTED:
  845.         SRTRACE(t,"Thread %d:%d (%s) TP_Started completed at %d:%d:%d\n",
  846.                 convptr->thread,convptr->conv,convptr->type,
  847.                 st.wHour,st.wMinute,st.wSecond);
  848.         memcpy(convptr->TPid,&(P_TPS(vcbptr)->tp_id),8);
  849.         break;
  850.  
  851.       case AP_TP_ENDED:
  852.         SRTRACE(t,"Thread %d:%d (%s) TP_Ended completed at %d:%d:%d\n",
  853.                 convptr->thread,convptr->conv,convptr->type,
  854.                 st.wHour,st.wMinute,st.wSecond);
  855.         break;
  856.  
  857.       case AP_M_ALLOCATE:
  858.         SRTRACE(t,"Thread %d:%d (%s) MC_Allocate completed at %d:%d:%d\n",
  859.                 convptr->thread,convptr->conv,convptr->type,
  860.                 st.wHour,st.wMinute,st.wSecond);
  861.         convptr->Convid = P_M_ALC(vcbptr)->conv_id;
  862.         break;
  863.  
  864.       case AP_M_SEND_DATA:
  865. //      SRTRACE(t,"Thread %d:%d (%s) MC_Send_Data completed at %d:%d:%d\n",
  866. //              convptr->thread,convptr->conv,convptr->type,
  867. //              st.wHour,st.wMinute,st.wSecond);
  868.         break;
  869.  
  870.       case AP_M_DEALLOCATE:
  871. SRTRACE(t,"Thread %d:%d (%s) MC_Deallocate completed at %d:%d:%d: send count %d\n",
  872.                 convptr->thread,convptr->conv,convptr->type,
  873.                 st.wHour,st.wMinute,st.wSecond,
  874.                 convptr->SendCount);
  875.         convptr->Convid = 0;
  876.         break;
  877.  
  878.       case AP_M_CONFIRM:
  879. SRTRACE(t,"Thread %d:%d (%s) MC_Confirm completed at %d:%d:%d: send count %d\n",
  880.                 convptr->thread,convptr->conv,convptr->type,
  881.                 st.wHour,st.wMinute,st.wSecond,
  882.                 convptr->SendCount);
  883.         break;
  884.  
  885.       default:
  886.         SRTRACE(t,"Thread %d:%d (%s) UNKNOWN opcode - set TPEnded\n",
  887.                 convptr->thread,convptr->conv,convptr->type);
  888.         TPEnded = TRUE;
  889.         DebugBreak();
  890.         break;
  891.     }
  892.   }
  893.   SRTRFLUSH()
  894.   return(TPEnded);
  895. }
  896.  
  897. /*****************************************************************************/
  898. /* ReadConfig - Reads config info from MSEND.CFG and allocates buffer for    */
  899. /*              sending                                                      */
  900. /*****************************************************************************/
  901. void ReadConfig()
  902. {
  903.   char buffer[200];
  904.  
  905.   if (!ReadString("TraceFile",TraceFile,60))
  906.   {
  907.     strcpy(TraceFile,"MSEND.TRC");
  908.   }
  909.  
  910.   strcpy(TPName,"MSEND");
  911.   PadString(TPName,64);
  912.   CONV_A_TO_E(TPName,64);
  913.  
  914.   if (!ReadString("RemoteTPName",RemoteTPName,64))
  915.   {
  916.     strcpy(RemoteTPName,"MRCVTP");
  917.   }
  918.   PadString(RemoteTPName,64);
  919.   CONV_A_TO_E(RemoteTPName,64);
  920.  
  921.   if (!ReadString("LocalLUAlias",LocalLUAlias,8))
  922.   {
  923.     strcpy(LocalLUAlias,"SENDLU");
  924.   }
  925.   PadString(LocalLUAlias,8);
  926.  
  927.   if (!ReadString("RemoteLUAlias",RemoteLUAlias,8))
  928.   {
  929.     strcpy(RemoteLUAlias,"RECVLU");
  930.   }
  931.   PadString(RemoteLUAlias,8);
  932.  
  933.   if (!ReadString("ModeName",ModeName,8))
  934.   {
  935.     strcpy(ModeName,"#INTER");
  936.   }
  937.   PadString(ModeName,8);
  938.   CONV_A_TO_E(ModeName,8);
  939.  
  940.   NumSends=8;
  941.   if (ReadString("NumSends",buffer,200))
  942.   {
  943.     NumSends=atoi(buffer);
  944.   }
  945.  
  946.   ConfirmEvery=2;
  947.   if (ReadString("ConfirmEvery",buffer,200))
  948.   {
  949.     ConfirmEvery=atoi(buffer);
  950.   }
  951.  
  952.   SendSize=256;
  953.   if (ReadString("SendSize",buffer,200))
  954.   {
  955.     SendSize=atoi(buffer);
  956.   }
  957.  
  958.   NumSendConvs = 4;
  959.   if (ReadString("NumSendConvs",buffer,200))
  960.   {
  961.     NumSendConvs=atoi(buffer);
  962.   }
  963.  
  964. }
  965.  
  966. /*****************************************************************************/
  967. /* CONV_A_TO_E - ASCII to EBCDIC conversion routine                          */
  968. /*****************************************************************************/
  969. void CONV_A_TO_E(char * string,int length)
  970. {
  971.   memset(cnvtptr,0,sizeof(cnvt));
  972.  
  973.   cnvt.opcode       = SV_CONVERT;
  974.   cnvt.direction    = SV_ASCII_TO_EBCDIC;
  975.   cnvt.char_set     = SV_AE;
  976.  
  977.   cnvt.len          = length;
  978.   cnvt.source       = string;
  979.   cnvt.target       = string;
  980.  
  981.   ACSSVC_C((long)(char *) (cnvtptr));
  982. }
  983.  
  984. /*****************************************************************************/
  985. /* CONV_E_TO_A - EBCDIC to ASCII conversion routine                          */
  986. /*****************************************************************************/
  987. void CONV_E_TO_A(char * string,int length)
  988. {
  989.   memset(cnvtptr,0,sizeof(cnvt));
  990.  
  991.   cnvt.opcode       = SV_CONVERT;
  992.   cnvt.direction    = SV_EBCDIC_TO_ASCII;
  993.   cnvt.char_set     = SV_AE;
  994.   cnvt.len          = length;
  995.   cnvt.source       = string;
  996.   cnvt.target       = string;
  997.  
  998.   ACSSVC_C((long)(char *) (cnvtptr));
  999. }
  1000.  
  1001. /*****************************************************************************/
  1002. /* GenerateData    - Fill in data buffer                                     */
  1003. /*****************************************************************************/
  1004. void GenerateData(CONVCB * convptr)
  1005. {
  1006.   int i;
  1007.   int div;
  1008.   int rem;
  1009.   char * dptr;
  1010.  
  1011.   dptr = convptr->DataPtr;
  1012.   div = convptr->SendSize / 5;
  1013.   rem = convptr->SendSize % 5;
  1014.  
  1015.   for (; div--;)
  1016.   {
  1017.     for (i=4; i--; *dptr++ = datach);
  1018.     *dptr++ = '.';
  1019.   }
  1020.   for (; rem--; *dptr++ = datach);
  1021.  
  1022.   EnterCriticalSection(&runsem);
  1023.   datach = (datach=='Z' ? 'A' : datach + 1);
  1024.   LeaveCriticalSection(&runsem);
  1025. }
  1026.  
  1027. /*****************************************************************************/
  1028. /* ReadString - Get a line of text from the config file                      */
  1029. /*****************************************************************************/
  1030. int ReadString(char * lpValueName,char * lpData, int maxlen)
  1031. {
  1032.   char       buffer[200];
  1033.   char      *p = NULL;
  1034.   FILE      *h = NULL;
  1035.   BOOL       match = FALSE;
  1036.   BOOL       eof   = FALSE;
  1037.   int        rc = 0;
  1038.   int        ch = 0;
  1039.   int        i = 0;
  1040.   BOOL       gotdata = FALSE;
  1041.   char       separators[] = " =\t\n";
  1042.  
  1043.   GetModuleFileName( hInst, buffer, sizeof(buffer) );
  1044.   lstrcpy( buffer+lstrlen(buffer) - 4, ".CFG" );
  1045.   h = fopen( buffer, "r" );
  1046.   buffer[0] = '\0';
  1047.  
  1048.   lpValueName=strupr(lpValueName);
  1049.  
  1050.   if (h != NULL)
  1051.   {
  1052.     while ((!match) && (!eof))
  1053.     {
  1054.       /***********************************************************************/
  1055.       /* Use fgetc to read a line of text from the file                      */
  1056.       /***********************************************************************/
  1057.       for (i=0; (i<sizeof(buffer))     &&
  1058.                 ((ch=getc(h)) != EOF)  &&
  1059.                 ((char)ch != '\n');
  1060.                                    i++)
  1061.       {
  1062.         buffer[i] = (char)ch;
  1063.       }
  1064.       if ((char)ch == '\n')
  1065.       {
  1066.         buffer[i++] = (char)ch;
  1067.       }
  1068.       if (ch == EOF)
  1069.       {
  1070.         eof = TRUE;
  1071.       }
  1072.       else
  1073.       {
  1074.         /*********************************************************************/
  1075.         /* Compare the first token in the line read with the requested parm  */
  1076.         /*********************************************************************/
  1077.         if (!strcmpi(strupr(strtok(buffer, separators)), lpValueName))
  1078.         {
  1079.           match = TRUE;
  1080.           /*******************************************************************/
  1081.           /* Get a pointer to the second token (the value we want)           */
  1082.           /*******************************************************************/
  1083.           p = strtok(NULL, separators);
  1084.  
  1085.           /*******************************************************************/
  1086.           /* Copy the data IF there is some                                  */
  1087.           /*******************************************************************/
  1088.           if (p != NULL)
  1089.           {
  1090.             /*****************************************************************/
  1091.             /* Force a NULL after the second token                           */
  1092.             /*****************************************************************/
  1093.             strtok(NULL, separators);
  1094.  
  1095.             /*****************************************************************/
  1096.             /* Copy the data                                                 */
  1097.             /*****************************************************************/
  1098.             strncpy(lpData, p, maxlen);
  1099.             gotdata = TRUE;
  1100.           }
  1101.           else
  1102.           {
  1103.             gotdata = FALSE;
  1104.           }
  1105.         }
  1106.       }
  1107.     }
  1108.  
  1109.     if (gotdata)
  1110.     {
  1111.       rc = 1;
  1112.     }
  1113.  
  1114.     fclose(h);
  1115.  
  1116.   }
  1117.  
  1118.   return(rc);
  1119. }
  1120.  
  1121. /*****************************************************************************/
  1122. /* PadString - Remove terminating NULL  and pad on the right with spaces     */
  1123. /*****************************************************************************/
  1124. void PadString(char * string,int length)
  1125. {
  1126.   char * p;
  1127.   if ((p=memchr(string,'\0',length)) != NULL)
  1128.   {
  1129.     while (p < string+length)
  1130.     {
  1131.       *p++=' ';
  1132.     }
  1133.   }
  1134. }
  1135.  
  1136.