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.
OTDumpInternetStatus.c
/* |
File: OTDumpInternetStatus.c |
Contains: |
Written by: Quinn "The Eskimo!" |
Copyright: Copyright © 1998-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/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
//#define qDebug 1 |
///////////////////////////////////////////////////////////////////// |
// Pick up standard C stuff. |
#include <stdio.h> |
#include <string.h> |
///////////////////////////////////////////////////////////////////// |
// Pick up standard OT APIs. |
#include <OpenTptInternet.h> |
///////////////////////////////////////////////////////////////////// |
// Pick up low-level OT APIs. |
#include <Files.h> |
#include <OpenTptClient.h> |
#include <OTDebug.h> |
///////////////////////////////////////////////////////////////////// |
// Pick up the symbolic name of the various OT modules. |
#include <modnames.h> |
///////////////////////////////////////////////////////////////////// |
// OTDebugStr is not defined in any OT header files, but it is |
// exported by the libraries, so we define the prototype here. |
extern pascal void OTDebugStr(const char* str); |
///////////////////////////////////////////////////////////////////// |
// The following equates are actually exported by <miioccom.h>, but |
// they commented out for some reason )-: |
// #include <miioccom.h> |
#define MIOC_ND 'c' /* ioctl's for Mentat's nd device */ |
// The following equates define the two "Name Dispatch" ioctls |
// for setting and getting OT internal parameters. |
#define ND_GET MIOC_CMD(MIOC_ND, 0) /* Get a value */ |
#define ND_SET MIOC_CMD(MIOC_ND, 1) /* Set a value */ |
///////////////////////////////////////////////////////////////////// |
// The name of the Name Dispatch variables we display. |
#define ARP_ND_CACHE_REPORT "arp_cache_report" |
// ARP cache report |
#define IP_ND_INTERFACE_STATUS "ip_ipif_status" |
// List of active logical interfaces |
#define IP_ND_LINK_STATUS "ip_ill_status" |
// List of active physical interfaces |
#define IP_ND_ROUTE_STATUS "ip_ire_hash" |
// List of IP Routing Entries (IREs), grouped |
// by table in the order searched. |
#define IP_ND_ROUTE_STATUS2 "ip_ire_status" |
// List of IP Routing Entries (IREs) without |
// grouping. |
#define TCP_ND_STATUS "tcp_status" |
// TCP status |
#define UDP_ND_STATUS "udp_status" |
// UDP status |
///////////////////////////////////////////////////////////////////// |
static OSStatus CreateStatusStream(StreamRef *result) |
// Create a raw stream to which we can send the various |
// status reports. We do this by opening the IP driver, |
// and pushing the other modules directly on top of it. |
// This arrangement is just for convenience. We could |
// just have easily opened the null driver and pushed |
// the module of interest on top. |
{ |
OSStatus err; |
OSStatus junk; |
StreamRef strm; |
// Open up a raw stream to the IP device. |
strm = OTStreamOpen(MI_IP_NAME, 0, &err); |
if (err == noErr) { |
// To make this simpler we're going to use sync/blocking mode. |
OTStreamSetBlocking(strm); |
OTStreamSetSynchronous(strm); |
} |
// Push the various modules of interest on top of the stream. |
if (err == noErr) { |
err = OTStreamIoctl(strm, I_PUSH, MI_ARPM_NAME); |
} |
if (err == noErr) { |
err = OTStreamIoctl(strm, I_PUSH, MI_TCPM_NAME); |
} |
if (err == noErr) { |
err = OTStreamIoctl(strm, I_PUSH, MI_UDPM_NAME); |
} |
// Clean up and setup result to either be valid or nil. |
if (err == noErr) { |
*result = strm; |
} else { |
if (strm != kOTInvalidStreamRef) { |
junk = OTStreamClose(strm); |
OTAssert("CreateStatusStream: OTStreamClose failed", junk == noErr); |
} |
*result = kOTInvalidStreamRef; |
} |
return err; |
} |
static void DumpNameDispatchReport(StreamRef strm, char *ndName, char *userVisibleName) |
// Dumps a Name Dispatch (ND) report to standard out. strm |
// is a raw stream that contains the module from which the |
// report is to be extracted. ndName is the Name Dispatch |
// name of the report. userVisibleName is the name of the report |
// in user terminology (only used to make the printout sensible). |
// |
// The general principle is as follows. We send an Name Dispatch ioctl |
// down strm. The relevant module catches the ioctl, creates the |
// report (as text, with null characters as the line terminator) |
// and sends it back to us. The stream head copies the data back |
// into our ioctl buffer. |
// |
// The only tricky thing is to judge the size of the buffer to |
// allocate. We do this in two passes. In the first pass, |
// we create a minimum sized buffer and use it for the ioctl. |
// The ioctl result comes back as the size of the buffer we |
// should have allocated. We then reallocate the buffer |
// and issue the ioctl again. Obviously the size of the report |
// could change between successive ioctls, so we have to |
// loop until it works correctly. |
{ |
OSStatus err; |
struct strioctl ndIoctl; |
SInt32 i; |
char *dataBuffer; |
SInt32 dataBufferSize; |
SInt32 minimumDataBufferSize; |
SInt32 ioctlResult; |
Boolean done; |
printf("Dumping %s (%s)\n\n", userVisibleName, ndName); |
// Allocate a minimum sized buffer for the first ioctl call. |
// It's the length of the string, plus space for the null terminator, |
// plus space for an extra null. |
dataBuffer = nil; |
dataBufferSize = OTStrLength(ndName) + 1 + 1; |
minimumDataBufferSize = dataBufferSize; |
done = false; |
do { |
OTAssert("DumpNameDispatchReport: dataBuffer should have been disposed in the looping case", dataBuffer == nil); |
// Allocate the memory according to our current guess as to dataBufferSize. |
err = noErr; |
dataBuffer = OTAllocMem( dataBufferSize ); |
if (dataBuffer == nil) { |
err = kENOMEMErr; |
} |
if (err == noErr) { |
// Copy the name of the ND variable we're trying |
// to get into our buffer. |
OTStrCopy(dataBuffer, ndName); |
// Now put a null after the name in the data buffer. |
// This is because ND requests must be made up |
// of two strings, right after one another in the |
// buffer. |
dataBuffer[ OTStrLength(ndName) + 1 ] = 0; |
// The ND_GET ioctl returns a value and sets ic_len. A negative |
// value is an error and you can give up now (-: The rule for |
// positive values is a bit weirder. ic_len is always set |
// to the amount of data that is actually returned. If the |
// data available exceeds the available buffer space (as |
// defined by the ic_len on input), the ioctl returns |
// a positive number that is the amount of buffer space |
// needed. So we first call it with a minimal buffer |
// then give it the buffer space it requires. Obviously |
// there's a concurrency race here; we loop until our |
// buffer is big enough. |
// First get the size of data buffer we need to allocate. |
ndIoctl.ic_cmd = ND_GET; |
ndIoctl.ic_timout = 0; |
ndIoctl.ic_len = dataBufferSize; |
ndIoctl.ic_dp = dataBuffer; |
ioctlResult = OTStreamIoctl(strm, I_STR, &ndIoctl); |
// printf("¥¥¥ dataBufferSize = %ld, ic_len = %ld, ioctlResult = %ld\n", dataBufferSize, ndIoctl.ic_len, ioctlResult); |
if (ioctlResult < 0) { |
err = ioctlResult; |
} else { |
if (ioctlResult <= dataBufferSize) { |
// The report fit into dataBuffer, so let's |
// just print it out and we're done. Remember that |
// the report uses nulls as line terminators, so we |
// have to print it character by character )-: |
err = noErr; |
for (i = 0; i < ndIoctl.ic_len; i++) { |
if (dataBuffer[i] == 0) { |
putchar('\n'); |
} else { |
putchar(dataBuffer[i]); |
} |
} |
done = true; |
} else { |
// The allocated data buffer is the wrong size, |
// so we deallocate and loop. |
OTAssert("DumpNameDispatchReport: Should have a data buffer here", dataBuffer != nil); |
OTFreeMem(dataBuffer); |
dataBuffer = nil; |
// In this case, the ioctl has returned the size that |
// the buffer /should have been/ to get all the info. We |
// set dataBufferSize to that value and loop. |
// |
// The buffer that we allocate should be able to hold |
// the request (ie the string (with null terminator) |
// and the second null). If the ioctlResult comes |
// back too small, we're going to die when copying |
// the string into the new buffer. However, the ioctlResult |
// should be bigger than the buffer, because otherwise it |
// wouldn't have failed. So we just assert that |
// ioctlResult >= minimumDataBufferSize, just to be sure. |
OTAssert("DumpNameDispatchReport: ioctl failed but it should have succeeded", ioctlResult >= minimumDataBufferSize); |
dataBufferSize = ioctlResult; |
} |
} |
} |
} while (err == noErr & ! done ); |
// Clean up. |
if (dataBuffer != nil) { |
OTFreeMem(dataBuffer); |
} |
if (err == noErr) { |
printf("Success!\n"); |
} else { |
printf("Failed with error %ld.\n", err); |
} |
printf("\n\n"); |
} |
///////////////////////////////////////////////////////////////////// |
void main(void) |
{ |
OSStatus err; |
OSStatus junk; |
StreamRef strm; |
InetInterfaceInfo junkInfo; |
printf("Hello Cruel World!\n"); |
printf("OTDumpInternetStatus -- Dumps the state of the OT TCP/IP stack to stdout\n\n"); |
err = InitOpenTransport(); |
if (err == noErr) { |
err = OTInetGetInterfaceInfo(&junkInfo, kDefaultInetInterface); |
if (err != noErr) { |
printf("This report is not meaningful unless the TCP/IP stack is loaded.\n"); |
printf("You can still get the report, it just low on useful content.\n"); |
printf("\n"); |
err = noErr; |
} |
if (err == noErr) { |
// Create the raw stream from which we're going to extract |
// report information. This stream contains all the TCP/IP |
// modules ganged together in one convenient package. |
err = CreateStatusStream(&strm); |
if (err == noErr) { |
// Get and dump each report, one at a time. |
DumpNameDispatchReport(strm, ARP_ND_CACHE_REPORT, "ARP Cache"); |
DumpNameDispatchReport(strm, IP_ND_INTERFACE_STATUS, "IP Logical Interfaces"); |
DumpNameDispatchReport(strm, IP_ND_LINK_STATUS, "IP Physical Interfaces"); |
DumpNameDispatchReport(strm, IP_ND_ROUTE_STATUS, "IP Routing Table"); |
DumpNameDispatchReport(strm, IP_ND_ROUTE_STATUS2, "IP Routing Table (without grouping)"); |
DumpNameDispatchReport(strm, TCP_ND_STATUS, "TCP Status"); |
DumpNameDispatchReport(strm, UDP_ND_STATUS, "UDP Status"); |
// Clean up. |
junk = OTStreamClose(strm); |
OTAssert("main: OTStreamClose failed", junk == noErr); |
} |
} |
CloseOpenTransport(); |
} |
if (err == noErr) { |
printf("Success.\n"); |
} else { |
printf("Failed with 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