BSDLLCTest.c

/*
    File:       BSDLLCTest.c
 
    Contains:   Simple app write or receive 8022 Ethernet packets using a raw mode socket
 
    Copyright:  Copyright (c) 1998-2003 by Apple Computer, Inc., All Rights Reserved.
 
    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
 ("Apple") in consideration of your agreement to the following terms, and your
 use, installation, modification or redistribution of this Apple software
 constitutes acceptance of these terms.  If you do not agree with these terms,
 please do not use, install, modify or redistribute this Apple software.
 
 In consideration of your agreement to abide by the following terms, and subject
 to these terms, Apple grants you a personal, non-exclusive license, under Appleƕs
 copyrights in this original Apple software (the "Apple Software"), to use,
 reproduce, modify and redistribute the Apple Software, with or without
 modifications, in source and/or binary forms; provided that if you redistribute
 the Apple Software in its entirety and without modifications, you must retain
 this notice and the following text and disclaimers in all such redistributions of
 the Apple Software.  Neither the name, trademarks, service marks or logos of
 Apple Computer, Inc. may be used to endorse or promote products derived from the
 Apple Software without specific prior written permission from Apple.  Except as
 expressly stated in this notice, no other rights or licenses, express or implied,
 are granted by Apple herein, including but not limited to any patent rights that
 may be infringed by your derivative works or by other works in which the Apple
 Software may be incorporated.
 
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
 COMBINATION WITH YOUR PRODUCTS.
 
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 *
*/
#include "BSDLLCTest.h"
#include "GetEthernetAddrSample.h"
#include "EthernetSocketStuff.h"
#include "MoreUNIX.h"
 
enum {
    kDestAddressField = 1,
    kDSAPField = 2,
    kSNAPField = 3,
    kNumPacketsField = 4,
    kSendTimeField = 5,
    kTransferRateField = 6,
    kNumPacketsReceivedField = 7,
    kNumPacketsInOrderField = 8,
    kNumPacketsOutOfOrderField = 9,
    kLastPacketReceivedField = 10,
    kDoTestButton = 11,
    kSendReceiveButton = 12,
    kSNAPLabel = 13,
    kSourceAddressField = 14,
    kDestAddressIsMCast = 15,
    kEnetPopupButton = 16,
    kCancelTestButton = 17,
    kAboutAppNameText = 18,
    kAboutVersionText = 19,
    kQuitButton = 20,
    kLastItem
};
 
#define kMaxInputSize   32
 
//-----------------------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------------------
IBNibRef            gNibRef;
WindowRef           gMainWindow;
WindowRef           gAboutWindow;
EventLoopRef        gMainLoop;
EventLoopTimerUPP   gTimerUPP;
EventLoopTimerRef   gTimerRef;
EventHandlerUPP     gMyDoTestButtonInterceptorUPP;
EventHandlerUPP     gMyDoCancelTestButtonInterceptorUPP;
EventHandlerUPP     gMySendRcvButtonInterceptorUPP;
EventHandlerUPP     gMyAppCommandInterceptorUPP;
EventHandlerUPP     gMyEnetPopupCommandInterceptorUPP;
EventHandlerUPP     gMyDestAddrIsMCastInterceptorUPP;
EnetData            gedata[kMaxEnetEntries];
EnetTestData        gTestData;
EnetTestData        *gEnetTestData = &gTestData;
UInt32              gNumEnetEntries = kMaxEnetEntries;
UInt32              gCurrPopupEntry = 1;
UInt32              gVerMacOS;
MACAddress          gDestAddr = {MCASTADDR0, MCASTADDR1, MCASTADDR2, MCASTADDR3, MCASTADDR4, MCASTADDR5};
MACAddress          gBroadcastAddr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
UInt16              gSAPAddr = DEFAULTSAP;
UInt8               gSNAPAddr[5] = {MYSNAP0, MYSNAP1, MYSNAP2, MYSNAP3, MYSNAP4};
UInt32              gSendRcvState = kSendTest;  // indicates the current state of the test
UInt32              gNumPacketsToHandle = DEFAULT_NUM_PACKETS_TO_SEND;
UInt32              gFlags;
int                 gshmid;
Boolean             gDestAddrIsMCast;
Boolean             gDone;
Boolean             gAbort = FALSE;
//-----------------------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------------------
pascal void TimerAction(EventLoopTimerRef theTimer, void *userData);
UInt32   MyNumToHexString(UInt32 num, char *str);
OSStatus MyHexStringToNum(char *str, UInt32 *num);
OSStatus MyStringToNum(char *str, SInt32 *num);
UInt32   MyNumToString(UInt32 num, char *str, Boolean negative);
OSStatus GetSAPFieldValue(UInt16 *sap);
OSStatus SetSAPFieldValue(UInt16 sap);
OSStatus GetSNAPFieldValue(UInt8 *snap);
OSStatus SetSNAPFieldValue(UInt8 *sap);
OSStatus GetNumPacketsField(UInt32 *numPackets);
OSStatus SetSendStatistics(UInt32 numPackets, UInt32 sendTime);
OSStatus SetReceiveStatistics(UInt32 packetsReceived, UInt32 PacketsInOrder, 
                                UInt32 PacketsOutOfOrder, UInt32 lastPacketReceived);
OSStatus LoadMainWindowFromNibFile(IBNibRef gNibRef);
OSStatus LoadAboutWindowFromNibFile(IBNibRef gNibRef);
OSStatus EnetStrToAddr(char *str, MACAddress *eaddr);
int      EnetAddrToString(MACAddress *eaddr, char *str);
OSStatus SetEthernetAddressField(SInt32 id, MACAddress *eaddr);
OSStatus SetResults(EnetTestData *enetTestData);
OSStatus MyDoCancelTestButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
OSStatus MyDestAddrIsMCastInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
OSStatus MyDoTestButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
void     AddEnetServicesToPopupMenu(EnetData *enetdata);
void     SetActiveEnetPopupMenu(UInt16 menuItem);
OSStatus MyEnetPopupButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
OSStatus MySendRcvButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
OSStatus MyAppCommandInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData);
 
void     Initialize(void);  /* function prototypes */
void     DisposeUPPs();
 
/*******************************************************************************
** Initialize
** Do stuff like InitCursor
********************************************************************************/
void Initialize()   /* Initialize some managers */
{
    OSErr   err;
        
    InitCursor();       
    
    err = Gestalt(gestaltSystemVersion, &gVerMacOS);
    if (err != noErr)
        ExitToShell();
    else
    {
        fprintf(stderr, "Version of Mac OS is %X\n", (int)gVerMacOS);
        if (gVerMacOS <= 0x1015)
        {
            fprintf(stderr, "The MultiCast option for a receive socket is not supported in this release\n");
            fprintf(stderr, "This release of the OS support a max packet size of 1499 bytes only\n");
        }
    }
    // init the gedata array
    memset(gedata, 0, sizeof(gedata));
 
    // SIGPIPE bad.
    // refer to the MoreAuthSample code for the use of MoreUNIXIgnoreSIGPIPE
    err = EXXXToOSStatus( MoreUNIXIgnoreSIGPIPE() );
}
 
 
pascal void TimerAction(EventLoopTimerRef theTimer, void *userData)
{   
    if (gSendRcvState == kCancelTest)
    {
        SetResults(gEnetTestData);
    }
}
 
 
/*
    MyNumToHexString takes a UInt32 value and creates a hex string with the 
    "0x" prefix
*/
UInt32 MyNumToHexString(UInt32 num, char *str)
{
    UInt32  n, i, j, digit;
    char    tmp[16];
 
    n = num;
    i = j = 0;
    
    while (n)
    {
         // create an inverted string
        digit = n % 0x10;
        if (digit < 10)
            tmp[j++] = '0' + digit;
        else
            tmp[j++] = 'A' + digit - 10;
 
        n /= 0x10;
    }
    
    // insert the string prefix
    str[i++] = '0';
    str[i++] = 'x';
    // inssert the string
    while (j != 0)
    {
        str[i++] = tmp[--j];
    }
    // set null termination of the string
    str[i] = 0;
    return i;
}
 
/*
    MyHexStringToNum converts a str - a "C" style string which can be prefixed with "0x"
    or 'x' and returns the value in num
*/
OSStatus MyHexStringToNum(char *str, UInt32 *num)
{
    UInt32  i, len;
    UInt32  digit;
    
    // intialize the *num to 0
    *num = 0;
    
    len = strlen(str);
    
    if (str[0] == 'x' || str[0] == 'X')
    {
        if (len > 9)
            return -1;  // string to long to fit into a UInt32 result
        else
            i = 1;
    }
    else if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
    {
        if (len > 10)
            return -1;  // string to long to fit into a UInt32 result
        else
            i = 2;
    }
    else
    {
        if (len > 8)
            return -1;  // string to long to fit into a UInt32 result
        else
            i = 0;
    }
    
    while (i < len)
    {
        digit = str[i++];
        if (digit >= '0' && digit <= '9')
            digit -= '0';
        else if (digit >= 'A' && digit <= 'F')
        {
            digit += 10;
            digit -= 'A';
        }
        else if (digit >= 'a' && digit <= 'f')
        {
            digit += 10;
            digit -= 'a';
        }
        else    // an illegal character is in the string
            return -1;
        *num = *num * 0x10 + digit;
    }
    return noErr;
}
 
OSStatus MyStringToNum(char *str, SInt32 *num)
{
    UInt32  i, len;
    UInt32  digit;
    Boolean isNegative = false;
    
    i = 0;
    *num = 0;
    len = strlen(str);
    
    if (str[i] == '-')
    {
        isNegative = true;
        i++;
    }
    while (i < len)
    {
        if (str[i] >= '0' && str[i] <= '9')
            digit = str[i] - '0';
        else
            return -1;
        *num = *num * 10 + digit;
        i++;
    }
    if (isNegative)
        *num *= -1;
        
    return noErr;
}
 
UInt32 MyNumToString(UInt32 num, char *str, Boolean negative)
{
    UInt32  n, i, j;
    char    tmp[16];
    
    n = num;
    i = j = 0;
    
    if (negative)
        str[i] = '-';
    
    if (n != 0)
    {
        while (n)
        {
            // create an inverted string
            tmp[j++] = '0' + (n % 10);
            n /= 10;
        }
    }
    else
        tmp[j++] = '0';
    
    // now move the inverted string into the str
    while (j != 0)
    {
        str[i++] = tmp[--j];
    }
    // set null termination of the string
    str[i] = 0;
    return i;
}
 
OSStatus GetSAPFieldValue(UInt16 *sap)
{
    ControlID   controlID = { kTestSignature, kDSAPField };
    ControlRef  control;
    UInt32  len;
    OSStatus    err = noErr;
    UInt32  value;
    char    str[16];
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    
    err = GetControlData(control, kControlNoPart, kControlEditTextTextTag,
                        sizeof(str), str, &len);
    require_noerr(err, CantGetControlData);
    str[len] = 0;
    
    err = MyHexStringToNum(str, &value);
    require_noerr(err, InvalidData);
    *sap = value;
    return noErr;
     
InvalidData:
    fprintf(stderr, "Invalid hx data in control %ld\n", controlID.id);
    return err;    
CantGetControlData:
    fprintf(stderr, "Unable to find control data - control %ld, error was %d\n", controlID.id, (int)err);
    return err;    
CantGetControlByID:
    fprintf(stderr, "Unable to find control ID %ld, error was %d\n", controlID.id, (int)err);
    return err;    
}
 
OSStatus SetSAPFieldValue(UInt16 sap)
{
    ControlID   controlID = { kTestSignature, kDSAPField };
    ControlRef  control;
    OSStatus    err = noErr;
    UInt32  len;
    char    str[16];
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    
    len = MyNumToHexString(gSAPAddr, str);
    
    if (len > 0)
    {
        err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, &str);
        require_noerr(err, CantSetControlData);
    }
    return noErr;
 
CantSetControlData:
    fprintf(stderr, "Unable to set control data %ld, error was %d\n", controlID.id, (int)err);
    return err;
    
CantGetControlByID:
    fprintf(stderr, "Unable to find control ID %ld, error was %d\n", controlID.id, (int)err);
    return err;
}
 
OSStatus GetSNAPFieldValue(UInt8 *snap)
{
    ControlID   controlID = { kTestSignature, kSNAPField };
    ControlRef  control;
    UInt32  len;
    OSStatus    err = noErr;
    UInt32  value;
    UInt32  offset;
    UInt32  i;
    char    str[16];
    char    temp1[2], temp2[2];
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    err = GetControlData(control, kControlNoPart, kControlEditTextTextTag, sizeof(str), str, &len);
    require_noerr(err, CantGetControlData);
    str[len] = 0;
    offset = 0;
    if((str[0] == 'x') || (str[0] == 'X'))
        offset = 1;
    else if((str[1] == 'x') || (str[1] == 'X'))
        offset = 2;
    
    // create a 1 char string to pass to the MyHexStringToNum function
    temp1[1] = temp2[1] = 0;
    for (i = 0; i < 5; i++)
    {
            // get the upper byte character
        temp1[0] = str[offset + 2 * i];
            // get the lower byte character
        temp2[0] = str[offset + 2 * i + 1];
            // convert the upper byte
        err = MyHexStringToNum(temp1, &value);
        if (err)
            break;
            // set the upper byte of the snapAddr
        snap[i] = value << 4;
            // convert the lower byte character
        err = MyHexStringToNum(temp2, &value);
        if (err)
            break;
            // set the lower byte of the snapAddr
        snap[i] += value;
        
    }
    
    require_noerr(err, InvalidData);
 
    return noErr;
                        
InvalidData:
    fprintf(stderr, "Invalid hx data in control %ld\n", controlID.id);
    memset(snap, 0, 5); // zero out the  snap address
    return err;
CantGetControlData:
    fprintf(stderr, "Unable to find control data - control %ld, error was %d\n", controlID.id, (int)err);
    return err;
CantGetControlByID:
    fprintf(stderr, "Unable to find control ID %ld, error was %d\n", controlID.id, (int)err);
    return err;
}
 
OSStatus SetSNAPFieldValue(UInt8 *snap)
{
    ControlID   controlID = { kTestSignature, kSNAPField };
    ControlRef  control;
    OSStatus    err = noErr;
    UInt32      len;
    UInt32      i, val;
    char        str[16];
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    
    // the snap address is a 5 byte value, which we will prefix with "0x"
    
    str[0] = '0';
    str[1] = 'x';
    
    for (i = 0; i < 5; i++)
    {
        // set the higher digit
        val = snap[i] / 16;
        if ((val >= 0) && (val <= 9))
            str[2 * i + 2] = '0' + val;
        else if ((val >= 10) && (val <= 15))
            str[2 * i + 2] = 'A' + val - 10;
        else
            return -1;
        // set the lower digit
        val = snap[i] % 16;
        if ((val >= 0) && (val <= 9))
            str[2 * i + 3] = '0' + val;
        else if ((val >= 10) && (val <= 15))
            str[2 * i + 3] = 'A' + val - 10;
        else
            return -1;
    }
    str[12] = 0;
    len = 12;
 
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, &str);
    require_noerr(err, CantSetControlData);
    return noErr;
    
CantGetControlByID:
    fprintf(stderr, "Unable to find control ID %ld, error was %d\n", controlID.id, (int)err);
    return err;
CantSetControlData:
    fprintf(stderr, "Unable to set control ID %ld, error was %d\n", controlID.id, (int)err);
    return err;
}
 
OSStatus SetControlState(WindowRef window, OSType type, SInt32 id, Boolean enable)
{
    OSStatus    err;
    ControlID   controlID;
    ControlRef  control;
        controlID.signature = type;
        controlID.id = id;
            err = GetControlByID(window, &controlID, &control);
            require_noerr(err, CantGetControlByID);
            if (enable)
    {
        err = ActivateControl(control);
        require_noerr(err, CantEnableControl);
    }
    else
    {
        err = DeactivateControl(control);
        require_noerr(err, CantDisableControl);
    }
    return noErr;
 
CantGetControlByID:
    fprintf(stderr, "Unable to find control ID %ld, error was %d\n", id, (int)err);
    return err;
CantEnableControl:
    fprintf(stderr, "Unable to enable control %ld, error was %d\n", id, (int)err);
    return err;
CantDisableControl:
    fprintf(stderr, "Unable to disable control %ld, error was %d\n", id, (int)err);
    return err;
}
 
OSStatus SetStateOfSendReceiveFields(void)
{
    ControlID   controlID = { kTestSignature, kSendReceiveButton };
    ControlRef  control;
    OSStatus    err = noErr;
    Boolean sendState, recvState;
 
    if (gSendRcvState != kCancelTest)
    {
            err = GetControlByID(gMainWindow, &controlID, &control);
            require_noerr(err, CantGetControlByID);
            // get the state of the Send Receive buttons
            gSendRcvState = GetControlValue(control);
 
            if (gSendRcvState == kSendTest)
            {
                    
                SetEthernetAddressField(kSourceAddressField, &gedata[gCurrPopupEntry-1].macAddress);
                SetEthernetAddressField(kDestAddressField, &gDestAddr);
                // enable the send fields
                // disable the receive fields
                sendState = kEnable;
                recvState = kDisable;
            }
            else
            {
                // set the source address as a generic broadcast address and
                // the destination address as the
                SetEthernetAddressField(kSourceAddressField, &gBroadcastAddr);
                SetEthernetAddressField(kDestAddressField, &gedata[gCurrPopupEntry-1].macAddress);
                // enable the receive fields
                // disable the send fields
                sendState = kDisable;
                recvState = kEnable;
            }
            // these fields are always enabled for send and received
            SetControlState(gMainWindow, kTestSignature, kSendReceiveButton, kEnable);
            SetControlState(gMainWindow, kTestSignature, kDSAPField, kEnable);
            SetControlState(gMainWindow, kTestSignature, kSNAPField, kEnable);
            SetControlState(gMainWindow, kTestSignature, kSourceAddressField, kEnable);
            SetControlState(gMainWindow, kTestSignature, kDestAddressField, kEnable);
            SetControlState(gMainWindow, kTestSignature, kDoTestButton, kEnable);
            // the test button is always disabled when not running a test
            SetControlState(gMainWindow, kTestSignature, kCancelTestButton, kDisable);
    }
    else
    {
            // in the CancelTest state, all fields and buttons are disabled except the
            // CancelTest button and the quit button
            SetControlState(gMainWindow, kTestSignature, kDoTestButton, kDisable);
            SetControlState(gMainWindow, kTestSignature, kSendReceiveButton, kDisable);
            // the test button is always disabled when not running a test
            SetControlState(gMainWindow, kTestSignature, kCancelTestButton, kEnable);
            sendState = kDisable;
            recvState = kDisable;
            SetControlState(gMainWindow, kTestSignature, kDSAPField, kDisable);
            SetControlState(gMainWindow, kTestSignature, kSNAPField, kDisable);
            SetControlState(gMainWindow, kTestSignature, kSourceAddressField, kEnable);
    }
 
    // set the stat of the send fields
    SetControlState(gMainWindow, kTestSignature, kNumPacketsField, sendState);
 
    // set the state of the receive fields
    SetControlState(gMainWindow, kTestSignature, kDestAddressIsMCast, recvState);
    SetControlState(gMainWindow, kTestSignature, kNumPacketsReceivedField, kDisable);
    SetControlState(gMainWindow, kTestSignature, kNumPacketsInOrderField, kDisable);
    SetControlState(gMainWindow, kTestSignature, kNumPacketsOutOfOrderField, kDisable);
    SetControlState(gMainWindow, kTestSignature, kLastPacketReceivedField, kDisable);
    // leave the kDestAddressIsMCast radio button disabled if the current MacOS is 10.1.5 or
    // earlier since the SetMulticast feature does not work
    if (gVerMacOS <= 0x1015)
        SetControlState(gMainWindow, kTestSignature, kDestAddressIsMCast, kDisable);
    else
        SetControlState(gMainWindow, kTestSignature, kDestAddressIsMCast, recvState);
        
    return noErr;
        
CantGetControlByID:
    fprintf(stderr, "Error in setting data for Send Statistics - %ld\n", err);
    return err;
 
}
 
OSStatus GetNumPacketsField(UInt32 *numPackets)
{
    ControlID   controlID = { kTestSignature, kNumPacketsField };
    ControlRef  control;
    UInt32  len;
    char    str[16];
    OSStatus    err;
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    // get the control text
    err = GetControlData(control, kControlNoPart, kControlEditTextTextTag, 
                        sizeof(str), str, &len);
    require_noerr(err, CantGetControlData);
   // force string to be a "C" style string
    str[len] = 0;
    // convert the string
    err = MyStringToNum(str, numPackets);
    require_noerr(err, InvalidStringData);
    return noErr;
    
InvalidStringData:
CantGetControlByID:
CantGetControlData:
    return err;
}
 
OSStatus SetSendStatistics(UInt32 numPackets, UInt32 sendTime)
{
    ControlID   controlID = { kTestSignature, kNumPacketsField };
    ControlRef  control;
    UInt32  len, rate;
    char    str[16];
    OSStatus    err;
    
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(numPackets, str, kPositive);
    // set the control text
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "set num packets sent field to %s\n", str);
 
    controlID.id = kSendTimeField;
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(sendTime, str, kPositive);
 
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, &str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "set time field to %s\n", str);
    
    if (sendTime > 0)
        rate = numPackets / sendTime;
    else
        rate = 0;
 
    controlID.id = kTransferRateField;
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(rate, str, kPositive);
    // set the control data
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "set rate field to %s\n", str);
 
    SetControlState(gMainWindow, kTestSignature, kSendTimeField, FALSE);
    SetControlState(gMainWindow, kTestSignature, kTransferRateField, FALSE);
    return noErr;
 
 
CantGetControlByID:
CantSetControlData:
    fprintf(stderr, "Error in setting data for Send Statistics - %d\n", (int)err);
    return err;
 
}
 
OSStatus SetReceiveStatistics(UInt32 packetsReceived, UInt32 PacketsInOrder, 
                                UInt32 PacketsOutOfOrder, UInt32 lastPacketReceived)
{
    ControlID   controlID = { kTestSignature, kNumPacketsReceivedField };
    ControlRef  control;
    UInt32  len;
    char    str[16];
    OSStatus    err;
    
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(packetsReceived, str, kPositive);
    // set the control data
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "Num Packets received - %d\n", (int)packetsReceived);
 
    controlID.id = kNumPacketsInOrderField;
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(PacketsInOrder, str, kPositive);
    // set the control data
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "Packets in order - %d\n", (int)PacketsInOrder);
 
    controlID.id = kNumPacketsOutOfOrderField;
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(PacketsOutOfOrder, str, kPositive);
    // set the control data
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "Packets out of order - %d\n", (int)PacketsOutOfOrder);
 
    controlID.id = kLastPacketReceivedField;
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    len = MyNumToString(lastPacketReceived, str, kPositive);
    // set the control data
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, str);
    require_noerr(err, CantSetControlData);
//    fprintf(stderr, "Last packet received - %d\n", (int)lastPacketReceived);
 
    SetControlState(gMainWindow, kTestSignature, kNumPacketsReceivedField, FALSE);
    SetControlState(gMainWindow, kTestSignature, kNumPacketsInOrderField, FALSE);
    SetControlState(gMainWindow, kTestSignature, kNumPacketsOutOfOrderField, FALSE);
    SetControlState(gMainWindow, kTestSignature, kLastPacketReceivedField, FALSE);
    
    return noErr;
 
CantGetControlByID:
CantSetControlData:
    fprintf(stderr, "Error in setting data for Receive Statistics - %d\n", (int)err);
    return err;
}
 
OSStatus SetEnetPopupButton(EnetData *enet, UInt32 itemno)
{
    OSStatus        err;
    ControlID       controlID = { kTestSignature, kEnetPopupButton };
    ControlRef      control;
    
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    
 
CantGetControlByID:
    fprintf(stderr, "SetEnetPopupButton: Unable to get a control for the main window - control number %ld.\n", controlID.id);
    return err;
}
 
OSStatus LoadMainWindowFromNibFile(IBNibRef gNibRef)
{
    ControlID       controlID = { kTestSignature, kDoTestButton };
    EventTypeSpec   connectEvents = { kEventClassControl, kEventControlHit };
    EventTypeSpec   popConnectEvents[] = { { kEventClassMenu, kEventMenuTargetItem }, { kEventClassMenu, kEventMenuEndTracking } };
    OSStatus        err;
    ControlRef      control;
    MenuRef         menuRef;
    
    // Create a window. "MainWindow" is the name of the window object. This name is set in 
    // InterfaceBuilder when the nib is created.
    err = CreateWindowFromNib(gNibRef, CFSTR("MainWindow"), &gMainWindow);
    require_noerr(err, CantCreateWindow);
 
    // set up the UPP's for "Do Test" button proc handler
    if (gMyDoTestButtonInterceptorUPP == NULL)
    {
        gMyDoTestButtonInterceptorUPP = NewEventHandlerUPP(MyDoTestButtonInterceptor);
    }
    
    // set the "Do Test" button as the default button
    controlID.id = kDoTestButton;        
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
 
    SetWindowDefaultButton(gMainWindow, control);
    if (gMyDoTestButtonInterceptorUPP != NULL)
    {
        InstallControlEventHandler(control, gMyDoTestButtonInterceptorUPP, 1, &connectEvents, NULL, NULL);
    }
 
    // set up the UPP's for "Cancel Test" button proc handler
    if (gMyDoCancelTestButtonInterceptorUPP == NULL)
    {
        gMyDoCancelTestButtonInterceptorUPP = NewEventHandlerUPP(MyDoCancelTestButtonInterceptor);
    }
        // set the "Do Test" button as the default button
    controlID.id = kCancelTestButton;
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    if (gMyDoCancelTestButtonInterceptorUPP != NULL)
    {
        InstallControlEventHandler(control, gMyDoCancelTestButtonInterceptorUPP, 1, &connectEvents, NULL, NULL);
    }
    
        // set up the UPP's for "Send/Receive" button proc handler
    if (gMySendRcvButtonInterceptorUPP == NULL)
    {
    gMySendRcvButtonInterceptorUPP = NewEventHandlerUPP(MySendRcvButtonInterceptor);
    }
    
    // set the interceptor for the Send/Receive radio button
    controlID.id = kSendReceiveButton;        
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
 
    if (gMySendRcvButtonInterceptorUPP != NULL)
    {
        InstallControlEventHandler(control, gMySendRcvButtonInterceptorUPP, 1, &connectEvents, NULL, NULL);
    }
 
    // set up the UPP's for "Dest Addr is Multicast" radio button
    if (gMyDestAddrIsMCastInterceptorUPP == NULL)
    {
        gMyDestAddrIsMCastInterceptorUPP = NewEventHandlerUPP(MyDestAddrIsMCastInterceptor);
    }
    
    // set the interceptor for the "Dest Addr is Multicast" radio button
    controlID.id = kDestAddressIsMCast;        
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
 
    if (gMyDestAddrIsMCastInterceptorUPP != NULL)
    {
        InstallControlEventHandler(control, gMyDestAddrIsMCastInterceptorUPP, 1, &connectEvents, NULL, NULL);
    }
 
    // set up the UPP's for "enet popup" button
    if (gMyEnetPopupCommandInterceptorUPP == NULL)
    {
        gMyEnetPopupCommandInterceptorUPP = NewEventHandlerUPP(MyEnetPopupButtonInterceptor);
    }
    
    // set the "enet popup" button control handler function
    controlID.id = kEnetPopupButton;        
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
 
    if (gMyEnetPopupCommandInterceptorUPP != NULL)
    {
        menuRef = GetControlPopupMenuHandle(control);
        InstallMenuEventHandler(menuRef, gMyEnetPopupCommandInterceptorUPP, 2, (EventTypeSpec*) &popConnectEvents, NULL, NULL);
    }
    
    // get the ethernet address data, as well as the bsd name, and an indication whether the item is
    // built in.  On return gNumEnetEntries is the number of ethernet entries which were found.
    err = GetEthernetAddressInfo((EnetData*)&gedata, &gNumEnetEntries);
    if (err != noErr)
    {
        fprintf(stderr, "an error occured in trying to find ethernet interfaces %ld\n", err);
    }
    else if (gNumEnetEntries == 0)
    {
        fprintf(stderr, "no ethernet interfaces were found.\n");
        err = -1;
    }
    else
    {
        AddEnetServicesToPopupMenu((EnetData*) &gedata);
    }
        
    SetSAPFieldValue(gSAPAddr);
    SetSNAPFieldValue((UInt8*)&gSNAPAddr);
    SetStateOfSendReceiveFields();
    SetSendStatistics(gNumPacketsToHandle, 0);
    
    // set up the timer proc
    gMainLoop = GetMainEventLoop();
    gTimerUPP = NewEventLoopTimerUPP(TimerAction);
    
    err = InstallEventLoopTimer(gMainLoop, 1, 1, gTimerUPP, NULL, &gTimerRef);
    require_noerr(err, CantInstallTimer);
    
    return err;
        
CantCreateWindow:
    fprintf(stderr, "Unable to create the main.\n");
    return err;
 
CantGetControlByID:
    fprintf(stderr, "Unable to get a control for the main window - control number %ld.\n", controlID.id);
    return err;
    
CantInstallTimer:
    fprintf(stderr, "Unable to install timer %ld.\n", err);
    return err;
}
 
OSStatus
LoadAboutWindowFromNibFile(IBNibRef gNibRef)
{
    OSStatus        err;
    ControlID       controlID = { kTestSignature, kAboutAppNameText };
    ControlRef      control;
    ControlFontStyleRec fontRec;
    CFBundleRef     myBundle;
    CFDictionaryRef myDictionary;
    CFStringRef     appNameCFString;
    CFStringRef     versionCFString;
    char            appName[kMaxInputSize];
    char            version[kMaxInputSize];
    
    // Then create a window. "gAboutWindow" is the name of the window object. This name is set in 
    // InterfaceBuilder when the nib is created.
    err = CreateWindowFromNib(gNibRef, CFSTR("AboutWindow"), &gAboutWindow);
    require_noerr(err, CantCreateWindow);
 
    myBundle = CFBundleGetMainBundle();
    myDictionary = CFBundleGetInfoDictionary(myBundle);
    appNameCFString = CFDictionaryGetValue(myDictionary, CFSTR("CFBundleExecutable"));
    versionCFString = CFDictionaryGetValue(myDictionary, CFSTR("CFBundleVersion"));
 
    CFStringGetCString(appNameCFString, appName, kMaxInputSize, CFStringGetSystemEncoding());
    CFStringGetCString(versionCFString, version, kMaxInputSize, CFStringGetSystemEncoding());
    
    GetControlByID(gAboutWindow, &controlID, &control);
    fontRec.flags = kControlUseFontMask | kControlUseFaceMask | kControlAddToMetaFontMask | kControlUseJustMask;
    fontRec.style = bold;
    fontRec.just = teCenter;
    fontRec.font = kControlFontBigSystemFont;
    SetControlFontStyle(control, &fontRec);
    SetControlData(control, kControlNoPart, kControlEditTextTextTag, strlen(appName), appName);
    
    controlID.id = kAboutVersionText;
    GetControlByID(gAboutWindow, &controlID, &control);
    fontRec.flags = kControlUseFontMask | kControlAddToMetaFontMask | kControlUseJustMask;
    fontRec.just = teCenter;
    fontRec.font = kControlFontSmallSystemFont;
    SetControlFontStyle(control, &fontRec);
    SetControlData(control, kControlNoPart, kControlEditTextTextTag, strlen(version), version);
 
CantCreateWindow:
    return err;
 
}
 
int EnetAddrToString(MACAddress *eaddr, char *str)
{
    UInt32  i;
    UInt32  digit1, digit2, len;
    UInt8   *addr = (UInt8*)eaddr;
    
    len = 0;
    for (i = 0; i < kIOEthernetAddressSize; i++)
    {
                digit1 = addr[i];
 
        digit1 = addr[i] / 0x10;
        digit2 = addr[i] % 0x10;
        if (digit1 < 10)
            str[len++] = '0' + digit1;
        else
            str[len++] = 'A' + (digit1 - 10);
 
        if (digit2 < 10)
            str[len++] = '0' + digit2;
        else
            str[len++] = 'A' + (digit2 - 10);
            
        if (i + 1 < kIOEthernetAddressSize)
            str[len++] = ':';
    }
    str[len] = 0;
    return len;
}
 
OSStatus EnetStrToAddr(char *str, MACAddress *eaddr)
{
    UInt32  i;
    UInt32  digit1, j;
    UInt8   *addr = (UInt8*)eaddr;
    
    i = 0;
    memset(eaddr, 0, sizeof(MACAddress));
    for (j = 0; j < (3 * kIOEthernetAddressSize - 1); j++)
    {
        if (((j + 1) % 3) != 0) // do not look at the separator character
        {
            if (str[j] >= '0' && str[j] <= '9')
                digit1 = str[j] - '0';
            else if (str[j] >= 'A' && str[j] <= 'F')
                digit1 = 10 + str[j] - 'A';
            else if (str[j] >= 'a' && str[j] <= 'f')
                digit1 = 10 + str[j] - 'a';
            else
            {
                return -1;  // invalid character detected
            }
            addr[i] = addr[i] * 0x10 + digit1;
        }
        else // increment the eaddr field assignment character when j equates to the field position
            // for the separator character.
            i++;
    }
    return noErr;
}
 
OSStatus SetEthernetAddressField(SInt32 id, MACAddress *eaddr)
{
    OSStatus        err;
    ControlID       controlID;
    ControlRef      control;
    char        enetstr[32];
    UInt32      len;
    
    controlID.signature = kTestSignature;
    controlID.id = id;
    
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
 
    len = EnetAddrToString(eaddr, enetstr);
    // set the control data
    err = SetControlData(control, kControlNoPart, kControlStaticTextTextTag, len, enetstr);
    require_noerr(err, CantSetControlData);
    return noErr;
    
CantSetControlData:
CantGetControlByID:
    fprintf(stderr, "SetEthernetAddressField: error occured in get/set control data\n");
    return err;
}
 
OSStatus GetEthernetAddressField(SInt32 id, MACAddress *eaddr)
{
    OSStatus        err;
    ControlID       controlID;
    ControlRef      control;
    char        enetstr[32];
    UInt32      len;
    
    controlID.signature = kTestSignature;
    controlID.id = id;
    
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
 
    err = GetControlData(control, kControlNoPart, kControlEditTextTextTag,
                        sizeof(enetstr), enetstr, &len);
    require_noerr(err, CantGetControlData);
    // force the string to be a "C" style string
    enetstr[len] = 0;
                        
    err = EnetStrToAddr(enetstr, eaddr);
    require_noerr(err, CantConvertData);
    return noErr;
 
CantConvertData:
CantGetControlData:
CantGetControlByID:
    fprintf(stderr, "GetEthernetAddressField: error occured in get/set control data\n");
    return err;
}
 
void AddEnetServicesToPopupMenu(EnetData *enetdata)
{
    ControlID       controlID = { kTestSignature, kEnetPopupButton };
    ControlRef      control;
    CFStringRef     tempEnet = NULL;
    char            tempEnetString[256];
    MenuRef         menu;
    OSStatus        err = noErr;
    UInt16          i, enetItem, enetStrLen;
    
    err = GetControlByID(gMainWindow, &controlID, &control);
    if (err == noErr)
    {
        for (enetItem = 0; enetItem < gNumEnetEntries; enetItem++)
        {
            strcpy(tempEnetString, enetdata[enetItem].bsdName);
            enetStrLen = strlen(tempEnetString);
            
            for (i = 0; i < enetStrLen; i++) tempEnetString[i] = toupper(tempEnetString[i]);
            if (enetdata[enetItem].isBuiltIn)
                strcat(tempEnetString, " Built-in\0");
            
            tempEnet = CFStringCreateWithCString(NULL, tempEnetString, CFStringGetSystemEncoding());
            if (tempEnet)
            {
                menu = GetControlPopupMenuHandle(control);
 
                if (enetItem == 0)
                {
                    // replace the first item
                    err = SetMenuItemTextWithCFString(menu, 1, tempEnet);
                    if (err != noErr)
                    {
                        fprintf(stderr, "Failed to set menu item %d\n", enetItem);
                    }
                    
                }
                else
                {
                    // append the menu item
                    err = AppendMenuItemTextWithCFString(menu, tempEnet, 0, 0, NULL);
                    if (err != noErr)
                    {
                        fprintf(stderr, "Failed to append menu item %d\n", enetItem);
                    }
                }
                CFRelease(tempEnet);
            }
        }
        SetControlMaximum(control, gNumEnetEntries);
    }
    else
        fprintf(stderr, "Enable to get main window control\n");
}
 
void SetActiveEnetPopupMenu(UInt16 menuItem)
{
    ControlID   controlID = { kTestSignature, kEnetPopupButton };
    ControlRef  control;
    OSStatus    err;
                        
    err = GetControlByID(gMainWindow, &controlID, &control);
    if (err == noErr)
    {        
        SetControlValue(control, menuItem);        
    }
}
 
OSStatus MyEnetPopupButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData)
{
    OSStatus        err = noErr;
    static SInt16   menuItem = 0;   // static item to keep track of recently selected item
                                    // across calls to this interceptor
    
    switch ( GetEventKind(inEvent) )
    {
        case kEventMenuTargetItem:
            GetEventParameter(inEvent, kEventParamMenuItemIndex, typeMenuItemIndex, NULL, sizeof(typeMenuItemIndex), NULL, &menuItem);
            break;
        case kEventMenuEndTracking:
            if ((menuItem != gCurrPopupEntry) && (menuItem != 0))
            {
                if (menuItem <= gNumEnetEntries)
                {
                    gCurrPopupEntry = menuItem;
                    SetActiveEnetPopupMenu(menuItem);
                    err = SetStateOfSendReceiveFields();
                }
            }
            break;
    }
    
    return err;
}
 
/*
    SetResults is called after a successful test to put the results into the dialog.
    The results are stored in the EnetTestData structure.
*/
OSStatus SetResults(EnetTestData *testData)
{
    OSStatus    status = noErr;
    if (testData->sendRcvState == kSendTest)
    {
        // enter send test fields
        status = SetSendStatistics(testData->numPacketsSent, testData->tdiff);
    }
    else
    {
        // enter receive test fields
        status = SetReceiveStatistics(testData->packetsRead, testData->packetsInOrder,
                                    testData->packetsOutOfOrder, testData->lastPacketNum);
            
    }
    return status;
}
 
OSStatus MyDoCancelTestButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData)
{
    OSStatus        err = noErr;
    
    fprintf(stderr, "entered MyDoCancelTestButtonInterceptor\n");
    gEnetTestData->sendRcvState = kCancelTest;
 
    err = DoEnetTest(gEnetTestData);
    // test was for receive test, so set the fields back to the receive state
    SetResults(gEnetTestData);
    gSendRcvState = kReceiveTest;
    SetStateOfSendReceiveFields();
    
    return err;
}
 
OSStatus MyDestAddrIsMCastInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData)
{
    OSStatus        err = noErr;
    ControlID       controlID = { kTestSignature, kDestAddressIsMCast };
    ControlRef      control;
 
    err = GetControlByID(gMainWindow, &controlID, &control);
    require_noerr(err, CantGetControlByID);
    // get the state of the Send Receive buttons
    gDestAddrIsMCast = GetControlValue(control);
    return noErr;
    
CantGetControlByID:
        return err;
}
 
OSStatus MyDoTestButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData)
{
    OSStatus        err = noErr;
 
    // zero out the test memory structure
    memset(gEnetTestData, 0, sizeof(*gEnetTestData));
    // get the current SAP value setting
    err = GetSAPFieldValue(&(gEnetTestData->sap));
    require_noerr(err, CantGetSAPData);
    fprintf(stderr, "DSAP value is 0x%X\n", gEnetTestData->sap);
 
    // save the current version of the OS
    gEnetTestData->verMacOS = gVerMacOS;
    
    gEnetTestData->destAddrIsMCast = gDestAddrIsMCast;
 
    // read the current SNAP value if the SAP is 0xAA
    if (gEnetTestData->sap == 0xAA)
    {
        err = GetSNAPFieldValue((UInt8*)&(gEnetTestData->snap));
        require_noerr(err, CantGetSNAPData);
    }
 
    // get the source address to be used
    err = GetEthernetAddressField(kSourceAddressField, &(gEnetTestData->srcaddr));
    require_noerr(err, CantGetSourceEthernetAddress);
 
    // get the destination address to be used
    err = GetEthernetAddressField(kDestAddressField, &(gEnetTestData->destaddr));
    require_noerr(err, CantGetDestEthernetAddress);
    
    err = GetNumPacketsField(&(gEnetTestData->numPacketsToSend));
    require_noerr(err, CantGetNumPackets);
    
    gEnetTestData->sendRcvState = gSendRcvState;
 
    // copy the name of the selected enet hw based on the selected popup item
    // so that we can do a bind
    strcpy(gEnetTestData->saddr.sa_data, gedata[gCurrPopupEntry-1].bsdName);
    fprintf(stderr, "Processing packets on ethernet port %s\n", gEnetTestData->saddr.sa_data);
 
    // determine if this is the first time we are using this ethernet device.
    // if the device is inactive and is not the built in device, then the first time
    // the socket is used, the driver will outbound packets until the link has
    // been established.
    gEnetTestData->isFirstTime = FALSE;
    if ((gedata[gCurrPopupEntry-1].isBuiltIn == FALSE) && (gedata[gCurrPopupEntry-1].usedPreviously == FALSE))
    {
        gedata[gCurrPopupEntry-1].usedPreviously = TRUE;
        gEnetTestData->isFirstTime = TRUE;
    }
    err = DoEnetTest(gEnetTestData);
    if (err)
        fprintf (stderr, "error occurred on processing DoEnetTest %ld\n", err);
    else
    {
        switch (gSendRcvState)
        {
            case kReceiveTest:
                gSendRcvState = kCancelTest;
                // by setting the SendRcvState to kCancelTest, the DoTest button is inactivated
                // and the Cancel Test button is activated.
                SetStateOfSendReceiveFields();
                break;
                
            case kSendTest:
                gEnetTestData->tdiff = gEnetTestData->tend - gEnetTestData->tbegin;
                fprintf(stderr, "sent %ld packets in %ld seconds\n", gEnetTestData->numPacketsSent, gEnetTestData->tdiff);
                SetResults(gEnetTestData);
                break;
            
        }
 
    }
    return noErr;
 
CantGetNumPackets:
CantGetDestEthernetAddress:
CantGetSourceEthernetAddress:
CantGetSAPData:
CantGetSNAPData:
    return noErr;
}
 
OSStatus MySendRcvButtonInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData)
{
    OSStatus        err = noErr;
    
    err = SetStateOfSendReceiveFields();
 
    return err;
}
 
OSStatus MyAppCommandInterceptor(EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData)
{
    HICommand   theCommand;
    OSStatus    status = noErr;
    
    status = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &theCommand);
 
    if (status)
        return status;
    
    switch (theCommand.commandID)
    {
        case kHICommandAbout:
            if ( MacIsWindowVisible(gAboutWindow) == false )
            {
                if ( LoadAboutWindowFromNibFile(gNibRef) == noErr)
                {
                    RepositionWindow(gAboutWindow, NULL, kWindowCenterOnMainScreen);
                    BringToFront(gAboutWindow);
                    ShowWindow(gAboutWindow);
                }
            }
            else
            {
                ActivateWindow(gAboutWindow, true);
                BringToFront(gAboutWindow);
            }
            break;
            
        default:
            status = CallNextEventHandler(inCallRef, inEvent);
            break;
    }
    
    return status;
}
 
 
void DisposeUPPs()
{
    if (gMyDestAddrIsMCastInterceptorUPP)
    {
        DisposeEventHandlerUPP(gMyDestAddrIsMCastInterceptorUPP);
        gMyDestAddrIsMCastInterceptorUPP = NULL;
    }
    if (gMyDoTestButtonInterceptorUPP)  
    {   
        DisposeEventHandlerUPP(gMyDoTestButtonInterceptorUPP);
        gMyDoTestButtonInterceptorUPP = NULL;
    }
    if (gMyEnetPopupCommandInterceptorUPP)
    {       
        DisposeEventHandlerUPP(gMyEnetPopupCommandInterceptorUPP);
        gMyEnetPopupCommandInterceptorUPP = NULL;
    }
    if (gMyDoCancelTestButtonInterceptorUPP)
    {       
        DisposeEventHandlerUPP(gMyDoCancelTestButtonInterceptorUPP);
        gMyDoCancelTestButtonInterceptorUPP = NULL;
    }
    if (gMySendRcvButtonInterceptorUPP)     
    {
        DisposeEventHandlerUPP(gMySendRcvButtonInterceptorUPP);
        gMySendRcvButtonInterceptorUPP = NULL;
    }
    if (gMyAppCommandInterceptorUPP)
    {
        DisposeEventHandlerUPP(gMyAppCommandInterceptorUPP);
        gMyAppCommandInterceptorUPP = NULL;
    }
}
 
int main (void)
{
    OSStatus        err;
    EventTypeSpec   commandEvents = { kEventClassCommand, kEventProcessCommand };
 
    // This simply launches the 'Console.app' to show the output from this program.
    LSOpenCFURLRef(CFURLCreateWithString(NULL, CFSTR("/var/tmp/console.log"), NULL), NULL);
 
    Initialize();
                         
    // Create a Nib reference passing the name of the nib file (without the .nib extension)
    // CreateNibReference only searches into the application bundle.
    err = CreateNibReference(CFSTR("BSDLLCTest"), &gNibRef);
    require_noerr(err, CantGetNibRef);
 
    // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
    // object. This name is set in InterfaceBuilder when the nib is created.
    err = SetMenuBarFromNib(gNibRef, CFSTR("MainMenu"));
    require_noerr(err, CantSetMenuBar);
 
    if (gMyAppCommandInterceptorUPP == NULL)
    {
        gMyAppCommandInterceptorUPP = NewEventHandlerUPP(MyAppCommandInterceptor);
    }
    
    if (gMyAppCommandInterceptorUPP != NULL)
    {
        // I'm only using this for the About Box.
        InstallApplicationEventHandler(gMyAppCommandInterceptorUPP, 1, &commandEvents, NULL, NULL);
    }
 
    err = LoadMainWindowFromNibFile(gNibRef);
    require_noerr(err, CantCreateWindow);
    
    InitCursor();
    
    // The window was created hidden so show it.
    RepositionWindow(gMainWindow, NULL, kWindowCenterOnMainScreen);
    ShowWindow(gMainWindow);
 
    
    // Call the event loop
    RunApplicationEventLoop();
    
    // stop the event timer
    RemoveEventLoopTimer(gTimerRef);
    
 
    // We don't need the nib reference anymore.
    DisposeNibReference(gNibRef);
    DisposeUPPs();
        
    fprintf(stderr, "\nProgram ended\n");
    return 0;
 
CantCreateWindow:
CantSetMenuBar:
CantGetNibRef:
 
    fprintf(stderr, "\nProgram ended\n");
    return err;
 
}