Re: bootp example
Re: bootp example
- Subject: Re: bootp example
- From: Quinn <email@hidden>
- Date: Wed, 9 Jul 2003 10:47:16 +0100
At 10:50 -0400 25/6/03, Matt Mashyna wrote:
I need to implement a bootp server for carbon (yes 9 & X) so I can
listen for a router reboot. Can anyone point me to some example code
?
I don't know of any official UDP broadcast send/received samples.
However, my experience is that this isn't particularly tricky. The
most common gotchas associated with UDP broadcast reception are
covered by DTS Q&A NW 53.
<
http://developer.apple.com/qa/nw/nw53.html>
I also dug through my archive of snippets written for developers and
found some code that might be useful. It contains too many ugly
experiments to post as a whole, but I've included some relevant
routines at the end of this email.
Note that this was written for traditional Mac OS (pre-Carbon). I
decided not to update it for Carbon because we're no longer
encouraging developers to use the OT API for new code.
S+E
--
Quinn "The Eskimo!" <
http://www.apple.com/developer/>
Apple Developer Technical Support * Networking, Communications, Hardware
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 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;
}
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;
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 = BindEndpoint(ep, kOTAnyInetAddress, kTestPort);
}
if (err == noErr) {
do {
if (gPacketsToSend == 0) {
err = MyYieldToAnyThread();
} else {
OTInitInetAddress(&destAddr, kTestPort, 0xFFFFFFFF);
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;
}
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.