GetSetOptions.c

/*
    File:       GetSetOptions.c
 
    Contains:   Sample for getting and setting options using the various
                option management routines.
 
    Written by: Quinn "The Eskimo!" 
 
    Copyright:  Copyright © 1997-2001 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):
                2/18/2001   Chad Jones      Updated for Codewarrior IDE 4.1 and Carbonized for OSX
                7/22/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
/////////////////////////////////////////////////////////////////////
// Need to include to be carbonized 
 
#if defined(__MWERKS__)
#   include <carbon.h>
#   include <OpenTransport.h>
#   include <OpenTptInternet.h>
#   include <OpenTptSerial.h>
#   include <SIOUX.h>
 
#else
#   include <CoreServices/CoreServices.h>
#endif
 
#   include <stdio.h>
 
/////////////////////////////////////////////////////////////////////
// This MoreAssertQ is used in replacement for OTAssert under carbon because
// OTAssert is not in carbon.
 
static void MoreAssertQ(Boolean mustBeTrue)
{
    if ( ! mustBeTrue ) {
        DebugStr("\pGetSetOptions: Assertion failure.");
    }
}
 
/////////////////////////////////////////////////////////////////////
 
static OTResult SetFourByteOption(EndpointRef ep,
                                    OTXTILevel level,
                                    OTXTIName  name,
                                    UInt32     value)
    // level and name must denote a four byte option that is
    // appropriate for the endpoint ep.  This routine sets the
    // option to value.  ep is assumed to be in synchronous
    // mode.
    //
    // If all goes well, the result is noErr.  If an error
    // occurs, the result is negative.  If the option could not
    // be negotiated, a positive result being one of (T_FAILURE,
    // T_PARTSUCCESS, T_READONLY, T_NOTSUPPORT) is returned
{
    OTResult    err;
    TOption     option;
    TOptMgmt    request;
    TOptMgmt    result;
    
    // Set up the option buffer to reflect the specific option
    // and value we want to set.  We use a TOption structure
    // to represent the option buffer.  TOption is specifically
    // defined to allow easy construction of 4 byte options.
    // If you want to negotiate different size options, or
    // multiple options in a single call, then constructing
    // the option buffer is a little trickier
    
    option.len      = kOTFourByteOptionSize;
    option.level    = level;
    option.name     = name;
    option.status   = 0;
    option.value[0] = value;
 
    // Set up the request for OTOptionManagement to point
    // to the option buffer we just filled out, and tell
    // it that we want to negotiate (ie set) the option.
    
    request.opt.buf = (UInt8 *) &option;
    request.opt.len = sizeof(option);
    request.flags   = T_NEGOTIATE;
 
    // Set up the reply for OTOptionManagement.  This is where
    // OTOptionManagement puts the result of the negotiation.
    
    result.opt.buf = (UInt8 *) &option;
    result.opt.maxlen = sizeof(option);
 
    // Call OTOptionManagement and then check that the value
    // was negotiated successfully.  Any value other than
    // T_SUCCESS is reported via the error result.
    
    err = OTOptionManagement(ep, &request, &result);
 
    if (err == noErr) {
        if (option.status != T_SUCCESS) {
            err = option.status;
        }
    }
                
    return (err);
}
 
/////////////////////////////////////////////////////////////////////
 
static OTResult GetFourByteOption(EndpointRef ep,
                                    OTXTILevel level,
                                    OTXTIName  name,
                                    UInt32     *value)
    // level and name must denote a four byte option that is
    // appropriate for the endpoint ep.  This routine gets the
    // current option setting and puts it in the the variable
    // pointed to by value.  ep is assumed to be in synchronous
    // mode.
    //
    // If all goes well, the result is noErr.  If an error
    // occurs, the result is negative.  If the option could not
    // be read, a positive result being one of (T_FAILURE,
    // T_PARTSUCCESS, T_NOTSUPPORT) is returned
{
    OTResult    err;
    TOption     option;
    TOptMgmt    request;
    TOptMgmt    result;
    
    // Set up the option buffer to reflect the specific option
    // and value we want to set.  We use a TOption structure
    // to represent the option buffer.  TOption is specifically
    // defined to allow easy construction of 4 byte options.
    // If you want to negotiate different size options, or
    // multiple options in a single call, then constructing
    // the option buffer is a little trickier
    
    option.len      = kOTFourByteOptionSize;
    option.level    = level;
    option.name     = name;
    option.status   = 0;
    option.value[0] = 0;    // Ignored because we're getting the value.
 
    // Set up the request for OTOptionManagement to point
    // to the option buffer we just filled out, and tell
    // it that we want to get the current value of the option.
    
    request.opt.buf = (UInt8 *) &option;
    request.opt.len = sizeof(option);
    request.flags   = T_CURRENT;
 
    // Set up the reply for OTOptionManagement.  This is where
    // OTOptionManagement puts the result of the negotiation.
    
    result.opt.buf = (UInt8 *) &option;
    result.opt.maxlen = sizeof(option);
 
    // Call OTOptionManagement and then check that the value
    // was read successfully.  Any status other than
    // T_SUCCESS or T_READONLY is reported via the error
    // result.
    
    err = OTOptionManagement(ep, &request, &result);
 
    if (err == noErr) {
        switch (option.status) {
            case T_SUCCESS:
            case T_READONLY:
                *value = option.value[0];
                break;
            default:
                err = option.status;
                break;
        }
    }
                
    return (err);
}
 
/////////////////////////////////////////////////////////////////////
 
static OSStatus PrintOptionBuffer(const TNetbuf *optionBuffer)
    // Print a summary of the optionBuffer to stdout.
    // Basically the call enumerates the option buffer using
    // OTNextOption, and prints the level, name, size and status
    // of each of the options in the buffer.
{
    OSStatus err;
    TOption *currentOption;
 
    currentOption = nil;
    do {
        err = OTNextOption(optionBuffer->buf, optionBuffer->len, &currentOption);
        if (err == noErr && currentOption != nil) {
            printf("Level = $%08lx, Name = $%08lx, Data Length = %ld, Status = $%08lx\n",
                                currentOption->level, 
                                currentOption->name, 
                                currentOption->len -                                        kOTOptionHeaderSize,
                                currentOption->status);
            fflush(stdout);
        }
    } while (err == noErr && currentOption != nil);
    
    return (err);
}
 
/////////////////////////////////////////////////////////////////////
 
static OSStatus PrintAllOptionsAtLevel(EndpointRef ep, OTXTILevel level)
    // Gets all of the options for the endpoint ep at the specified
    // level and prints a summary of them to stdout.
{
    OSStatus        err;
    TEndpointInfo   epInfo;
    TOptionHeader   requestOption;
    void            *resultOptionBuffer;
    TOptMgmt        request;
    TOptMgmt        result;
 
    resultOptionBuffer = nil;
 
    // First call OTGetEndpointInfo to find out the maximum
    // size of the options for this type of endpoint and then
    // allocate that size buffer to hold the resulting options.
    
    err = OTGetEndpointInfo(ep, &epInfo);
    if (err == noErr) {
        resultOptionBuffer = OTAllocMemInContext(epInfo.options,nil);
    
        if (resultOptionBuffer == nil) {
            err = kENOMEMErr;
        }
    }
    
    // Call OTOptionManagement to get the current value (T_CURRENT)
    // of all of the options (ie T_ALLOPT) of the specified level.
    // The resulting options go into resultOptionBuffer, which we
    // have just allocated.
 
    if (err == noErr) {
        requestOption.len       = kOTOptionHeaderSize;
        requestOption.level     = level;
        requestOption.name      = T_ALLOPT;
        requestOption.status    = 0;
 
        request.opt.buf = (UInt8 *) &requestOption;
        request.opt.len = sizeof(requestOption);
        request.flags   = T_CURRENT;
        
        result.opt.buf = resultOptionBuffer;
        result.opt.maxlen = epInfo.options;
        
        err = OTOptionManagement(ep, &request, &result);
    }
    
    // Now that we have the options, print them to stdout.
    
    if (err == noErr) {
        err = PrintOptionBuffer(&result.opt);
        printf("\n");
        fflush(stdout);
    }
    
    // Clean up.
    
    if (resultOptionBuffer != nil) {
        OTFreeMem(resultOptionBuffer);
    }
    
    return (err);
}
 
/////////////////////////////////////////////////////////////////////
 
int main(void)
    // A simple main line that demonstrates the use of the various
    // functions defined above.  The basic idea is to create
    // an endpoint, get the value of the kIP_REUSEADDR option, then
    // change it to true, and read it back to verify that the change
    // worked.  We then do a few other interesting things with
    // various miscellaneous options API routines.
{
    OSStatus err;
    OSStatus junk;
    EndpointRef ep;
    UInt32 value;
    
    #if defined(__MWERKS__)
        SIOUXSettings.autocloseonquit = FALSE;  // don't close the SIOUX window on program termination
        SIOUXSettings.asktosaveonclose = FALSE; // don't offer to save on a close
    #endif
    
    err = InitOpenTransportInContext(kInitOTForApplicationMask, nil);
    
    if (err == noErr) {
    
        ep = OTOpenEndpointInContext(OTCreateConfiguration(kTCPName), 0, nil, &err,nil);
        if (err == noErr) {
            
            printf("\nGetting and Setting IP_REUSEADDR.\n");
            fflush(stdout);
            
            err = GetFourByteOption(ep, INET_IP, kIP_REUSEADDR, &value);
            if (err == noErr) {
                printf("Default value = %ld\n", value);
                fflush(stdout);
            }
            if (err == noErr) {
                err = SetFourByteOption(ep, INET_IP, kIP_REUSEADDR, true);
            }
            if (err == noErr) {
                err = GetFourByteOption(ep, INET_IP, kIP_REUSEADDR, &value);
                if (err == noErr) {
                    printf("New value = %ld\n", value);
                    fflush(stdout);
                }
            }
 
            if (err == noErr) {
                printf("\nPrinting Options Piecemeal at Level INET_IP.\n");
                err = PrintAllOptionsAtLevel(ep, INET_IP);
                fflush(stdout);
            }
    
        //If you used the pre-carbon sampes of this sample code you may be wondering where calls to     
        //PrintOptionsForConfiguration and BuildAndPrintOptions are.
        //In carbon and OSX these calls have no meaning because there is no concept of options as
        //strings in OSX or carbon.  Thus they have  been removed completely from this sample code.
            
            junk = OTCloseProvider(ep);
            MoreAssertQ(junk == noErr); //False if: Closing the endpoint failed.
        }
        
        CloseOpenTransportInContext(nil);
    }
    
    if (err == noErr) {
        printf("Success.\n");
    } else {
        printf("Failed with error %ld.\n", err);
    }
 
    fflush(stdout);
        return(0);
}