LocalServerTCP/LocalServerClient/TCPPitchSample.cp

/*
    File:       TCPPitchSample.cp
 
    Contains:   Tcp pitch sample.
 
    Copyright:  © 1993-1997, 2000 by Apple Computer, Inc., all rights reserved.
 
*/
 
 
// OT TCP Pitch Test Program (as an SIOW app)
 
#include <OpenTransport.h>
#include <OpenTransportProviders.h>
#include <Processes.h>
#include <stdio.h>
#include <StdLib.h>
#include "ServerInfo.h"
#include <AppleEvents.h>
 
 
#ifndef T_DISCON_IND
#define T_DISCON_IND 128
#endif
 
 
/*******************************************************************************
** GLOBAL VARIABLES
********************************************************************************/
 
InetPort    gCatchPort      = 0;
InetHost    gCatchIpAddr    = 0;
InetPort    gPitchPort      = 0;
InetHost    gPitchIpAddr    = 0;    
 
unsigned short gBindCompleted       = 0;
unsigned short gCallRcvOrdDiscon    = 0;
static OTNotifyUPP      gNotifier = nil;
 
 
struct InetAddress gCatchAddr, rcvsin, reqsin, retsin;
 
/*******************************************************************************
** Function Prototypes
********************************************************************************/
 
void Inits();
OSErr GetServerInfo();
void CleanUp();
void Idle();    
void DoIt();
OSErr FindProcessBySignature( const OSType targetType,
                                        const OSType targetCreator,
                                        ProcessSerialNumberPtr psnPtr );
OTResult SetFourByteOption(EndpointRef ep,
                           OTXTILevel level,
                           OTXTIName  name,
                           UInt32   value);
 
/*******************************************************************************
**  main function
********************************************************************************/
 
void main()
{
    printf ("Hello World\n");
    Inits();
    if (GetServerInfo() == noErr)
    {
        DoIt();
    }
    else
        printf ("GetServerInfo returned an error\n");
 
    CleanUp();
}
 
/*******************************************************************************
** Initialize Quickdraw and ASLM
********************************************************************************/
 
void Inits()
{
    if (InitOpenTransport() != kOTNoError)
    {
        fprintf(stderr, "OTTcpPitch: Could not initialize ASLM, exiting\n");
        exit(1);
    }
}
 
/*******************************************************************************
    The FindProcessBySignature function returns a ProcessSerialNumber
    for a process whose signature (type and creator) matches the input values.
    The ProcessSerialNumber will be kNoProcess is the requested process cannot
    be found. 
 
    targetType      input:  The file type of the process to be found.
    targetCreator   input:  The creator type of the process to be found.
    
    psnPtr          input:  Pointer to a ProcessSerialNumber where the
                            process serial number is returned.
                    output: Process serial number.
    
    RESULT CODES
    ____________
    noErr              0    No error
    procNotFound    Ð600    No eligible process with specified descriptor
    ____________
********************************************************************************/
 
OSErr FindProcessBySignature( const OSType targetType,
                                        const OSType targetCreator,
                                        ProcessSerialNumberPtr psnPtr )
{
    OSErr       anErr = noErr;
    Boolean     foundTheProcess = false;
    
    ProcessInfoRec  infoRec;
    
    infoRec.processInfoLength = sizeof( ProcessInfoRec );
    infoRec.processName = nil;
    infoRec.processLocation = nil;
    infoRec.processAppSpec = nil;
    
    psnPtr->lowLongOfPSN = kNoProcess;
    psnPtr->highLongOfPSN = kNoProcess;
 
    while ( !foundTheProcess && (anErr == noErr) )
    {
        anErr = GetNextProcess( psnPtr );
        if ( anErr == noErr )
        {
            anErr = GetProcessInformation( psnPtr, &infoRec );
            if ( ( anErr == noErr )
                 && ( infoRec.processType == targetType )
                 && ( infoRec.processSignature == targetCreator ) )
            {
                foundTheProcess = true;
            }
        }
    }
    
    return anErr;
 
}//end FindProcessBySignature
 
 
/*******************************************************************************
** Send an Apple Event to find out if the server is up and running
** which will return the address to send the event to 
********************************************************************************/
 
OSErr GetServerInfo()
{
    AppleEvent              reqEvent = { typeNull, nil };
    AppleEvent              retEvent = { typeNull, nil };
    DescType                typeCode;
    OSErr                   err;
    ProcessSerialNumber     psn = { kNoProcess, kNoProcess };
    AEDesc                  targetAppDesc = { typeNull, nil };
    Size                    size;
    char                    mystr[255];
    UInt32                  dummy;
 
    err = FindProcessBySignature(kApplicationFileType, kPassServerSignature, &psn);
    if (err == noErr)
    {
        err = AECreateDesc (typeProcessSerialNumber, &psn, sizeof( ProcessSerialNumber ), &targetAppDesc);
 
        if ( err == noErr )
        {
            err = AECreateAppleEvent( kPassServerInfoClass, kPassServerInfoEvent, &targetAppDesc,
                                        kAutoGenerateReturnID, kAnyTransactionID, &reqEvent);
            if (err)
                printf("AECreateAppleEvent returned error %d\n", err);
        }
        else
            printf("AECreateDesc returned error %d\n", err);
            
        AEDisposeDesc( &targetAppDesc );
    }
    else
        printf("FindProcessBySignature returned error %d\n", err);
        
    if (err == noErr)
    {
        // we have to insert a dummy in the outgoing AppleEvent list which the
        // LocalServer is expecting, but will not do anything with.  Just doing this
        // for kicks
        err = AEPutParamPtr(&reqEvent, keyDirectObject, typeLongInteger, &dummy,
                            sizeof(dummy) );
    }
    
    if (err == noErr)
    {
        err = AESend(&reqEvent, &retEvent, kAEWaitReply+kAENeverInteract, kAENormalPriority,
                    kAEDefaultTimeout, nil, nil);
                    
        if (err != noErr)
        {
            printf("Error calling AESend = %d\n", err);
        }
        else
        {
                // get the apple event object
            err = AEGetParamPtr(&retEvent, keyDirectObject, kPassServerType, &typeCode,
                                    &gCatchAddr, sizeof (struct InetAddress), &size );
            if (err != noErr)
                printf("Error calling AEGetParamDesc to get the catch address %d\n", err);
 
            // dispose of the returned apple event
            AEDisposeDesc(&retEvent);
        }
        AEDisposeDesc(&reqEvent);
 
    }
    
    if (err == noErr)
    {
        OTInetHostToString(gCatchAddr.fHost, mystr);
        printf("LocalServer found at %s, port %d.\n", mystr, gCatchAddr.fPort);
    }
    return err;
}
 
 
/*******************************************************************************
** Clean up at the end
********************************************************************************/
 
void CleanUp()
{
    CloseOpenTransport();
}
 
 
 
/*******************************************************************************
** Idle
********************************************************************************/
 
void Idle()
{
    EventRecord theEvent;
    WaitNextEvent(everyEvent, &theEvent, 1, nil);
}
 
/*******************************************************************************
** EventHandler
********************************************************************************/
 
pascal void EventHandler(void*, OTEventCode event, OTResult, void*)
{
    OTEventCode tempevent = 0;
 
    switch ( event )
    {
        case T_BINDCOMPLETE:
                            gBindCompleted = 1;
                            break;
        case T_ORDREL:
        case T_DISCONNECTCOMPLETE:
                            gCallRcvOrdDiscon = 1;
                            break;
        case T_CONNECT:
                            printf("T_CONNECT event occurred\n");
                            break;
        case T_DATA:
                            printf("T_DATA event occurred\n");
                            break;
        case T_DISCONNECT:
                            printf("T_DISCONNECT event occurred\n");
                            break;
        case T_ERROR:
                            printf("T_ERROR event occurred\n");
                            break;
        
        default:
                            printf("TCP EventHandler got unexpected event %d", event);
                            break;
    }
    return;
}
 
/*******************************************************************************
** DoIt
********************************************************************************/
 
void DoIt()
{
    TEndpoint*      ep = NULL;
    TEndpointInfo   info;
    TBind           req, ret;
    TCall           sndcall, rcvcall;
    OSStatus        err = kOTNoError;
    OTResult        result;
    long            myport = 0;
    InetHost        myaddr = 0;
    char            mystr[255];
    long            bytes = 0;
    OTFlags         flags = 0;
    OTTimeStamp     time;
    OTTimeStamp     end, *begin, diff;
    UInt32          diffInMsec;
    UInt32          i, j;
    UInt8           *ptr;
    UInt8           buffer[32];
 
 
    myport = 0;
    gPitchPort =(InetPort)  myport;
    
    gPitchIpAddr = gCatchAddr.fHost;
 
    OTMemset(&rcvsin, 0, sizeof(struct InetAddress));
    OTMemset(&sndcall, 0, sizeof(TCall));
    OTMemset(&rcvcall, 0, sizeof(TCall));
    OTMemset(&reqsin, 0, sizeof(struct InetAddress));
    OTMemset(&rcvsin, 0, sizeof(struct InetAddress));
    OTMemset(&req, 0, sizeof(TBind));
    OTMemset(&ret, 0, sizeof(TBind));
 
    do
    {
        //
        // Now create a TCP
        //
        ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &info, &err);
 
        if ( ep == NULL || err != kOTNoError )
        {
            ep = NULL;
            fprintf(stderr,"ERROR: OpenEndpoint(\"TCP\") failed with %d\n", err);
            break;
        }
        
        // since we are going to send very small packet in this example, we need to 
        // set the TCP NO_DELAY option, otherwise performance will be very poor
        // due to the Nagle Algorithm, where TCP optimizes small sends by waiting 
        // for multiple requests to bundle the sends into a single larger packet.
        
        err = SetFourByteOption(ep, INET_TCP, TCP_NODELAY, 1);
 
        err = ep->SetSynchronous();
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: SetSynchronous() failed with %d\n", err);
            break;
        }
 
        //
        // Install notifier we're going to use for testing
        //
        gNotifier = NewOTNotifyUPP(EventHandler);
        err = ep->InstallNotifier(gNotifier, 0);
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", err);
            break;
        }
 
        //
        // Try to bind
        //
        gPitchIpAddr = 0;
        OTInitInetAddress(&reqsin, gPitchPort, gPitchIpAddr);
 
        req.addr.len = sizeof(struct InetAddress);
        req.addr.buf = (unsigned char *) &reqsin;
        req.qlen = 0;                                       // don't care for tcp
        ret.addr.maxlen = sizeof(struct InetAddress);
        ret.addr.buf = (unsigned char *) &retsin;
 
        OTInetHostToString(retsin.fHost, mystr);
        printf("Trying to bind at %s, port %d.\n", mystr, gPitchPort);
 
        // bind TCP to current address and port
        err = ep->Bind(&req, &ret);
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: Bind() failed with %d\n", err);
            break;
        }
 
        OTInetHostToString(retsin.fHost, mystr);
        printf("Bound ep to %s, port %d.\n", mystr, retsin.fPort);
 
        err = ep->SetSynchronous();
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: SetSynchronous() failed with %d\n", err);
            break;
        }
 
 
        sndcall.addr.len = sizeof(struct InetAddress);
        sndcall.addr.buf = (unsigned char *) &gCatchAddr;
    
        rcvcall.addr.maxlen = sizeof(struct InetAddress);
        rcvcall.addr.buf = (unsigned char *) &rcvsin;
 
        err = ep->Connect(&sndcall, &rcvcall);
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: Connect() failed with %d\n", err);
            break;
        }
        
        for (i = 0; i < 50; i++)
        {
            OTGetTimeStamp(&time);
 
            bytes = ep->Snd(&time, sizeof(time), flags);
            if ( bytes >= 0 )
            {
                // the server will return the byte sent
                result = ep->Rcv(&buffer, sizeof(buffer), &flags);
                // get a timestamp 
                OTGetTimeStamp(&end);
 
                fprintf(stderr, "Sent bytes: <%d> data\n", bytes);
                    // print out the bytes of the time stamp
                if (result > 0)
                {
                    fprintf(stderr, "Rcv'd nbytes: <%d> data\n", result);
                    begin = (OTTimeStamp*)&buffer;
                    OTSubtractTimeStamps(&diff, begin, &end);
                    diffInMsec = OTTimeStampInMilliseconds(&diff);
                    printf("%ld bytes received - %ld milliseconds\n", result, diffInMsec);
                    ptr = (UInt8*) &buffer;
                    for (j = 0; j < result; j++)
                        fprintf(stderr, "%X ", *ptr++);
                    fprintf(stderr, "\n"); 
                }
                else
                    fprintf(stderr, "OTRcv'd error %d\n", result);
                
                }
            else 
            {
                fprintf(stderr, "ERROR: Snd() failed with %d\n", bytes);
                break;
            }
            Idle();
            fflush(stderr);
        }
        
    } while (false);
 
    if ( ep != NULL )
    {
        err = ep->SetSynchronous();
        err = ep->SndOrderlyDisconnect();
        if ( err != kOTNoError )
        {
            if ( err == kOTLookErr )
                fprintf(stderr, "SndOrderlyDisconnect() returns %d\n", err);
            else
                fprintf(stderr, "ERROR: SndOrderlyDisconnect() failed with %d\n", err);
        }
        else
            fprintf(stderr, "Orderly Disconnect sent successfully\n");
    
        err = ep->RcvOrderlyDisconnect();
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: RcvOrderlyDisconnect() failed with %d\n", err);
        }
        
    
        //
        // Remove notifier
        //
        ep->RemoveNotifier();   
        //
        // Try to Unbind
        // 
        err = ep->Unbind();
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: Unbind() returned %d\n", err);
        }
        //
        // Get rid of endpoint.
        //
        err = OTCloseProvider(ep);
        if ( err != kOTNoError )
        {
            fprintf(stderr, "ERROR: CloseEndpoint() failed with %d\n", err);
        }
    }
    fprintf(stderr, "Bye\n");
}
 
OTResult SetFourByteOption(EndpointRef ep,
                           OTXTILevel level,
                           OTXTIName  name,
                           UInt32   value)
{
   OTResult err;
   TOption  option;
   TOptMgmt request;
   TOptMgmt result;
   
   /* Set up the option buffer to specify the option and value to
         set. */
   option.len  = kOTFourByteOptionSize;
   option.level= level;
   option.name = name;
   option.status = 0;
   option.value[0] = value;
 
   /* Set up request parameter for OTOptionManagement */
   request.opt.buf= (UInt8 *) &option;
   request.opt.len= sizeof(option);
   request.flags  = T_NEGOTIATE;
 
   /* Set up reply parameter for OTOptionManagement. */
   result.opt.buf  = (UInt8 *) &option;
   result.opt.maxlen  = sizeof(option);
 
   
   err = OTOptionManagement(ep, &request, &result);
 
   if (err == noErr) {
      if (option.status != T_SUCCESS) 
         err = option.status;
   }
            
   return (err);
}