•OT_Classes/TNetworkSession.cp

//  TNetworkSession.cp - Macintosh OpenTransport Network Server class object
// 
// Apple Macintosh Developer Technical Support
// Written by:  Vinne Moscaritolo
//
//  Copyright (work in progress)  Apple Computer, Inc All rights reserved.
//
// 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.
// 
 
#include "TNetworkSession.h"
#include "TNetworkAcceptor.h"
 
 
// ---------------------------------------------------------------------------
//   NotifyProc (queue up an event)
// ---------------------------------------------------------------------------
//   TNetworkSession OT Notifier Proc  
 
pascal void TNetworkSession::NotifyProc( TNetworkSession* theSession, OTEventCode theEvent, OTResult theResult, void* theParam)
{   
    try
    {
//// No-copy memory was released
            if(theEvent == T_MEMORYRELEASED) TNetworkBuf::Release(theParam); 
            
// Data avail at endpoint
            else if (theEvent == T_DATA)  theSession->EventDataAvail();
        
// queue all others
                else QUEUE_NET_EVENT( theSession, theEvent, theResult, theParam);
    }
 
    catch (TNetworkException &ex)
    {
                DebugStr("\p TNetworkSession::NotifyProc -- Network Exception.. ");
    }
    
    catch(TMacException &ex)
    {
                DebugStr("\p TNetworkSession::NotifyProc -- Mac Exception.. ");
    }
    
    catch(...)      // catch everything
    {
                DebugStr("\p TNetworkSession::NotifyProc -- Other Exception.. ");
    } 
    
}
 
 
// ---------------------------------------------------------------------------
//   TNetworkSession
// ---------------------------------------------------------------------------
//  Default Constructor
 
TNetworkSession::TNetworkSession(TNetworkAcceptor* theServer) 
{
    TNetworkEndpointDescriptor* theEPD;
    
// Setup a new endpoint
    fEndPoint = kOTInvalidEndpointRef;
    fData           = nil;
    fServer     = theServer;
    
    theEPD = theServer->GetEPD();
    
  ThrowIfOTErr( ::OTAsyncOpenEndpoint(theEPD->GetConfiguration() ,0,&fInfo, NotifyProc, this ) );
 
}
 
// ---------------------------------------------------------------------------
//   ~TNetworkListener
// ---------------------------------------------------------------------------
//  Destructor
 
TNetworkSession::~TNetworkSession()
{
    // close up enpoint
        if(fEndPoint !=  kOTInvalidEndpointRef) ::OTCloseProvider(fEndPoint);
        if( fData) delete fData;
};
 
 
// ---------------------------------------------------------------------------
//   TNetworkAcceptor::Done(  )
// ---------------------------------------------------------------------------
//  Session Thread completed..
 
void TNetworkSession::Done()
{
    OTResult state = ::OTGetEndpointState(fEndPoint);
    
// If your not shutdown yet
    if(state == T_DATAXFER) {
    
// flush out all waiting data
        fioStream << flush;
            
// and disconnect the endpoint
    if( (fInfo.flags == T_COTS_ORD) || (fInfo.flags == T_TRANS_ORD))
        ::OTSndOrderlyDisconnect(fEndPoint);
    else 
        ::OTSndDisconnect (fEndPoint,&fCallInfo);
        }
        
}
 
 
 
// ---------------------------------------------------------------------------
//   TNetworkSession::HandleEvent (TNetworkEvent*)
// ---------------------------------------------------------------------------
//  Network Server Event Handler
 
void TNetworkSession::HandleEvent (TNetworkEvent* theEvent)
{
    switch ( theEvent->fEvent ){
 
///// OpenEndpoint Completed
            case T_OPENCOMPLETE:    
                     EventOpenComplete(theEvent);
                    break;
///// Endpoint accepted connection 
            case T_PASSCON: 
                     EventPassCon(theEvent);
                    break;
///// Client Quit 
            case T_DISCONNECT:              
                    EventDisconnect(theEvent);
                    break;
///// remote client request release
            case T_ORDREL:
                    EventOrdRelease(theEvent);
                    break;
///// Connection Torn Down
            case T_DISCONNECTCOMPLETE:
                    EventDisconnectComplete(theEvent);
                    break;
///// Winding down
            case T_UNBINDCOMPLETE:
                    EventUnbindComplete(theEvent);
                    break;
//// Data Available
            case T_DATA:
                    EventDataAvail(theEvent);
                    break;
//// Expidited Data Available
            case T_EXDATA:
                    EventExDataAvail(theEvent);
                    break;
//// No-copy memory was released        // DEBUG ONLY...
        case T_MEMORYRELEASED:
                    EventMemoryReleased(theEvent);
                    break; 
////..Other ...
            default:
                    EventOther(theEvent);
                    break;
        }
}
 
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventOpenComplete(theEvent )
// ---------------------------------------------------------------------------
//  Network Endpoint Open Completion Handler
 
void TNetworkSession::EventOpenComplete(TNetworkEvent* theEvent)
{
// record endpoint 
    fEndPoint = (EndpointRef) theEvent->fParam;
    
// Setup Tcall/Tdisconnect area
    fCallInfo.addr.len          = 0;
    fCallInfo.opt.len               = 0;
    fCallInfo.udata.len         = 0;
    fDisconInfo.udata.len       = 0;
 
    fCallInfo.addr.maxlen   = (fInfo.addr == T_INVALID)?0:fInfo.addr;
    fCallInfo.opt.maxlen        = (fInfo.options == T_INVALID)?0:fInfo.options;
    fCallInfo.udata.maxlen  = (fInfo.connect == T_INVALID)?0:fInfo.connect; 
    fDisconInfo.udata.maxlen= (fInfo.discon == T_INVALID)?0:fInfo.discon;
 
// Alloacte enough ram for Tcall & TDiscon buffers
    size_t buffSize = fCallInfo.addr.maxlen 
                                        + fCallInfo.opt.maxlen 
                                        + (fCallInfo.udata.maxlen > fDisconInfo.udata.maxlen 
                                                    ? fCallInfo.udata.maxlen
                                                    : fDisconInfo.udata.maxlen);
                                        
    fData = new UInt8[buffSize];
 
    fCallInfo.addr.buf          = &fData[0];
    fCallInfo.opt.buf           = fCallInfo.addr.buf + fCallInfo.addr.maxlen;
    fCallInfo.udata.buf         = fCallInfo.opt.buf + fCallInfo.opt.maxlen;
    fDisconInfo.udata.buf   = fCallInfo.udata.buf;  // Disconnect and connect share the same data area
 
// Enable AckSends
    ThrowIfOTErr( ::OTAckSends(fEndPoint));
 
// attach endpoint to stream;
    fioStream.attach(fEndPoint,&fInfo);
 
// Inform Server that we are ready to be used
        QUEUE_NET_EVENT( fServer, TNetworkAcceptor::kSessionAvailable, noErr, this);
    
}
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventPassCon(theEvent)
// ---------------------------------------------------------------------------
//  Network Endpoint Handoff Completion Handler
 
void TNetworkSession::EventPassCon(TNetworkEvent* theEvent)
{
    try{
        Start();            // start thread.
    } 
    catch(...){
        Done();
    }
}
 
 
// ---------------------------------------------------------------------------
//   TNetworkAcceptor::EventDisconnect 
// ---------------------------------------------------------------------------
//  Connecting client quit
 
void TNetworkSession::EventDisconnect(TNetworkEvent* theEvent)
{
    OSStatus ErrNo;
        
        if( ErrNo = ::OTRcvDisconnect(fEndPoint, &fDisconInfo)) 
            ErrNo = ErrNo ;
 
        if( ErrNo = ::OTUnbind(fEndPoint)) ;
            ErrNo = ErrNo ;
    
}
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventOrdRelease 
// ---------------------------------------------------------------------------
//  remote client request release
 
void TNetworkSession::EventOrdRelease(TNetworkEvent* theEvent)
{
    OSStatus ErrNo;
 
        if( ErrNo = ::OTRcvOrderlyDisconnect(fEndPoint)) 
            ErrNo = ErrNo ;
 
        if( ErrNo = ::OTUnbind(fEndPoint)) ;
            ErrNo = ErrNo ;
 
// shut down thread if still running
        Stop();
 
}
 
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventDisconnectComplete 
// ---------------------------------------------------------------------------
//  Connection Torn Down
 
void TNetworkSession::EventDisconnectComplete(TNetworkEvent* theEvent)
{
    OSStatus ErrNo;
        if( ErrNo = ::OTUnbind(fEndPoint)) ;
            ErrNo = ErrNo ;
}
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventUnbindComplete 
// ---------------------------------------------------------------------------
//  Network Endpoint Unbind Completion Handler
 
void TNetworkSession::EventUnbindComplete(TNetworkEvent* theEvent)
{
        
// notify server that your done...
        QUEUE_NET_EVENT( fServer, TNetworkAcceptor::kSessionAvailable  , noErr, this);
}
 
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventDataAvail 
// ---------------------------------------------------------------------------
//  Data Available
 
 
void TNetworkSession::EventDataAvail(TNetworkEvent* theEvent)
{
#pragma unused (theEvent)
        OTFlags             flags;
        OTResult            status;
        OTBuffer*           buffP;
        OTBufferInfo    buffInfo;
        size_t              actCount;
        char*                   buffer;
            
// do while data left in OT
    while((status = ::OTRcv(fEndPoint, &buffP, kOTNetbufDataIsOTBufferStar, &flags)) > 0) {
        
    // get count of bytes in buffer
            OTInitBufferInfo(&buffInfo, buffP);
    
    // loop until no longer hungry 
        do{
    // reserve buffer space
                ThrowIfNil( buffer = fioStream.ReserveBuffer(status, &actCount));
            
    // read data into buffer
            ::OTReadBuffer(&buffInfo, buffer, &actCount);
            fioStream.EnqueueBuffer(buffer,actCount);
        
            status -= actCount;
            
        } while( status > 0 );
        
    // return OTBuffer to system
        ::OTReleaseBuffer(buffP);
    }   
    
 
// Did we read all the data
        if(status ==  kOTNoDataErr) return;
 
// was  the endpoint not ready yet
        else if(status ==  kOTStateChangeErr) QUEUE_NET_EVENT(this, T_DATA, 0, 0);
                    
// Check for Rcv Error 
        else ThrowIfOTErr( status );    
 
};
                    
// ---------------------------------------------------------------------------
//   TNetworkSession::EventExDataAvail 
// ---------------------------------------------------------------------------
//   Expidited Data Available
 
void TNetworkSession::EventExDataAvail(TNetworkEvent* theEvent)
{
};
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventMemoryReleased(theEvent )
// ---------------------------------------------------------------------------
//  Network Endpoint Memory released hander
 
void TNetworkSession::EventMemoryReleased(TNetworkEvent* theEvent)
{
    TNetworkBuf::Release((void*)theEvent->fParam );
}
 
            
 
// ---------------------------------------------------------------------------
//   TNetworkSession::EventOther 
// ---------------------------------------------------------------------------
//  Other random event
 
void TNetworkSession::EventOther(TNetworkEvent* theEvent)
{       
        if(theEvent)
            ThrowIfOTErr(noErr);
};