home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 April: Mac OS SDK / Dev.CD Apr 97 SDK1.toast / Development Kits (Disc 1) / Open Transport / Sample Code / DTS Sample Code / OTLLCTest / OTLLCTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-19  |  23.9 KB  |  945 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        OTLLCTest.c
  3.  
  4.     Contains:    Simple app write or receive 8022 Ethernet packets using a multicast address
  5.  
  6.     Written by:    Rich Kubota
  7.  
  8.     Copyright:    © 1993-1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     This program implements both a sender and receiver such that both sides
  13.     open an 802.2 Ethernet endpoint. The user can then select whether to run the 
  14.     program as a sender or receiver. If implemented as a receiver, the endpoint
  15.     is bound, and the multicast option is turned on. The receiver waits in a 
  16.     spin loop for a specified period of time before quitting.  The receiver will process
  17.     all incoming ethernet packets destined to the endpoint for the specified
  18.     protocol.  Upon receipt, the program checks to see whether the packet was sequential
  19.     to the previous packet.  A collection of global counter maintains the number of
  20.     inOrder, outOfOrder packets, and the number of packets reads resulting in an error,
  21.     plus the number of packets which come in back to back while in the handler.
  22.     
  23.     Note the this sample turns on the rawmode option so that the handler will be passed the
  24.     14 byte 802.2 header.
  25.     Also note that the sender may also implement the rawmode option so that it can also
  26.     fill in the header bytes itself.  If this is done, then the buffer needs to 
  27.     be enlarged to include these additional bytes.  These additional bytes will not affect
  28.     the maximum tsdu size since the tsdu size is the i-frame limit and does not include
  29.     the header size.
  30.     
  31.     The sender process, sends 10005 x 1496 byte packets as fast as possible.  The user 
  32.     can select to to turn on AckSends mode where the packet is handed to OT and not
  33.     released until OT sends the information to the lower layer. 
  34.     
  35.     
  36.  
  37. */
  38.  
  39. #include <stdio.h>
  40. #include <Types.h>
  41. #include <Memory.h>
  42. #include <Resources.h>
  43. #include <Events.h>
  44. #include <OpenTransport.h>            // open transport files            
  45. #include <OpenTptLinks.h>
  46. #include <Time.h>
  47. #include <Errors.h>
  48. #include "OTLLCTest.h"
  49.  
  50. //-----------------------------------------------------------------------------------------
  51. // Globals
  52. //-----------------------------------------------------------------------------------------
  53.  
  54. EndpointRef        gEndpoint;
  55. OSStatus        gstatus;
  56. UInt32            gFlags;
  57. UInt32            gPacketsRead;
  58. UInt32            gBackToBackPackets;    // counter of number of times a packet is read in addition to the first pcket
  59. UInt32            gInOrder;
  60. UInt32            gOutOfOrder;
  61. UInt32            gCounter;
  62. UInt32            gNumDataEvents;
  63. UInt32            gReadErrors;
  64. UInt8            *gBuffer;
  65. UInt8            *gDummyBuffer;
  66. Address8022     gAddr;
  67. UInt8            gmcAddr[k48BitAddrLength] = {MCASTADDR0,MCASTADDR1,MCASTADDR2,MCASTADDR3,MCASTADDR4,MCASTADDR5};
  68. Boolean            gDone;
  69. //-----------------------------------------------------------------------------------------
  70. // Prototypes
  71. //-----------------------------------------------------------------------------------------
  72. extern OSStatus DoNegotiateRawModeOption(EndpointRef ep, UInt32 rawModeOption);
  73. OSStatus         DoBind();
  74. OSStatus         DoAddMulticast(EndpointRef ep, unsigned char *mcAddr);
  75. OSStatus        DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr);
  76. void             WriteApplIntro(void);
  77. UInt32             GetYesNoOption(void);
  78. UInt32             GetUserOption(void);
  79. void            DoOTLLCWriteTest(void);
  80. void            DoOTLLCReadTest(void);
  81. OSStatus         DoReadPacket(EndpointRef ep, UInt8 *mainBuffer);
  82. pascal void     LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie);
  83. Boolean         IsPressed(unsigned short k, unsigned char *keyMap);
  84. Boolean         UserAbort(void);
  85. void             DoValueBreak(long value, const char* message);
  86.  
  87.  
  88. /*******************************************************************************
  89. ** DoBindENET
  90. ********************************************************************************/
  91.  
  92. OSStatus DoBind(void)
  93. {
  94.     OSStatus        osstatus;
  95.     TBind            requestInfo;
  96.     TBind            responseInfo;
  97.     UInt32            i;
  98.     
  99.     gAddr.fAddrFamily = AF_8022;
  100.     
  101.     for (i = 0; i < k48BitAddrLength; i++)
  102.         gAddr.fHWAddr[i] = 0x00;
  103.         
  104.     gAddr.fSAP = TESTSAP;
  105.         
  106.         // finish bind information
  107.     requestInfo.addr.buf = (UInt8 *)&gAddr;
  108.     requestInfo.addr.len = 10;        // family type + Ethernet + type field
  109.     requestInfo.addr.maxlen = 0;            
  110.     requestInfo.qlen = 0;
  111.     
  112.     responseInfo.addr.buf = (UInt8 *)&gAddr;
  113.     responseInfo.addr.len = 0;        
  114.     responseInfo.addr.maxlen = 10;    // family type + Ethernet + type field        
  115.     responseInfo.qlen = 0;
  116.     
  117.     
  118.     SetStillBindFlag(gFlags);
  119.     
  120.     if (osstatus = OTBind(gEndpoint, &requestInfo, &responseInfo))
  121.     {
  122.         printf("\nCould not bind an endpoint, error = %d\n", osstatus);
  123.         ClrStillBindFlag(gFlags);
  124.     }
  125.     else
  126.     {
  127.         while (TstStillBindFlag(gFlags))
  128.             OTIdle();
  129.         if (gstatus != kOTNoError)
  130.         {
  131.             printf("\nCould not bind an endpoint, error = %d\n", gstatus);
  132.             osstatus = gstatus;
  133.         }
  134.         SetEPBoundFlag(gFlags);
  135.     }
  136.     return osstatus;
  137. }
  138.  
  139.  
  140.  
  141. /*******************************************************************************
  142. ** DoAddMulticast
  143. ********************************************************************************/
  144.  
  145. OSStatus DoAddMulticast(EndpointRef ep, unsigned char *mcAddr)
  146. {
  147.     OSStatus    osstatus = noErr;
  148.     TOptMgmt     ret;
  149.     TOptMgmt    req;
  150.     UInt8        reqOpt[64];        
  151.     UInt8        retOpt[64];
  152.     
  153.     req.opt.buf    = reqOpt;
  154.     req.flags    = T_NEGOTIATE;
  155.  
  156.     ret.opt.buf        = retOpt;
  157.     ret.opt.maxlen    = sizeof(retOpt);
  158.     
  159.     ((TOption*)reqOpt)->level    = LNK_TPI;
  160.     ((TOption*)reqOpt)->name    = OPT_ADDMCAST;
  161.     ((TOption*)reqOpt)->len        = kOTOptionHeaderSize + k48BitAddrLength;
  162.     memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
  163.                 
  164.     req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
  165.                 
  166.     if ( (osstatus = OTOptionManagement(ep, &req, &ret)) != kOTNoError )
  167.         fprintf(stderr, "DoAddMulticast - OptionManagement Returned %d\n", osstatus);
  168.     else
  169.     {
  170.         fprintf(stderr, "DoAddMulticast - Option Status = %d\n", ((TOption*)retOpt)->status);
  171.         SetMCastActiveFlag(gFlags);
  172.     }
  173.     return osstatus;
  174. }
  175.  
  176.  
  177. /*******************************************************************************
  178. ** DoRemoveMulticast
  179. ********************************************************************************/
  180.  
  181. OSStatus DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr)
  182. {
  183.     OSStatus    osstatus = noErr;
  184.     TOptMgmt    ret;
  185.     TOptMgmt    req;
  186.     UInt8        reqOpt[64];        
  187.     UInt8        retOpt[64];
  188.     
  189.     req.opt.buf    = reqOpt;
  190.     req.flags    = T_NEGOTIATE;
  191.  
  192.     ret.opt.buf        = retOpt;
  193.     ret.opt.maxlen    = sizeof(retOpt);
  194.     
  195.     ((TOption*)reqOpt)->level    = LNK_TPI;
  196.     ((TOption*)reqOpt)->name    = OPT_DELMCAST;
  197.     ((TOption*)reqOpt)->len        = kOTOptionHeaderSize + k48BitAddrLength;
  198.     memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
  199.                     
  200.     req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
  201.     
  202.     if ( (osstatus = OTOptionManagement(ep, &req, &ret)) != kOTNoError )
  203.         fprintf(stderr, "\nDoRemoveMulticast - OptionManagement Returned %d.", osstatus);
  204.     else
  205.         fprintf(stderr, "\nDoRemoveMulticast - Option Status = %d.", ((TOption*)retOpt)->status);
  206.     return osstatus;
  207. }
  208.  
  209. void WriteApplIntro(void)
  210. {
  211.     fprintf(stderr, "\nEthernet 802.2 LLC Test program v1.0\n");
  212.     fprintf(stderr, "\nThis test application sets the system");
  213.     fprintf(stderr, "\ninto send or receive mode.\n");
  214.     fprintf(stderr, "\nThe send portion of this program sets the Ethernet");
  215.     fprintf(stderr, "\ndriver to use a multicast address, then sends 10000");
  216.     fprintf(stderr, "\n- 1500 byte packets out the wire.\n");
  217.     fprintf(stderr, "\nThe receive portion of this program sets the Ethernet");
  218.     fprintf(stderr, "\ndriver to use a multicast address, then waits for the");
  219.     fprintf(stderr, "\n10000 - 1500 byte packets or times out after 30 seconds.\n");
  220. }
  221.  
  222. UInt32 GetYesNoOption(void)
  223. {
  224.     UInt32    result;
  225.     char    selection[32];
  226.     Boolean    done;
  227.     
  228.     fprintf(stdout, "\n    Enter Y - To accept option");
  229.     fprintf(stdout, "\n    Enter N - To decline option");
  230.     fprintf(stdout, "\n    Enter Q - To quit");
  231.     fprintf(stdout, "\nYour selection -> ");
  232.     fflush(stdout);
  233.     done = false;
  234.  
  235.     do
  236.     {
  237.         scanf("%s", selection);
  238.         switch (selection[0])
  239.         {
  240.             case 'y':
  241.             case 'Y':
  242.                 result = kAcceptOption;
  243.                 done = true;
  244.                 break;
  245.             
  246.             case 'n':
  247.             case 'N':
  248.                 result = kDeclineOption;
  249.                 done = true;
  250.                 break;
  251.  
  252.             case 'q':
  253.             case 'Q':
  254.                 result = kQuitTest;
  255.                 done = true;
  256.                 break;
  257.                 
  258.             default:
  259.                 fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  260.                 fflush(stdout);
  261.                 break;
  262.  
  263.         }
  264.     } while (!done);
  265.     
  266.     fflush (stdout);
  267.     return result;
  268. }
  269.  
  270.  
  271. UInt32 GetUserOption(void)
  272. {
  273.     UInt32    result;
  274.     char    selection[32];
  275.     Boolean    done;
  276.     
  277.     fprintf(stdout, "\nSelect the type of test to run");
  278.     fprintf(stdout, "\nMake sure that the receive program is already launched");
  279.     fprintf(stdout, "\n    Enter S - Send test packets");
  280.     fprintf(stdout, "\n    Enter R - Receive test packets");
  281.     fprintf(stdout, "\n    Enter q - quit");
  282.     fprintf(stdout, "\nYour selection -> ");
  283.     fflush(stdout);
  284.     done = false;
  285.  
  286.     do
  287.     {
  288.         scanf("%s", selection);
  289.         switch (selection[0])
  290.         {
  291.             case 'r':
  292.             case 'R':
  293.                 result = kReceiveTest;
  294.                 done = true;
  295.                 break;
  296.             
  297.             case 's':
  298.             case 'S':
  299.                 result = kSendTest;
  300.                 done = true;
  301.                 break;
  302.  
  303.             case 'q':
  304.             case 'Q':
  305.                 result = kQuitTest;
  306.                 done = true;
  307.                 break;
  308.                 
  309.             default:
  310.                 fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  311.                 fflush(stdout);
  312.                 break;
  313.  
  314.         }
  315.     } while (!done);
  316.     
  317.     fflush (stdout);
  318.     return result;
  319. }
  320.  
  321. void DoOTLLCWriteTest(void)
  322. {
  323.     OSStatus    osstatus;
  324.     TUnitData    unitdata;
  325.     UInt32        i;
  326.     time_t        t1, t2, t3;
  327.     Address8022    dAddr;
  328.     UInt16        rawModeOffset = 0;
  329.     UInt8        data[DATASIZE+14];    // set data to be DATASIZE + space for rawmode header
  330.     
  331.     
  332.     osstatus = DoBind();
  333.  
  334.     if (TstUseAckSendsFlag(gFlags))
  335.         osstatus = OTAckSends(gEndpoint);
  336.  
  337.     if (TstUseRawModeFlag(gFlags))
  338.     {
  339.         osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn);
  340.         if (osstatus == kOTNoError)
  341.         {
  342.             SetRawModeFlag(gFlags);
  343.                 // if rawmode is on then we want to offset the data
  344.                 // an additional 17 bytes and set the header info
  345.                 // ourselves.
  346.                 // note that 17 bytes constitutes the 6 byte dAddr, 6 byte sAddr
  347.                 // 2 byte length field, 1 byte ssap, 1 byte dsap and 1 byte control byte
  348.             
  349.                         
  350.             rawModeOffset = 17;
  351.         }
  352.         else
  353.         {
  354.                 // if the option failed, then we don't use it'
  355.             fprintf (stdout, "\nError negotiating raw mode option");
  356.                 // reset the status result.
  357.             osstatus = kOTNoError;
  358.         }
  359.     }
  360.         
  361.     if (osstatus == kOTNoError)
  362.     {
  363.             // set up the first 12 bytes past the control byte, so that we can recognize them
  364.         data[0 + rawModeOffset] = 1;
  365.         data[1 + rawModeOffset] = 2;
  366.         data[2 + rawModeOffset] = 3;
  367.         data[3 + rawModeOffset] = 4;
  368.         data[4 + rawModeOffset] = 5;
  369.         data[5 + rawModeOffset] = 6;
  370.         data[6 + rawModeOffset] = 7;
  371.         data[7 + rawModeOffset] = 8;
  372.         data[8 + rawModeOffset] = 9;
  373.         data[9 + rawModeOffset] = 10;
  374.         data[10 + rawModeOffset] = 11;
  375.         data[11 + rawModeOffset] = 12;
  376.  
  377.             // set up some specific bytes in the data buffer
  378.         data[DATAOFFSET+0 + rawModeOffset] = 0;
  379.         data[DATAOFFSET+1 + rawModeOffset] = 0;
  380.         data[DATAOFFSET+2 + rawModeOffset] = 'L';
  381.         data[DATAOFFSET+3 + rawModeOffset] = 'A';
  382.         data[DATAOFFSET+4 + rawModeOffset] = 'S';
  383.         data[DATAOFFSET+5 + rawModeOffset] = 'T';
  384.         data[DATAOFFSET+6 + rawModeOffset] = 1;
  385.         data[DATAOFFSET+7 + rawModeOffset] = 2;
  386.         data[DATAOFFSET+8 + rawModeOffset] = 3;
  387.         data[DATAOFFSET+9 + rawModeOffset] = 4;
  388.         data[DATAOFFSET+10 + rawModeOffset] = 5;
  389.         data[DATAOFFSET+11 + rawModeOffset] = 6;
  390.         
  391.         
  392.         unitdata.udata.buf = (UInt8*)data;
  393.     
  394.         if (TstRawModeFlag(gFlags))
  395.             unitdata.udata.len = DATASIZE + 14;
  396.         else
  397.             unitdata.udata.len = DATASIZE;
  398.         unitdata.opt.len = 0;
  399.         unitdata.opt.buf = NULL;
  400.  
  401.         if (TstUseRawModeFlag(gFlags) == false)
  402.         {
  403.                 // set up the destination addresss
  404.             dAddr.fAddrFamily = AF_8022;
  405.             
  406.             dAddr.fHWAddr[0] = MCASTADDR0;
  407.             dAddr.fHWAddr[1] = MCASTADDR1;
  408.             dAddr.fHWAddr[2] = MCASTADDR2;
  409.             dAddr.fHWAddr[3] = MCASTADDR3;
  410.             dAddr.fHWAddr[4] = MCASTADDR4;
  411.             dAddr.fHWAddr[5] = MCASTADDR5;
  412.                 
  413.             dAddr.fSAP = TESTSAP;
  414.         
  415.             unitdata.addr.buf = (UInt8*)&dAddr;
  416.             unitdata.addr.len = 10;    // size of the dAddr to include address type, address and sap
  417.         }
  418.         else
  419.         {
  420.                 // set up for a rawmode send data call
  421.             data[0] = MCASTADDR0;
  422.             data[1] = MCASTADDR1;
  423.             data[2] = MCASTADDR2;
  424.             data[3] = MCASTADDR3;
  425.             data[4] = MCASTADDR4;
  426.             data[5] = MCASTADDR5;
  427.                 // set the packet len field
  428.             data[12] = DATASIZE >> 8;
  429.             data[13] = DATASIZE & 0xFF;
  430.                 // set the dsap, ssap, and control byte fields.
  431.             data[14] = TESTSAP;            // set DSAP
  432.             data[15] = TESTSAP;            // set SSAP
  433.             data[16] = 0x03;            // set control byte
  434.         
  435.             unitdata.addr.buf = nil;    // don't want to set the destination address since we've already 
  436.                                         // done so in the data
  437.             unitdata.addr.len = 0;        // no addr field data to send
  438.             
  439.         }
  440.  
  441.  
  442.         fprintf (stdout, "\n starting write of %ld llc packets of %ld bytes\n", (long)SENDCOUNT, (long)DATASIZE);
  443.         fflush(stdout);
  444.         t1 = clock ();
  445.         
  446.         gDone = false;
  447.         i = 0;
  448.         while (!gDone)
  449.         {
  450.             SetStillSendFlag(gFlags);    // set flag to indicate we have not completed writing our packet
  451.             ClrFlowClrFlag(gFlags);        // clear the flag that indicates that a T_GODATA event occurred
  452.                                         // we do this because a race condition might occur when we make the
  453.                                         // the OTSndUData call, a flowerr may occur, but get cleared by the time
  454.                                         // we actually check the osstatus field
  455.             osstatus = OTSndUData(gEndpoint, &unitdata);
  456.                         
  457.             switch (osstatus)
  458.             {
  459.                 case kENOMEMErr:
  460.                     fprintf(stderr, "\nkENOMEMErr %d.", i);
  461.                     gDone = UserAbort();
  462.                     OTIdle();        // ran out of memory so idle
  463.                     break;
  464.                     
  465.                 case kOTNoError:    // send was successful
  466.                     if (TstUseAckSendsFlag(gFlags))
  467.                     {
  468.                         while (TstAckSendsFlag(gFlags))    // if ack sends on, then wait until the T_MEMORYRELEASED event occurs
  469.                             gDone = UserAbort();        // which will clear the AckSendsFlag bit.
  470.                     }
  471.                         
  472.                     i++;
  473.                     if (i >= SENDCOUNT)
  474.                         gDone = true;
  475.                     else
  476.                     {
  477.                         data[DATAOFFSET+0+rawModeOffset] = i >> 8;
  478.                         data[DATAOFFSET+1+rawModeOffset] = i;
  479.                             
  480.                             // for test purposes, set the very last 2 bytes of the packet with count
  481.  
  482.                         data[DATASIZE-2+rawModeOffset] = i >> 8;
  483.                         data[DATASIZE-1+rawModeOffset] = i;
  484.                             // go back around and send another packet
  485.                     }
  486.                     break;
  487.                 
  488.                 case kOTFlowErr:
  489.                     if (!TstFlowClrFlag(gFlags))
  490.                     {
  491.                         SetFlowErrFlag(gFlags);    // a T_GODATA did not just come in
  492.                         fprintf(stderr, "\nflow error occurred while sending packet %d.", i);
  493.                         while (TstFlowErrFlag(gFlags) && !gDone)
  494.                         {
  495.                             gDone = UserAbort();
  496.                         }
  497.     
  498.                     }
  499.                     else    // a T_GODATA event snuck in on us
  500.                         ClrFlowErrFlag(gFlags);
  501.                     break;
  502.                 
  503.                 default:
  504.                     gDone = true;
  505.                     fprintf(stderr, "\nOTSndUData error returned %d\n", osstatus);
  506.                     fprintf(stderr, "\nwhile sending packet %d.", i);
  507.                     ClrStillSendFlag(gFlags);
  508.                     break;
  509.             }
  510.  
  511.             
  512.         }    // end while loop sending data
  513.         
  514.         t2 = clock();
  515.         t3 = t2 - t1;
  516.         fprintf (stdout, "\nCompleted sending %ld llc packets.", (long)SENDCOUNT);
  517.         fprintf (stdout, "\nTime start = %ld, time end = %ld, time taken %ld seconds.",
  518.                      t1, t2, (long)t3/CLOCKS_PER_SEC);
  519.         fprintf (stdout, "\nPackets per second = %ld, bytes/second = %ld.",
  520.                      ((long)SENDCOUNT*CLOCKS_PER_SEC)/t3, ((long)SENDCOUNT*DATASIZE*CLOCKS_PER_SEC)/t3);
  521.          
  522.         fflush(stdout);
  523.         
  524.         
  525.     }    // end if bind successful
  526.     
  527.     if (TstEPBoundFlag(gFlags))
  528.     {
  529.         OTSetSynchronous(gEndpoint);
  530.         OTUnbind(gEndpoint);
  531.     }
  532. }
  533.  
  534. void DoOTLLCReadTest(void)
  535. {
  536.     OSStatus    osstatus;
  537.     long        timer;
  538.     
  539.     gBuffer = (UInt8*)NewPtr(DATASIZE + 2* DATASLOP);    // allocate the data buffer + some slop
  540.     if (gBuffer)
  541.         osstatus = DoBind();
  542.     else
  543.     {
  544.         osstatus = memFullErr;
  545.         return;
  546.     }
  547.  
  548.     gBackToBackPackets = 0;
  549.     gInOrder = 0;
  550.     gOutOfOrder = 0;
  551.     gCounter = 0;
  552.     gPacketsRead = 0;
  553.     gNumDataEvents = 0;
  554.     gReadErrors = 0;
  555.     gDone = false;
  556.     
  557.     if (osstatus == kOTNoError)
  558.     {
  559.         SetWaitOptMgmtFlag(gFlags);
  560.         osstatus = DoAddMulticast(gEndpoint, gmcAddr);
  561.         while(TstWaitOptMgmtFlag(gFlags));
  562.     }
  563.     
  564.     if (osstatus == kOTNoError)
  565.     {
  566.         if (TstUseRawModeFlag(gFlags))
  567.         {
  568.             osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn);
  569.             if (osstatus == kOTNoError)
  570.             {
  571.                 SetRawModeFlag(gFlags);
  572.             }
  573.             else
  574.             {
  575.                     // if the option failed, then we don't use it'
  576.                 fprintf (stdout, "\nError negotiating raw mode option");
  577.                     // reset the status result.
  578.                 osstatus = kOTNoError;
  579.             }
  580.         }
  581.     }
  582.     
  583.     if (osstatus == kOTNoError)
  584.     {
  585.         SetWantDataFlag(gFlags);
  586.                 
  587.         fprintf (stdout, "\nStarting Read test - will terminate in %d seconds", TIMEOUT);
  588.         fprintf (stdout, "\nor as soon as the trigger packet is received.");
  589.         fprintf (stdout, "\nYou may also use Command . to end this test");
  590.         fprintf (stdout, "\nStarting Read");
  591.         fflush(stdout);
  592.         
  593.         timer = TickCount() + TIMEOUT * 60;
  594.             // loop until timer is less than TickCount or until the endtime value gets set
  595.         
  596.         while ((timer > TickCount()) && (gDone == false))
  597.         {
  598.                 // allow the user to exit the timer loop by 
  599.             gDone = UserAbort();
  600.         }
  601.  
  602.         
  603.         
  604.     }
  605.     
  606.     OTSetSynchronous(gEndpoint);
  607.         
  608.     if (TstMCastActiveFlag(gFlags))
  609.         DoRemoveMulticast(gEndpoint, gmcAddr);
  610.         
  611.     
  612.     if (osstatus == kOTNoError)
  613.     {
  614.         fprintf (stdout, "\n\nBufferReadCount = %ld", gPacketsRead);
  615.         fprintf (stdout, "\nInOrder = %ld\n", gInOrder);
  616.         fprintf (stdout, "\nOutofOrder = %ld\n", gOutOfOrder);
  617.         fprintf (stdout, "\nlast packet read was = %ld\n", gCounter);
  618.         fprintf (stdout, "\nNumber of data events was = %ld\n", gNumDataEvents);
  619.         fprintf (stdout, "\nNumber of read errors was = %ld\n", gReadErrors);
  620.         fprintf (stdout, "\nNumber of back to back packets was = %ld\n", gBackToBackPackets);
  621.         fflush(stdout);
  622.     }
  623.  
  624.     if (TstEPBoundFlag(gFlags))
  625.         OTUnbind(gEndpoint);
  626.  
  627.     if (gBuffer)
  628.         DisposePtr((Ptr)gBuffer);
  629.     
  630. }
  631.  
  632. OSStatus DoReadPacket(EndpointRef ep, UInt8 *mainBuffer)
  633. {
  634.     TUnitData    unitdata;
  635.     Address8022    dAddr;
  636.     OTFlags        otFlags;
  637.     OSStatus    result, tempResult;
  638.     
  639.     unitdata.addr.maxlen = 10;
  640.     unitdata.addr.buf = (UInt8*)&dAddr;
  641.     unitdata.udata.buf = mainBuffer;
  642.     unitdata.udata.maxlen = DATASIZE + DATASLOP;
  643.     unitdata.opt.maxlen = 0;
  644.     
  645.     result = OTRcvUData(ep, &unitdata, &otFlags);
  646.     return result;
  647. }
  648.  
  649. pascal void LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie)
  650. {
  651.     OSStatus    osstatus;
  652.     UInt8        *bufferToUse;
  653.     UInt32        lcounter, offset;
  654.     Boolean        firstTimeFlag;
  655.     
  656.     gstatus = result;
  657.     switch (event)
  658.     {
  659.         case T_MEMORYRELEASED:
  660.             ClrAckSendsFlag(gFlags);
  661.             break;
  662.  
  663.         case T_OPTMGMTCOMPLETE:
  664.             ClrWaitOptMgmtFlag(gFlags);
  665.             break;
  666.             
  667.         case T_BINDCOMPLETE:
  668.             ClrStillBindFlag(gFlags);
  669.             break;
  670.         
  671.         case T_UNBINDCOMPLETE:
  672.             break;
  673.         
  674.         case T_GODATA:
  675.             DebugStr("\pFlow Control occurred;g");
  676.             SetFlowClrFlag(gFlags);    // indicate that the flow data problem has now cleared.
  677.             break;
  678.         
  679.         case T_DATA:
  680.             gNumDataEvents++;
  681.             if (TstWantDataFlag(gFlags))
  682.                 bufferToUse = gBuffer;
  683.             else
  684.                 bufferToUse = gDummyBuffer;
  685.                 
  686.                 // initialize variables as we enter while loop
  687.             osstatus = kOTNoError;
  688.             firstTimeFlag = true;
  689.             
  690.             while ((osstatus == kOTNoError) && (!gDone))
  691.             {
  692.                 osstatus = DoReadPacket(gEndpoint, bufferToUse);
  693.                 
  694.                 if (firstTimeFlag == true)    
  695.                         // this is the first time through this loop 
  696.                         // for this call to the handler
  697.                     firstTimeFlag = false;
  698.                 else
  699.                         // increment the counter to indicate that there was a packet to
  700.                         // handle after reading the previous packet
  701.                     gBackToBackPackets++;
  702.                     
  703.                 if (osstatus != kOTNoDataErr)
  704.                 {
  705.                     if (osstatus < 0)
  706.                         gReadErrors++;
  707.                     else
  708.                         gPacketsRead++;
  709.                 }
  710.                     
  711.                 if (TstWantDataFlag(gFlags) && (osstatus == kOTNoError))
  712.                 {
  713.                     if (TstRawModeFlag(gFlags))
  714.                             // if rawmode is on then we want to account for
  715.                             // the additional 17 bytes which will be at the
  716.                             // beginning of the packet.
  717.                         offset = 17;
  718.                     else
  719.                         offset = 0;
  720.                     
  721.                     lcounter = gBuffer[DATAOFFSET + offset +0] << 8;
  722.                     lcounter |= gBuffer[DATAOFFSET + offset +1];
  723.                     if (lcounter >= TRIGGEREND)
  724.                     {
  725.                         gDone = true;        // we can bail now.
  726.                     }
  727.                     else
  728.                     {
  729.                         if (lcounter == gCounter)
  730.                             gInOrder++;
  731.                         else
  732.                             gOutOfOrder++;
  733.                         
  734.                         gCounter = lcounter + 1;    // prepare gCounter for next incoming packet to compare
  735.                     }
  736.                 }
  737.             }
  738.             break;
  739.             
  740.         default:
  741.             DoValueBreak(event, "Unknown event  occurred #           ;g");
  742.             break;
  743.             
  744.         
  745.     }    /* end switch on event */
  746. }
  747.  
  748. /*******************************************************************************
  749. ** IsPressed
  750. ********************************************************************************/
  751.  
  752. Boolean IsPressed(unsigned short k, unsigned char *keyMap)
  753. {
  754.     return (keyMap[k >> 3] >> (k & 7) & 1);
  755. }
  756.  
  757. /*******************************************************************************
  758. ** CmdKey
  759. ********************************************************************************/
  760.  
  761. Boolean UserAbort()
  762. {
  763.     unsigned char     keyMap[16];
  764.     EventRecord     event;
  765.     Boolean         result;
  766.     
  767.     GetKeys((unsigned long*)keyMap);
  768. //    GetKeys(( long*)keyMap);
  769.     if ( IsPressed(0x37, keyMap) && // is command period or esc key hit
  770.         (IsPressed(0x2F, keyMap) || IsPressed(0x41, keyMap)) )
  771.         result =  true;
  772.     else
  773.         result = false;
  774.  
  775.     return result;
  776. }
  777.  
  778. main (void)
  779. {
  780.     OSStatus    osstatus = noErr;
  781.     UInt32        selection;
  782.     
  783.     WriteApplIntro();
  784.     gFlags = 0;
  785.     if (osstatus = InitOpenTransport())
  786.     {
  787.         fprintf(stderr, "\n\nOpen Transport is not installed!\n");
  788.         fprintf(stderr, "\nBye Bye.\n");
  789.     }
  790.     else
  791.     {
  792.         SetOTActiveFlag(gFlags);    // indicate that OT is active
  793.  
  794.         gDummyBuffer = (UInt8*)NewPtr(DATASIZE + 2 * DATASLOP);
  795.         if (gDummyBuffer == NULL)
  796.             osstatus = memFullErr;
  797.     }
  798.         
  799.     if (osstatus == kOTNoError)
  800.     {
  801.             // open the default ethernet endpoint
  802.         gEndpoint = OTOpenEndpoint(OTCreateConfiguration(kEnetName), (OTOpenFlags)NULL, NULL, &osstatus);
  803.         if (osstatus != kOTNoError)
  804.         {
  805.             fprintf(stderr, "\n\nError opening Ethernet endpoint!");
  806.             fprintf(stderr, "\nOTOpenEndpoint returned %d\n", osstatus);
  807.             fprintf(stderr, "\nBye Bye.\n");
  808.         }
  809.         else
  810.             SetEPActiveFlag(gFlags);    // indicate that the endpoint is opened
  811.     }    
  812.     
  813.     if (osstatus == kOTNoError)
  814.     {
  815.         osstatus = OTInstallNotifier(gEndpoint, LLCEventHandler, NULL);
  816.         if (osstatus != kOTNoError)
  817.         {
  818.             fprintf(stderr, "\n\nError installing notifier!");
  819.             fprintf(stderr, "\nOTInstallNotifier returned %d\n", osstatus);
  820.         }
  821.     }    // now ready to handle async events
  822.     
  823.     if (osstatus == kOTNoError)
  824.     {
  825.         osstatus = OTSetAsynchronous(gEndpoint);
  826.         if (osstatus != kOTNoError) 
  827.         {
  828.             fprintf(stderr, "\n\nError making endpoint asynchronous!");
  829.             fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
  830.         }
  831.     }    // now ready to handle async events
  832.         
  833.     if (osstatus == kOTNoError)
  834.     {
  835.             // ask whether to use the rawmode option or not
  836.         fprintf(stdout, "\nDo you want to use the raw mode option?");
  837.         selection = GetYesNoOption();
  838.         if (selection == kQuitTest)
  839.         {
  840.             fprintf(stderr, "\n\nBye-Bye!");
  841.             osstatus = -1;
  842.         }
  843.         else if (selection == kAcceptOption)
  844.             SetUseRawModeFlag(gFlags);
  845.     }
  846.     
  847.     if (osstatus == kOTNoError)
  848.     {
  849.             
  850.             // what does the user want to do
  851.         selection = GetUserOption();
  852.         
  853.         switch (selection)
  854.         {
  855.             case kSendTest:
  856.                 fprintf(stdout, "\nDo you want to turn on AckSends?");
  857.                 selection = GetYesNoOption();
  858.                 if (selection == kQuitTest)
  859.                 {
  860.                     fprintf(stderr, "\n\nBye-Bye!");
  861.                     break;
  862.                 }
  863.                 else if (selection == kAcceptOption)
  864.                     SetUseAckSendsFlag(gFlags);
  865.  
  866.                 DoOTLLCWriteTest();
  867.                 break;
  868.             
  869.             case kReceiveTest:
  870.                 DoOTLLCReadTest();
  871.                 break;
  872.             
  873.             case kQuitTest:
  874.             default:
  875.                 fprintf(stderr, "\n\nBye-Bye!");
  876.                 break;
  877.         }
  878.     }
  879.     
  880.         // force endpoint to be synchronous
  881.     OTSetSynchronous(gEndpoint);
  882.     
  883.     if (TstEPActiveFlag(gFlags))
  884.         OTCloseProvider(gEndpoint);
  885.     
  886.     if (gDummyBuffer)
  887.         DisposePtr((Ptr)gDummyBuffer);
  888.         
  889.     if (TstOTActiveFlag(gFlags))
  890.         CloseOpenTransport();
  891.     
  892.     fprintf(stderr, "\nProgram ended");
  893. }
  894.  
  895. void DoValueBreak(long value, const char* message)
  896. {
  897.     static short    sDoErrorBreak = 0;
  898.  
  899.     {
  900.         Str255    s,
  901.                 n = "\p";
  902.  
  903.         s[0] = strlen(message);
  904.         BlockMoveData(message,&s[1],s[0]);
  905.         if (value < 0)
  906.         {
  907.             s[0] += 1;
  908.             s[s[0]] = '-';
  909.             value = -value;
  910.         }
  911.         while (value)
  912.         {
  913.             if (n[0])
  914.                 BlockMoveData(&n[1],&n[2],n[0]);
  915.             n[0]++;
  916.             n[1] = 48 + (value % 10);
  917.             value /= 10;
  918.         }
  919.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  920.         s[0] += n[0];
  921.  
  922.         sDoErrorBreak++;
  923.         {
  924.             short    cnt = sDoErrorBreak;
  925.  
  926.             s[0]++;
  927.             s[s[0]] = ',';
  928.             s[0]++;
  929.             s[s[0]] = ' ';
  930.             n[0] = 0;
  931.             while (cnt)
  932.             {
  933.                 if (n[0])
  934.                     BlockMoveData(&n[1],&n[2],n[0]);
  935.                 n[0]++;
  936.                 n[1] = 48 + (cnt % 10);
  937.                 cnt /= 10;
  938.             }
  939.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  940.             s[0] += n[0];
  941.         }
  942.         DebugStr(s);
  943.     }
  944. }
  945.