sock = OTOpenEndpointInContext(OTCreateConfiguration(kUDPName),
0,nil,&osErr_, NULL);
if(osErr_!=noErr || sock ==
kOTInvalidEndpointRef)
return -1;
----- Original Message -----
Sent: Thursday, November 04, 2004 12:09
AM
Subject: 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
email sent to email@hidden