Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
OTPingSample.c
/* |
File: OTPingSample.c |
Contains: A trivial ping implementation. |
Written by: Quinn "The Eskimo!" |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source 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 source |
code, but that you've made changes. |
Change History (most recent first): |
7/23/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include <stdio.h> |
#include <OpenTransport.h> |
#include <OpenTptInternet.h> |
#include <string.h> |
#include <Events.h> |
///////////////////////////////////////////////////////////////////// |
static UInt16 ChecksumBuffer(UInt16* buf, size_t len) |
{ |
// This checksum implementation requires the buffer to be an even number of bytes long. |
UInt32 sum; |
size_t nwords; |
nwords = len / 2; |
sum = 0; |
while (nwords > 0) { |
sum += *buf; |
buf++; |
nwords -= 1; |
} |
sum = (sum >> 16 ) + (sum & 0xffff); |
sum += (sum >> 16); |
return ~sum; |
} |
///////////////////////////////////////////////////////////////////// |
static OSStatus CreateAndConfigICMP(EndpointRef *ep) |
{ |
OSStatus err; |
*ep = OTOpenEndpoint(OTCreateConfiguration(kRawIPName), 0, nil, &err); |
if (err == noErr) { |
err = OTBind(*ep, nil, nil); |
// no others options to negotiate at this stage |
// You might think we need to negotiate the XTI_GENERIC/XTI_PROTOTYPE |
// option to request ICMP packets (ie protocol 2). This is not |
// necessary because rawip endpoints default to that protocol. |
} |
return (err); |
} |
///////////////////////////////////////////////////////////////////// |
static OSStatus LookupName(InetSvcRef inet_services, char *host_name, InetHost *host_addr) |
{ |
OSStatus err; |
InetHostInfo response; |
memset(&response, 0, sizeof(response)); |
err = OTInetStringToAddress(inet_services, host_name, &response); |
if (err == noErr) { |
*host_addr = response.addrs[0]; |
} |
return (err); |
} |
///////////////////////////////////////////////////////////////////// |
enum { |
kOurMagic = 'Quin' |
}; |
struct PingPacket { |
UInt8 pType; |
UInt8 pCode; |
UInt16 pChecksum; |
UInt16 pID; |
UInt16 pSeqNum; |
OSType pMagic; |
}; |
typedef struct PingPacket PingPacket, *PingPacketPtr; |
///////////////////////////////////////////////////////////////////// |
static OSStatus SendICMP(EndpointRef ep, InetHost dest, UInt16 seq_number) |
{ |
OSStatus err; |
InetAddress dest_addr; |
TUnitData udata; |
PingPacket ping_data; |
OTInitInetAddress(&dest_addr, 0, dest); |
ping_data.pType = 8; |
ping_data.pCode = 0; |
ping_data.pChecksum = 0; // dummy checksum of 0 for purposes of checksum calculation |
ping_data.pID = 666; |
ping_data.pSeqNum = seq_number; |
ping_data.pMagic = kOurMagic; |
ping_data.pChecksum = ChecksumBuffer((UInt16 *) &ping_data, sizeof(ping_data)); |
udata.addr.len = sizeof(dest_addr); |
udata.addr.buf = (unsigned char *) &dest_addr; |
udata.opt.len = 0; |
udata.opt.buf = nil; |
udata.udata.len = sizeof(ping_data); |
udata.udata.buf = (UInt8 *) &ping_data; |
err = OTSndUData(ep, &udata); |
return (err); |
} |
///////////////////////////////////////////////////////////////////// |
// we use this buffer to hold incoming ICMP packets |
static UInt8 icmp_data[5000]; |
///////////////////////////////////////////////////////////////////// |
static OSStatus WaitAndPrintICMPs(EndpointRef ep, UInt16 seq_number, Boolean *got_response) |
{ |
TUnitData udata; |
long start_time; |
OSStatus err; |
InetAddress src_addr; |
PingPacketPtr ping_data_ptr; |
*got_response = false; |
start_time = TickCount(); |
// Wait for 5 seconds and print out any ICMP packets we get back. |
do { |
// Set up the received... |
udata.addr.buf = (UInt8*) &src_addr; |
udata.addr.maxlen = sizeof(struct InetAddress); |
udata.opt.buf = nil; |
udata.opt.maxlen = 0; |
udata.udata.buf = icmp_data; |
udata.udata.maxlen = sizeof(icmp_data); |
// Look for a packet... |
err = OTRcvUData(ep, &udata, nil); |
if (err == noErr) { |
// Print out salient information from the packet... |
printf("¥¥¥Got ICMP!¥¥¥\n"); |
printf("ICMP from = %d.%d.%d.%d\n", icmp_data[12], icmp_data[13], icmp_data[14], icmp_data[15]); |
ping_data_ptr = (PingPacketPtr) &icmp_data[20]; |
printf("ICMP type = %d\n", ping_data_ptr->pType); |
printf("ICMP code = %d\n", ping_data_ptr->pCode); |
if (ping_data_ptr->pType == 0 |
&& ping_data_ptr->pID == 666 |
&& ping_data_ptr->pSeqNum == seq_number |
&& ping_data_ptr->pMagic == kOurMagic) { |
*got_response = true; |
} |
fflush(stdout); |
} else if (err == kOTNoDataErr) { |
err = noErr; |
} |
} while (err == noErr && TickCount() < start_time + 5 * 60); |
return (err); |
} |
///////////////////////////////////////////////////////////////////// |
static OSStatus DoPing(InetHost dest) |
{ |
OSStatus err; |
EndpointRef icmp_ep = nil; |
UInt16 seq_number; |
UInt16 lost; |
Boolean got_response; |
// Create the endpoint and negotiate the options... |
err = CreateAndConfigICMP(&icmp_ep); |
// Do the main ping loop... |
seq_number = 0; |
lost = 0; |
do { |
printf("\nSending ping...\n"); |
err = SendICMP(icmp_ep, dest, seq_number); |
if (err == noErr) { |
err = WaitAndPrintICMPs(icmp_ep, seq_number, &got_response); |
} |
if (err == noErr) { |
if (!got_response) { |
lost += 1; |
} |
seq_number += 1; |
} |
} while (err == noErr && seq_number < 5); |
if (err == noErr) { |
printf("Ping complete. %d packets sent. %d packets lost. %d%% packet loss.\n", seq_number, lost, lost * 100 / seq_number); |
} |
// clean up |
if (icmp_ep != nil) { |
(void) OTCloseProvider(icmp_ep); |
} |
return err; |
} |
///////////////////////////////////////////////////////////////////// |
void main(void) { |
OSStatus err; |
char host_name[256]; |
InetHost host_addr; |
InetSvcRef inet_services = nil; |
printf("Hello Cruel World!\n"); |
err = InitOpenTransport(); |
if (err == noErr) { |
inet_services = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err); |
if (err == noErr) { |
printf("Enter name of host to ping:\n"); |
gets(host_name); |
err = LookupName(inet_services, host_name, &host_addr); |
} |
if (err == noErr) { |
err = DoPing(host_addr); |
} |
if (inet_services != nil) { |
OTCloseProvider(inet_services); |
} |
CloseOpenTransport(); |
} |
if (err == noErr) { |
printf("Success!\n"); |
} else { |
printf("Failure! Error = %d.\n", err); |
} |
printf("Done. Press command-Q to Quit.\n"); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22