• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Receive UDP broadcast packets with OTRcvUData
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Receive UDP broadcast packets with OTRcvUData


  • Subject: Re: Receive UDP broadcast packets with OTRcvUData
  • From: Quinn <email@hidden>
  • Date: Wed, 3 Nov 2004 23:09:04 +0000

Title: Re: Receive UDP broadcast packets with OTRcvUData
At 14:50 +0100 3/11/04, Matthieu Beghin wrote:
I create a Synchrone socket and set it non blockling. It receives broadcast on 2.255.255.255.
Sometimes I have to answer by broadcast and I get the error
kEACCESErr -3212 Permission denied
when calling OTSndUData.

I just tried sending UDP broadcasts under OT on Mac OS X, and it worked as easily as I remember.  I'm not sure what's going on with your code, but you might want to compare it with mine.  I've included my test program at the end of this email.  Try it out on your machine and see what you get.

You should just be able to paste it into an Xcode CoreServices command line tool project.

S+E
--
Quinn "The Eskimo!"                    <http://www.apple.com/developer/>
Apple Developer Technical Support * Networking, Communications, Hardware

----------------------------------------------------------------------------
/*
    File:       UDPBroadcastTester.c

    Contains:   Framework for testing UDP broadcast code.

    Written by: Quinn "The Eskimo!"

    Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.

    Change History (most recent first):

    You may incorporate this sample code into your applications without
    restriction, though the sample code has been provided "AS IS" and the
    responsibility for its operation is 100% yours.  However, what you are
    not permitted to do is to redistribute the source as "DSC Sample Code"
    after having made changes. If you're going to re-distribute the source,
    we require that you make it clear in the source that the code was
    descended from Apple Sample Code, but that you've made changes.
*/

/////////////////////////////////////////////////////////////////////
// Pick up all the standard OT stuff.

#include <OpenTransport.h>

/////////////////////////////////////////////////////////////////////
// Pick up all the OT TCP/IP stuff.

#include <OpenTptInternet.h>

/////////////////////////////////////////////////////////////////////
// Pick up  OT low-level stuff.

#include <stropts.h>

/////////////////////////////////////////////////////////////////////
// Pick up the OTDebugBreak and OTAssert macros.

#include <OTDebug.h>

/////////////////////////////////////////////////////////////////////
// Pick up various Mac OS stuff.

#include <Threads.h>
#include <Traps.h>
#include <MixedMode.h>
#include <Gestalt.h>
#include <Events.h>

/////////////////////////////////////////////////////////////////////
// Standard C stuff

#include <stdio.h>

/////////////////////////////////////////////////////////////////////
// The following equates are actually exported by <miioccom.h>, but
// they commented out for some reason )-:

// #include <miioccom.h>

#define MIOC_SIOC       'j'     /* sockio.h socket ioctl's */

/////////////////////////////////////////////////////////////////////

enum {
    kTestPort = 12345
};

static Boolean gQuitNow = false;
static Boolean gEchoThreadBound = false;

/////////////////////////////////////////////////////////////////////

static OSStatus MyYieldToAnyThread(void)
{
    OSStatus err;
    OSStatus junk;
   
    err = noErr;
    junk = YieldToAnyThread();
    OTAssert("MyYieldToAnyThread: YieldToAnyThread failed", junk == noErr);
    if ( gQuitNow ) {
        err = userCanceledErr;
    }
    return err;
}

static pascal void YieldingNotifier(EndpointRef ep, OTEventCode code,
                                       OTResult result, void* cookie)
    // This simple notifier checks for kOTSyncIdleEvent and
    // when it gets one calls the Thread Manager routine
    // YieldToAnyThread.  Open Transport sends kOTSyncIdleEvent
    // whenever it's waiting for something, eg data to arrive
    // inside a sync/blocking OTRcv call.  In such cases, we
    // yield the processor to some other thread that might
    // be doing useful work.
{
    #pragma unused(result)
    #pragma unused(cookie)
    OSStatus junk;
   
    switch (code) {
        case kOTSyncIdleEvent:
            junk = YieldToAnyThread();
            OTAssert("YieldingNotifier: YieldToAnyThread failed", junk == noErr);
            if ( gQuitNow ) {
                junk = OTCancelSynchronousCalls(ep, userCanceledErr);
                OTAssert("YieldingNotifier: OTCancelSynchronousCalls failed", junk == noErr);
            }
            break;
        default:
            // do nothing
            break;
    }
}

/////////////////////////////////////////////////////////////////////

static void SetupEndpointForThreads(EndpointRef ep)
{
    OSStatus junk;
   
    // Establish the modes of operation.  This sample uses
    // sync/blocking mode, with sync idle events that yield
    // time using the Thread Manager.

    junk = OTSetSynchronous(ep);
    OTAssert("SetupEndpointForThreads: OTSetSynchronous failed", junk == noErr);
   
    junk = OTSetBlocking(ep);
    OTAssert("SetupEndpointForThreads: OTSetBlocking failed", junk == noErr);
   
    junk = OTInstallNotifier(ep, YieldingNotifier, ep);
    OTAssert("SetupEndpointForThreads: OTInstallNotifier failed", junk == noErr);
   
    junk = OTUseSyncIdleEvents(ep, true);
    OTAssert("SetupEndpointForThreads: OTUseSyncIdleEvents failed", junk == noErr);
}

/////////////////////////////////////////////////////////////////////

static OSStatus BindEndpoint(EndpointRef ep, InetHost host, InetPort port)
{
    OSStatus err;
    TBind bindRequest;
    InetAddress requestAddr;
    TBind bindResponse;
    InetAddress responseAddr;

    // Set up to bind the endpoint.  Because we're listening for broadcasts,
    // we have to request kOTAnyInetAddress.
   
    OTInitInetAddress(&requestAddr, port, host);
   
    OTMemzero(&bindRequest, sizeof(TBind));
    bindRequest.addr.buf = (UInt8 *) &requestAddr;
    bindRequest.addr.len = sizeof(InetAddress);

    // Because the port might be in use, we have to check that XTI
    // has not given us another port (XTI is kinda lame in this respect).
    // So we set up bindResponse to collect the bound address.
   
    OTMemzero(&bindResponse, sizeof(TBind));
    bindResponse.addr.buf = (UInt8 *) &responseAddr;
    bindResponse.addr.maxlen = sizeof(InetAddress);
   
    // Do the bind and check that we got what we wanted.
   
    err = OTBind(ep, &bindRequest, &bindResponse);
    if (err == noErr) {
        if ( requestAddr.fPort != responseAddr.fPort ) {
            err = kEADDRINUSEErr;
        }
    }
    return err;
}

/////////////////////////////////////////////////////////////////////

static OTResult SetFourByteOption(EndpointRef ep,
                                    OTXTILevel level,
                                    OTXTIName  name,
                                    UInt32     value)
    // level and name must denote a four byte option that is
    // appropriate for the endpoint ep.  This routine sets the
    // option to value.  ep is assumed to be in synchronous
    // mode.
    //
    // If all goes well, the result is noErr.  If an error
    // occurs, the result is negative.  If the option could not
    // be negotiated, a positive result being one of (T_FAILURE,
    // T_PARTSUCCESS, T_READONLY, T_NOTSUPPORT) is returned
{
    OTResult    err;
    TOption     option;
    TOptMgmt    request;
    TOptMgmt    result;
   
    // Set up the option buffer to reflect the specific option
    // and value we want to set.  We use a TOption structure
    // to represent the option buffer.  TOption is specifically
    // defined to allow easy construction of 4 byte options.
    // If you want to negotiate different size options, or
    // multiple options in a single call, then constructing
    // the option buffer is a little trickier
   
    option.len      = kOTFourByteOptionSize;
    option.level    = level;
    option.name     = name;
    option.status   = 0;
    option.value[0] = value;

    // Set up the request for OTOptionManagement to point
    // to the option buffer we just filled out, and tell
    // it that we want to negotiate (ie set) the option.
   
    request.opt.buf = (UInt8 *) &option;
    request.opt.len = sizeof(option);
    request.flags   = T_NEGOTIATE;

    // Set up the reply for OTOptionManagement.  This is where
    // OTOptionManagement puts the result of the negotiation.
   
    result.opt.buf = (UInt8 *) &option;
    result.opt.maxlen = sizeof(option);

    // Call OTOptionManagement and then check that the value
    // was negotiated successfully.  Any value other than
    // T_SUCCESS is reported via the error result.
   
    err = OTOptionManagement(ep, &request, &result);

    if (err == noErr) {
        if (option.status != T_SUCCESS) {
            err = option.status;
        }
    }
               
    return err;
}

/////////////////////////////////////////////////////////////////////

static OSStatus GetSourceAndDestHosts(InetHost *sourceHost, InetHost *destHost)
{
    OSStatus err;
    InetInterfaceInfo info;
   
    err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
    if (err == noErr) {
        *sourceHost = info.fAddress;
        *destHost = info.fBroadcastAddr;
        if ( *destHost == kOTAnyInetAddress ) {
            // *destHost = (0xFFFFFFFF & ~info.fNetmask) | (info.fAddress & info.fNetmask);
            *destHost = 0xFFFFFFFF;
        }
    }
    return err;
}

/////////////////////////////////////////////////////////////////////

static pascal OSStatus EchoThread(void *junkParam)
{
    #pragma unused(junkParam)
    OSStatus err;
    OSStatus junk;
    OTResult result;
    EndpointRef ep;
    TEndpointInfo epInfo;
    UInt8 *dataBuffer;
    UInt8 *addrBuffer;
    TUnitData rcvRequest;
    OTFlags junkFlags;
    InetAddress *sourceAddr;
   
    dataBuffer = nil;
    addrBuffer = nil;
   
    ep = OTOpenEndpoint(OTCreateConfiguration(kUDPName), 0, nil, &err);

    // If the endpoint opens successfully...
   
    if (err == noErr) {
        SetupEndpointForThreads(ep);

        junk = OTGetEndpointInfo(ep, &epInfo);
        OTAssert("EchoThread: OTGetEndpointInfo failed", junk == noErr);
       
        dataBuffer = OTAllocMem(epInfo.tsdu);
        if (dataBuffer == nil) {
            err = kENOMEMErr;
        }
        addrBuffer = OTAllocMem(epInfo.addr);
        if (dataBuffer == nil) {
            err = kENOMEMErr;
        }
    }
   
    // Now bind the endpoint.
   
    if (err == noErr) {
        result = SetFourByteOption(ep, INET_IP, IP_REUSEADDR, 1);
        if (result > 0) {
            err = kENXIOErr;
        } else {
            err = result;
        }
    }
    if (err == noErr) {
        err = BindEndpoint(ep, kOTAnyInetAddress, kTestPort);
    }
   
    if (err == noErr) {

        // Tell the sending thread that we're bound and waiting for
        // packets to echo.  We do this because we want to make sure
        // that we bind before it does.
       
        gEchoThreadBound = true;
       
        // Repeatedly get data from the endpoint and echo it to
        // stdout.
       
        do {
            OTMemzero(&rcvRequest, sizeof(TUnitData));
            rcvRequest.addr.buf = addrBuffer;
            rcvRequest.addr.maxlen = epInfo.addr;
            rcvRequest.udata.buf = dataBuffer;
            rcvRequest.udata.maxlen = epInfo.tsdu;
           
            err = OTRcvUData(ep, &rcvRequest, &junkFlags);
            if (err == noErr) {
                sourceAddr = (InetAddress *) addrBuffer;

                printf("EchoThread: Got a packet!\n");
                printf("  size = %ld.\n", rcvRequest.addr.len);
                if ( sourceAddr->fAddressType == AF_INET ) {
                    printf("  source addr = %d.%d.%d.%d, source port = %d\n",
                                (int) ((sourceAddr->fHost >> 24) & 0x00FF),
                                (int) ((sourceAddr->fHost >> 16) & 0x00FF),
                                (int) ((sourceAddr->fHost >>  8) & 0x00FF),
                                (int) ((sourceAddr->fHost >>  0) & 0x00FF),
                                sourceAddr->fPort);
                } else {
                    printf("  unknown (fAddressType = %d)\n", ((InetAddress *) addrBuffer)->fAddressType);
                }
            } else if (err == kOTLookErr) {
                OTResult look;
               
                look = OTLook(ep);
                switch ( look ) {
                    case T_UDERR:
                        err = OTRcvUDErr(ep, nil);
                        break;
                    default:
                        printf("EchoThread: Got a kOTLookErr, look = %ld\n", look);
                        // leave err set to kOTLookErr
                        break;
                }
            }
            // fflush(stdout);
        } while (err == noErr);
    }
   
    // Clean up.
   
    if (addrBuffer != nil) {
        OTFreeMem(dataBuffer);
    }
    if (dataBuffer != nil) {
        OTFreeMem(addrBuffer);
    }
    if (ep != kOTInvalidEndpointRef) {
        junk = OTCloseProvider(ep);
        OTAssert("EchoThread: OTCloseProvider failed", junk == noErr);
    }
   
    if (err == noErr || err == userCanceledErr) {
        printf("EchoThread: Successful termination.\n");
    } else {
        printf("EchoThread: Terminated with error %d.\n", err);
    }
    return noErr;
}

/////////////////////////////////////////////////////////////////////

#define HackyTest 0

#if !HackyTest

struct sockaddr {
        unsigned short  sa_family;              /* address family */
        char            sa_data[14];            /* up to 14 bytes of direct address */
};

struct  ifreq {
#define IFNAMSIZ    36              /* Must be same as kMaxProviderNameSize %%% */
    char    ifr_name[IFNAMSIZ];     /* if name, e.g. "en0" */
    union {
        struct  sockaddr ifru_addr;
        struct  sockaddr ifru_dstaddr;
        struct  sockaddr ifru_broadaddr;
        short   ifru_flags;
        int ifru_metric;
        char    *ifru_data;
    } ifr_ifru;
#define ifr_addr    ifr_ifru.ifru_addr  /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr   /* other end of p-to-p link */
#define ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_flags   ifr_ifru.ifru_flags /* flags */
#define ifr_metric  ifr_ifru.ifru_metric    /* metric */
#define ifr_data    ifr_ifru.ifru_data  /* for use by interface */
};

#define SIOCGIFCONF     MIOC_CMD(MIOC_SIOC,20)

static struct ifreq gInterfaceArray[10];

static OSStatus FindInterfaceNameByHost(EndpointRef ep, InetHost host, char *interfaceName)
{
    OSStatus err;
    struct strioctl interfaceIoctl;
    SInt32 interfaceIndex;
   
    OTMemzero(&gInterfaceArray[0], sizeof(gInterfaceArray));

    interfaceIoctl.ic_cmd = SIOCGIFCONF;
    interfaceIoctl.ic_timout = 0;
    interfaceIoctl.ic_len = sizeof(gInterfaceArray);
    interfaceIoctl.ic_dp = (char *) &gInterfaceArray[0];

    err = OTIoctl(ep, I_STR, &interfaceIoctl);
   
    if (err == noErr) {
        interfaceName[0] = 0;
        for (interfaceIndex = 0; interfaceIndex < 10; interfaceIndex++) {
            if ( ((InetAddress *) &(gInterfaceArray[interfaceIndex].ifr_addr))->fHost == host ) {
                OTStrCopy(interfaceName, gInterfaceArray[interfaceIndex].ifr_name);
            }
        }
        if ( interfaceName[0] == 0 ) {
            err = kENXIOErr;
        }
    }
   
    return err;
}

#endif

#define OldWay 0
#if OldWay

static OSStatus NegotiateBroadcastInterface(EndpointRef ep, InetHost host)
{
    OTResult    err;
    TOptMgmt    request;
    TOptMgmt    result;
    struct {
        TOptionHeader optHeader;
        char interfaceName[kMaxProviderNameSize];
    } option;
   
    #if HackyTest
        #pragma unused(host)
        err = noErr;
        OTStrCopy(option.interfaceName, "pci1011,140");
    #else
        err = FindInterfaceNameByHost(ep, host, option.interfaceName);
    #endif
   
    if (err == noErr) {
        option.optHeader.len = sizeof(option);      // kOTOptionHeaderSize + OTStrLength(option.interfaceName) + 1;
        option.optHeader.level  = INET_IP;
        option.optHeader.name = IP_BROADCAST_IF;
        option.optHeader.status = 0;

        // Set up the request for OTOptionManagement to point
        // to the option buffer we just filled out, and tell
        // it that we want to negotiate (ie set) the option.
       
        request.opt.buf = (UInt8 *) &option;
        request.opt.len = option.optHeader.len;
        request.flags   = T_NEGOTIATE;

        // Set up the reply for OTOptionManagement.  This is where
        // OTOptionManagement puts the result of the negotiation.
       
        result.opt.buf = (UInt8 *) &option;
        result.opt.maxlen = sizeof(option);

        // Call OTOptionManagement and then check that the value
        // was negotiated successfully.  Any value other than
        // T_SUCCESS is reported via the error result.
       
        err = OTOptionManagement(ep, &request, &result);

        if (err == noErr) {
            if (option.optHeader.status != T_SUCCESS) {
                err = option.optHeader.status;
            }
        }
    }
   
    return err;
}

#else

#define IP_BROADCAST_IFADDR     0x1018  /* Set interface addr for broadcasts */

static OSStatus NegotiateBroadcastInterface(EndpointRef ep, InetHost host)
{
    OSStatus err;
   
//  host = 0x11cb15f8;      // 17.203.21.248 *** temp hack to test that IP_BROADCAST_IFADDR works
   
    err = SetFourByteOption(ep, INET_IP, IP_BROADCAST_IFADDR, host);

    return err;
}

#endif

/////////////////////////////////////////////////////////////////////

static OSStatus PrintSecondaryAddresses(InetInterfaceInfo* interfaceInfo, SInt32 interfaceIndex)
{
    OSStatus err;
    InetHost *secondaryAddressBuffer;
    UInt32   numberOfSecondaryAddresses;
    UInt32   addressIndex;

    secondaryAddressBuffer = nil;
   
    numberOfSecondaryAddresses = interfaceInfo->fIPSecondaryCount;
   
    if ( numberOfSecondaryAddresses > 0 ) {

        // Allocate a buffer for the secondary address info.
       
        err = noErr;
        secondaryAddressBuffer = (InetHost *) OTAllocMem( numberOfSecondaryAddresses * sizeof(InetHost) );
        if (secondaryAddressBuffer == nil) {
            err = kENOMEMErr;
        }
       
        // Ask OT for the list of secondary addresses on this interface.
       
        if (err == noErr) {
            err = OTInetGetSecondaryAddresses(secondaryAddressBuffer, &numberOfSecondaryAddresses, interfaceIndex);
        }
       
        // Start a server for each secondary address.
       
        for (addressIndex = 0; addressIndex < numberOfSecondaryAddresses; addressIndex++) {
            printf("secondaryAddressBuffer[%ld] = lx\n", addressIndex, secondaryAddressBuffer[addressIndex]);
        }
    }

    // Clean up.
   
    if (secondaryAddressBuffer != nil) {
        OTFreeMem(secondaryAddressBuffer);
    }

    return err;
}

enum
{
    kOTIPSingleLinkMultihomingVersion = 0x01300000
};

static OSStatus PrintIPAddresses(void)
{
    OSStatus err;
    Boolean haveIPSingleLinkMultihoming;
    NumVersionVariant otVersion;
    SInt32 interfaceIndex;
    InetInterfaceInfo info;
    Boolean done;

    haveIPSingleLinkMultihoming =
            ( Gestalt(gestaltOpenTptVersions, (long *) &otVersion) == noErr
                && (otVersion.whole >= kOTIPSingleLinkMultihomingVersion )
                && ( OTInetGetSecondaryAddresses != (void *) kUnresolvedCFragSymbolAddress));
   
    err = noErr;
    done = false;
    interfaceIndex = 0;
    do {
        done = ( OTInetGetInterfaceInfo(&info, interfaceIndex) != noErr );
        if ( ! done ) {
            printf("fAddress = lx\n", info.fAddress);
            if ( haveIPSingleLinkMultihoming ) {
                err = PrintSecondaryAddresses(&info, interfaceIndex);
            }
            interfaceIndex += 1;
        }
    } while (err == noErr && !done);
   
    return err;
}

static void PrintIPAddressesTest(void)
{
    OSStatus err;
   
    err = PrintIPAddresses();
    if (err == noErr) {
        printf("Success!\n");
    } else {
        printf("Failed with error %ld.\n", err);
    }
}

/////////////////////////////////////////////////////////////////////

static UInt32 gPacketsToSend = 0;

static UInt32 gCurrentPacketNumber = 0;

static pascal OSStatus SendThread(void *junkParam)
{
    #pragma unused(junkParam)
    OSStatus err;
    OSStatus junk;
    EndpointRef ep;
    OTResult result;
    InetHost sourceHost;
    InetHost destHost;
    TUnitData sndRequest;
    InetAddress destAddr;
    OTResult look;
    char dataString[256];
   
    ep = kOTInvalidEndpointRef;
   
    // Start by waiting for the echo thread to start up successfully.
   
    err = noErr;
    while ( err == noErr && ! gEchoThreadBound ) {
        err = MyYieldToAnyThread();
    }
   
    // Create the endpoint, set it up for threaded execution, set
    // up the IP_REUSEADDR option, and then bind it to one of the
    // interfaces.
   
    if (err == noErr) {
        ep = OTOpenEndpoint(OTCreateConfiguration(kUDPName), 0, nil, &err);
    }
    if (err == noErr) {
        SetupEndpointForThreads(ep);
       
        result = SetFourByteOption(ep, INET_IP, IP_REUSEADDR, 1);
        if (result > 0) {
            err = kENXIOErr;
        } else {
            err = result;
        }
    }
    if (err == noErr) {
        err = GetSourceAndDestHosts(&sourceHost, &destHost);
    }
    if (err == noErr) {
        err = BindEndpoint(ep, sourceHost, kTestPort);
    }
    if (err == noErr) {
        err = NegotiateBroadcastInterface(ep, sourceHost);
    }
    if (err == noErr) {
        do {
            if (gPacketsToSend == 0) {
                err = MyYieldToAnyThread();
            } else {
                OTInitInetAddress(&destAddr, kTestPort, destHost);

                gCurrentPacketNumber += 1;
                sprintf(dataString, "Broadcast Message %ld", gCurrentPacketNumber);
               
                OTMemzero(&sndRequest, sizeof(TUnitData));
                sndRequest.addr.buf = (UInt8 *) &destAddr;
                sndRequest.addr.len = sizeof(InetAddress);
                sndRequest.udata.buf = (UInt8 *) dataString;
                sndRequest.udata.len = OTStrLength(dataString);
               
                err = OTSndUData(ep, &sndRequest);
                if (err == kOTLookErr) {
                    look = OTLook(ep);
                    switch ( look ) {
                        case T_UDERR:
                            err = OTRcvUDErr(ep, nil);
                            break;
                        case T_DATA:
                            printf("SendThread: Got a T_DATA\n");
                            // leave err set to kOTLookErr
                            break;
                        default:
                            printf("SendThread: Got a kOTLookErr, look = %ld\n", look);
                            // leave err set to kOTLookErr
                            break;
                    }
                }
                // fflush(stdout);
                gPacketsToSend -= 1;
            }
        } while (err == noErr);
    }
   
    // Clean up.
   
    if (ep != kOTInvalidEndpointRef) {
        junk = OTCloseProvider(ep);
        OTAssert("SendThread: OTCloseProvider failed", junk == noErr);
    }
   
    if (err == noErr || err == userCanceledErr) {
        printf("SendThread: Successful termination.\n");
    } else {
        printf("SendThread: Terminated with error %d.\n", err);
    }
    return noErr;
}

/////////////////////////////////////////////////////////////////////
// Experimental hack to get SIOUX to execute threads while
// it's waiting for user input.  It seems to cause SIOUX
// to suffer horribly re-entrancy problems, so it's disabled
// at the moment.

#define WildlyDangerousHack 0

#if WildlyDangerousHack

    typedef pascal void (*TEIdleProc)(TEHandle hTE);

    enum {
        uppTEIdleProcInfo = kPascalStackBased
             | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(TEHandle)))
    };

    static UniversalProcPtr gOldTEIdle;
    static UniversalProcPtr gMyTEIdle;

    static pascal void MyTEIdle(TEHandle hTE)
    {
        long oldA5;
        OSStatus junk;
       
        oldA5 = SetCurrentA5();
       
        junk = YieldToAnyThread();
        OTAssert("MyTEIdle: YieldToAnyThread failed", junk == noErr);
       
        (void) SetA5(oldA5);
       
        #if GENERATINGCFM
            CallUniversalProc(gOldTEIdle, uppTEIdleProcInfo, hTE);
        #else
            ((TEIdleProc) gOldTEIdle)(hTE);
        #endif
    }

#endif

/////////////////////////////////////////////////////////////////////

static void PrintHelp(void)
{
    printf("?) Help\n");
    printf("s) Send a packet\n");
    printf("S) Send 10 packets\n");
    printf("p) Print IP addresses\n");
    printf("r) Run threads for a while\n");
    printf("q) Quit\n");
}

void main(void)
{
    OSStatus err;
    ThreadID echoThread;
    ThreadID sendThread;
    ThreadState junkState;
    char command[256];
    UInt32 startTime;
   
    printf("Hello Cruel World!\n");
    printf("QStandard.c\n");
   
    err = InitOpenTransport();
   
    if (err == noErr) {
   
        err = NewThread(kCooperativeThread,
                            (ThreadEntryProcPtr) EchoThread, nil,
                            0, kCreateIfNeeded,
                            nil,
                            &echoThread);
        if (err == noErr) {
            err = NewThread(kCooperativeThread,
                                (ThreadEntryProcPtr) SendThread, nil,
                                0, kCreateIfNeeded,
                                nil,
                                &sendThread);
        }
        if (err == noErr) {
       
            #if WildlyDangerousHack

                // Oh this is ugly.  Patch TEIdle to call YieldToAnyThread,
                // so that our threads run while the SIOUX window is waiting
                // for input.
               
                gMyTEIdle = NewRoutineDescriptor( (ProcPtr) MyTEIdle, uppTEIdleProcInfo, GetCurrentArchitecture());
               
                OTAssert("main: Could not create routine descriptor for patch", gMyTEIdle != nil);
               
                gOldTEIdle = GetToolboxTrapAddress(_TEIdle);
                SetToolboxTrapAddress(gMyTEIdle, _TEIdle);
       
            #endif
        }
        if (err == noErr) {
            PrintHelp();
            do {
                printf("Enter a command:\n");
               
                gets(command);
                switch ( command[0] ) {
                    case 's':
                        gPacketsToSend += 1;
                        break;
                    case 'S':
                        gPacketsToSend += 10;
                        break;
                    case 'r':
                        startTime = TickCount();
                        while ( TickCount() < (startTime + (3 * 60)) ) {
                            (void) MyYieldToAnyThread();
                        }
                        break;
                    case 'p':
                        PrintIPAddressesTest();
                        break;
                    case '?':
                        PrintHelp();
                        break;
                    case 'q':
                        gQuitNow = true;
                        break;
                    default:
                        printf("Huh?\n");
                        break;
                }
                fflush(stdout);
            } while ( ! gQuitNow );
           
            printf("Waiting for threads to terminate...\n");
           
            while ( GetThreadState(echoThread, &junkState) == noErr) {
                (void) MyYieldToAnyThread();
            }
            while ( GetThreadState(sendThread, &junkState) == noErr) {
                (void) MyYieldToAnyThread();
            }

            printf("\n");
        }
       
        CloseOpenTransport();
    }
   
    if (err == noErr) {
        printf("Success.\n");
    } else {
        printf("Failed with error %d.\n", err);
    }

    printf("Done.  Press command-Q to Quit.\n");
}
----------------------------------------------------------------------------
 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Receive UDP broadcast packets with OTRcvUData
      • From: "Matthieu Beghin" <email@hidden>
    • Re: Receive UDP broadcast packets with OTRcvUData
      • From: "Matthieu Beghin" <email@hidden>
References: 
 >Re: Receive UDP broadcast packets with OTRcvUData (From: "Matthieu Beghin" <email@hidden>)

  • Prev by Date: Character device synchronization with network interface
  • Next by Date: Re: Character device synchronization with network interface
  • Previous by thread: Re: Receive UDP broadcast packets with OTRcvUData
  • Next by thread: Re: Receive UDP broadcast packets with OTRcvUData
  • Index(es):
    • Date
    • Thread