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.
OTStreamDumper.c
/* |
File: OTStreamDumper.c |
Contains: Stream module to strlog all data going by. |
Written by: Quinn "The Eskimo!" |
Copyright: Copyright © 2000 by Apple Computer, Inc., All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
*/ |
///////////////////////////////////////////////////////////////// |
// MIB Setup |
// Rather than include "MoreSetup.h" I just declare my assert routine |
// inline (see below). This module is meant as a programming tool, not |
// for end user machines. |
// Mac OS Interfaces |
#include <OpenTransportKernel.h> |
///////////////////////////////////////////////////////////////////// |
static void MoreAssertQ(Boolean mustBeTrue) |
{ |
if ( ! mustBeTrue ) { |
DebugStr("\pMoreAssertQ: Assertion failure."); |
} |
} |
///////////////////////////////////////////////////////////////////// |
#pragma mark ----- Data Structures ----- |
enum { |
kStreamDumpPerStreamDataMagic = 'StrD' |
}; |
struct PerStreamData |
{ |
OSType magic; // must be kStreamDumpPerStreamDataMagic |
UInt16 streamID; |
}; |
typedef struct PerStreamData PerStreamData, *PerStreamDataPtr; |
static PerStreamDataPtr GetPerStreamData(queue_t* readOrWriteQ) |
// Get the per-stream data for the given queue. |
// |
// Environment: any standard STREAMS entry point |
{ |
PerStreamDataPtr streamData; |
streamData = (PerStreamDataPtr) readOrWriteQ->q_ptr; |
MoreAssertQ(streamData != nil); |
MoreAssertQ(streamData->magic == kStreamDumpPerStreamDataMagic); |
return streamData; |
} |
static char* gStreamList = nil; |
static UInt16 gNextStreamID = 0; |
///////////////////////////////////////////////////////////////////// |
#pragma mark ----- Standard Entry Points ----- |
static SInt32 StreamDumpOpen(queue_t* rdq, dev_t* dev, SInt32 flag, SInt32 sflag, cred_t* creds) |
// This routine is called by STREAMS when a new stream is connected to |
// our module. |
// |
// Environment: standard STREAMS entry point |
{ |
int err; |
PerStreamDataPtr streamData; |
err = noErr; |
if ( rdq->q_ptr != nil ) { |
goto done; |
} |
if ( (err == noErr) && (sflag != MODOPEN) ) { |
err = ENXIO; |
} |
if (err == noErr) { |
err = mi_open_comm(&gStreamList, sizeof(PerStreamData), rdq, dev, flag, sflag, creds); |
if ( err == noErr ) { |
// Note that we can't call GetPerStreamData because the magic is not set up yet. |
streamData = (PerStreamDataPtr) rdq->q_ptr; |
OTMemzero(streamData, sizeof(PerStreamData)); |
streamData->magic = kStreamDumpPerStreamDataMagic; |
streamData->streamID = OTAtomicAdd16(1, (SInt16 *) &gNextStreamID); |
} |
} |
done: |
return err; |
} |
static SInt32 StreamDumpClose(queue_t* rdq, SInt32 flags, cred_t* credP) |
// This routine is called by STREAMS when a stream is being |
// disconnected from our module (ie closed). |
// |
// Environment: standard STREAMS entry point |
{ |
#pragma unused(flags) |
#pragma unused(credP) |
(void) mi_close_comm(&gStreamList, rdq); |
return 0; |
} |
static Boolean IsReadQ(queue_t* q) |
// Returns true if q is the read queue of a queue pair. |
{ |
return ( (q->q_flag & QREADR) != 0 ); |
} |
static void DumpCommon(queue_t* q, mblk_t* mp) |
// Common code, called by both StreamDumpWritePut and |
// StreamDumpReadPut, that logs the message via strlog. |
{ |
PerStreamDataPtr streamData; |
const char * primStr; |
const char * qStr; |
char lineBuffer[256]; |
streamData = GetPerStreamData(q); |
primStr = nil; |
if ( mp->b_datap->db_type == M_DATA ) { |
primStr = "M_DATA"; |
} else if ( mp->b_datap->db_type == M_PROTO) { |
switch ( ((T_primitives *) mp->b_rptr)->primType ) { |
case T_UNITDATA_IND: |
primStr = "T_UNITDATA_IND"; |
break; |
case T_UNITDATA_REQ: |
primStr = "T_UNITDATA_REQ"; |
break; |
case T_DATA_IND: |
primStr = "T_DATA_IND"; |
break; |
case T_DATA_REQ: |
primStr = "T_DATA_REQ"; |
break; |
default: |
// do nothing |
break; |
} |
// Always move to the next mblk because if primType is not |
// a data message then primStr is still nil and we never look at |
// mp. |
mp = mp->b_cont; |
} |
if (primStr != nil) { |
if ( IsReadQ(q) ) { |
qStr = "Read"; |
} else { |
qStr = "Write"; |
q = RD(q); |
} |
// Log some basic info about the message. |
(void) strlog(9993, streamData->streamID, kOTLvlInfoOnly, SL_TRACE | SL_NOTE, "%s (%s)", primStr, qStr); |
// Log the contents of each message block. |
while (mp != nil) { |
UInt32 mpSize; |
UInt32 i; |
UInt32 numPrintables; |
mpSize = MBLK_SIZE(mp); |
(void) strlog(9993, streamData->streamID, kOTLvlInfoOnly, SL_TRACE | SL_NOTE, |
"%*m", mpSize, mp->b_rptr); |
// If the message block's data is too big for our line buffer, don't |
// even attempt to log it as ASCII. |
if ( mpSize < 256 ) { |
BlockMoveData(mp->b_rptr, lineBuffer, mpSize); |
lineBuffer[mpSize] = 0; // terminate string will null |
numPrintables = 0; |
for (i = 0; i < mpSize; i++) { |
if ( lineBuffer[i] >= 32 && lineBuffer[i] < 127 ) { |
numPrintables += 1; |
} else { |
// Substitute '.' for non-printable characters. |
// CR and LF are printable (for the purposes of deciding whether |
// or not to print the ASCII at all). |
if ( lineBuffer[i] == 13 || lineBuffer[i] == 10 ) { |
numPrintables += 1; |
} |
lineBuffer[i] = '.'; |
} |
} |
if (numPrintables == mpSize) { |
(void) strlog(9993, streamData->streamID, kOTLvlInfoOnly, SL_TRACE | SL_NOTE, "Ò%sÓ", lineBuffer); |
} |
} |
mp = mp->b_cont; |
} |
} |
} |
static SInt32 StreamDumpWritePut(queue_t* q, mblk_t* mp) |
// This routine is called by STREAMS when it has a message for our |
// module from upstream. We call DumpCommon and then pass the |
// along. |
// |
// Environment: standard STREAMS entry point |
{ |
DumpCommon(q, mp); |
putnext(q, mp); |
return 0; |
} |
static SInt32 StreamDumpReadPut(queue_t* q, mblk_t* mp) |
// This routine is called by STREAMS when it has a message for our |
// module from downstream. We call DumpCommon and then pass the |
// message along. |
// |
// Environment: standard STREAMS entry point |
{ |
DumpCommon(q, mp); |
putnext(q, mp); |
return 0; |
} |
///////////////////////////////////////////////////////////////////// |
#pragma mark ----- Static Declaration Structures ----- |
static struct module_info gModuleInfo = |
{ |
9993, // Module Number, only useful for debugging |
"OTStreamDumper", // Name of module |
0, // Minimum data size |
INFPSZ, // Maximum data size |
16384, // Hi water mark for queue |
4096 // Lo water mark for queue |
}; |
static struct qinit gReadInit = |
{ |
StreamDumpReadPut, // Put routine for "incoming" data |
nil, // Service routine for "incoming" data |
StreamDumpOpen, // Our open routine |
StreamDumpClose, // Our close routine |
nil, // No admin routine |
&gModuleInfo // Our module_info |
}; |
static struct qinit gWriteInit = |
{ |
StreamDumpWritePut, // Put routine for client data |
nil, // Service routine for client data |
nil, // open field only used in read-side structure |
nil, // close field only used in read-side structure |
nil, // admin field only used in read-side structure |
&gModuleInfo // Our module_info |
}; |
static struct streamtab theStreamTab = |
{ |
&gReadInit, // Our read-side qinit structure |
&gWriteInit, // Our write-side qinit structure |
0, // We are not a mux, so set this to nil |
0 // We are not a mux, so set this to nil |
}; |
///////////////////////////////////////////////////////////////////// |
#pragma mark ----- Macintosh-specific Static Structures ----- |
static struct install_info theInstallInfo = |
{ |
&theStreamTab, // Stream Tab pointer |
kOTModIsModule + kOTModUpperIsTPI + kOTModIsFilter, |
// Tell OT that we are a driver, not a module |
// TPI may not be right if we're pushed on a DLPI |
// stream, but OT doesn't look at that flag anyway. |
SQLVL_MODULE, // Synchronization level, module level for the moment |
0, // Shared writer list buddy |
0, // Open Transport use - always set to 0 |
0 // Flag - always set to 0 |
}; |
// Prototypes for the exported routines below. |
extern Boolean InitStreamModule(void *portInfo); |
extern void TerminateStreamModule(void); |
extern install_info* GetOTInstallInfo(); |
#pragma export list GetOTInstallInfo, InitStreamModule, TerminateStreamModule |
// Export entry point |
extern Boolean InitStreamModule(void *portInfo) |
// Initialises the module before the first stream is opened. |
// Should return true if the module has started up correctly. |
// |
// Environment: Always called at SystemTask time. |
{ |
#pragma unused(portInfo) |
// Drop into MacsBug so that we can set breakpoints if necessary. |
#if MORE_DEBUG |
DebugStr("\pOTStreamDumper: InitStreamModule"); |
#endif |
return true; |
} |
extern void TerminateStreamModule(void) |
// Shuts down the module after the last stream has been |
// closed. |
// |
// Environment: Always called at SystemTask time. |
{ |
} |
extern install_info* GetOTInstallInfo() |
// Return pointer to install_info to STREAMS. |
{ |
return &theInstallInfo; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22