Using Options
This section describes the rules for option negotiation and how negotiation is affected by the function you use to set options. It also explains how you use endpoint functions to set and retrieve option values and how you use Open Transport utility functions to construct an options buffer and parse through an options buffer.If your application needs to negotiate option values, you must read the sections "Determining Which Function to Use to Negotiate Options," "Negotiating Options," and "Obtaining the Maximum Size of an Options Buffer." After reading these sections, you can read whichever of the remaining sections describes the task you need to accomplish.
Determining Which Function to Use to Negotiate Options
You can negotiate options using theOTOptionManagementfunction or using any one of the endpoint functions used to transfer data or establish a connection. The following bulleted list summarizes the major differences between using
theOTOptionManagementfunction or using other endpoint functions to set an option value.
- Options specified using the
OTOptionManagementfunction affect all functions called by an endpoint. Options specified using individual endpoint functions affect only the connection, transaction, or datagram for which they are set. For example, you can call theOTOptionManagementfunction to turn the checksum option on; you could override that value by calling theOTSndUDatafunction and turning the checksum option off for the duration of that function call. The next time you call theOTSndUDatafunction, the default value, set with theOTOptionManagementfunction would apply, so the checksum option would be off.- The
OTOptionManagementfunction is the only way that you can obtain default option values or check for current values of all options supported by an endpoint.- When attempting to set multiple options, if an option is illegal or rejected, the
OTOptionManagementfunction still returns successfully, indicating for each option in the buffer whether it has been successfully negotiated. In the same circumstances, any other function returns an error, and even though some of the options might have been successfully negotiated, you have no way of knowing which were and which were not.- If you are using the
OTOptionManagementfunction to set or verify option values, all options in the buffer must be for the same protocol. If you use any other function to negotiate options or to check their value, the buffer can contain options set for different protocols.- If association-related options contain information that is transmitted across the network or if they affect the transmission itself, they take effect when Open Transport establishes the connection, sends the transaction, or transmits the datagram. If you use the
OTOptionManagementfunction to change such an option, the endpoint provider checks whether the option is supported and negotiates a value according to its current knowledge. Then it writes the negotiated value to the endpoint's internal options buffer. However, more negotiations might take place when the connection is established or the transaction or datagram is sent. This can result in a degradation of the option value or even in a negotiation failure. If the negotiation succeeds, the newly negotiated values are written to the internal options buffer.
Negotiating Options
This section describes the rules governing option negotiation and the error conditions that might occur during this process. Unless stated otherwise, these rules apply to all functions that allow you to specify option values.A basic rule to keep in mind is that options change only as the result of successful negotiations or partly successful negotiations. If you use any function except the
OTOptionManagementfunction, the changes last for the duration of that function invocation. Option values are not changed by a change in the state of an endpoint. Once you change an option value permanently, there is no function that you can call to restore an option to its previous value, unless that previous value is the default value.Negotiating Multiple Options
You can use one function to negotiate several options by placing the options
in the options buffer passed to the function. If one of the options is ignored
or rejected for any reason, the outcome depends on the function you use to
set options.
If you specify the same option more than once, the endpoint provider does not check for duplicate occurrences of the same option. It simply processes the options one after another. However, the endpoint provider might negotiate options in any order; therefore, it is not safe to make any assumptions that a later occurrence of an option will override an earlier occurrence.
- If you use the
OTOptionManagementfunction, the function returns the result of negotiating each option in thestatusfield of each option. The failure of one or more options does not cause the function to fail.- The
OTConnect,OTAccept,OTSndUdata, orOTSndURequestfunctions might succeed or fail, depending on the implementation and on the error condition. Options that are not supported are generally ignored; they do not cause a function to fail or a connection to abort. However, if the endpoint provider is unable to negotiate options that are absolute requirements or options that are read-only, these functions will fail.If option negotiation causes one of these functions to fail, it is possible that some options were successfully negotiated before the failure. However, it is not possible to determine which of the options caused the failure.
Initiating an Option Negotiation
You initiate an option negotiation by calling theOTOptionManagementfunction with the flagT_NEGOTIATEset or by calling theOTConnect,OTSndUData, orOTSndURequestfunction and specifying an options buffer length that is greater than 0. You can specify values for some or all of the options supported by an endpoint. The endpoint provider takes values for options that you do not specify explicitly in the options buffer, from the endpoint's internal options buffer. This buffer contains the endpoint's current option values; these could be default values, values that you specified when you configured the provider, or values resulting from a previous negotiation.If the endpoint supports an option, the possible outcome of option negotiation depends on whether the option is an absolute requirement, as described in the next two sections. If the endpoint does not support the option, the
OTOptionManagementfunction reportsT_NOTSUPPORTin thestatusfield. TheOTConnect,OTSndUData, orOTSndURequestfunctions ignore the option.Options That Are Absolute Requirements
If the option is an absolute requirement, the result of the negotiation depends on whether the negotiated value is the same as the requested value. If it is, thestatusfield in theTOptionstructure describing the option is set toT_SUCCESSwhen the function returns. If the negotiated value is not the same as the requested value, the result depends on the function used to negotiate
the option:
- The
OTOptionManagementfunction returns successfully, but the returned option has itsstatusfield set toT_FAILURE.- A call to the
OTConnectfunction fails. If the call is synchronous, the function returns with thekOTLookErrresult. If the call is asynchronous, the endpoint provider issues aT_DISCONNECTevent to let you know that the connection has been rejected.- The
OTSndUDatafunction fails with thekOTLookErrresult; or if it returns successfully, the endpoint provider issues aT_UDERRevent to indicate that the datagram was not sent.
Options That Are not Absolute Requirements
If the requested option is not an absolute requirement, the result of the negotiation depends on whether the negotiated value is the same as the requested value. If it is, the endpoint provider sets thestatusfield of theTOptionstructure describing the option toT_SUCCESS. If the negotiated value is different than the proposed value, the endpoint provider sets thestatusfield of theTOptionstructure describing the options toT_PARTSUCCESS.Conflicting Option Values
It is possible that a requested option value conflicts with the value of another option that is proposed with the same call to the function or that is currently effective. The endpoint provider might not detect these conflicts immediately, and later they might lead to unpredictable results. If the endpoint provider detects conflicts at negotiation time, the conflicts are resolved according to the rules stated above.An endpoint provider usually detects conflicts at the time it establishes a connection or sends a datagram. Consequently, if you use the
OTOptionManagementfunction to set options, you might not become aware
that there is a problem due to conflicting options until the options are
actually exercised during connection establishment or data transmission.Privileged or Read-Only Options
A protocol implementation can define options to be privileged or read only. These two categories are not necessarily separate. A privileged option might be inaccessible or read-only for nonprivileged clients. An option might be read-only for all clients or solely for nonprivileged clients. Here are two general guidelines to keep in mind:
If you request negotiation of a privileged option using the
- A client must be privileged to be able to change a privileged option.
In the Macintosh implementation of Open Transport, there are no
privileged options.- A client cannot usually change the value of a read-only option.
An option might be read-only in some endpoint states but not in others. For example, the ISO quality-of-service options are negotiable in the
T_IDLEandT_INCONstates, and read-only in all other states exceptT_UNINIT. Consult the documentation provided for the protocol you are using to determine whether an endpoint's state affects the status of read-only options.
OTOptionManagementfunction, the function returns successfully with thestatusfield of the privileged option set toT_NOTSUPPORT. If you use theOTConnect,OTAccept,OTSndUData, orOTSndURequestfunctions, the option is ignored--that is, the function result is not affected by the fact that the options are not supported.If you request negotiation of a read-only option using the
OTOptionManagementfunction, the function returns with thestatusfield of the read-only option set toT_READONLY. If you use any other function to change a read-only option, the results vary with the function used:
- The
OTAcceptorOTConnectfunctions fail with thekOTAccessErrresult, or the connection establishment aborts and the endpoint provider issues aT_DISCONNECTevent. If the connection aborts, a synchronous call toOTConnectfails with theKOTLookErrresult. Timing and the protocol implementation determine whether theOTAcceptfunction succeeds or fails with thekOTLookErrresult.- The
OTSndUDatafunction might return thekOTLookErrresult or return successfully, but the endpoint provider issues aT_UDERRevent to indicate that it did not send the datagram.
Error Conditions
Option negotiation might be affected if you try to negotiate an illegal option, a privileged or read-only option, an unsupported option, or an option for an unsupported protocol (level). The results of attempting to negotiate privileged or read-only options are described in "Privileged or Read-Only Options" on page 5-15. This section explains the outcome of negotiating illegal options and describes other problems that might arise during option negotiation.An option is illegal in these cases:
If you specify an illegal option, the following error conditions result depending on the function you used:
- It is the last option in an options buffer, and the length specified in the
TOption.lenfield exceeds the remaining size of the options buffer. (The length of the option includes the option header as well as the option value. See Figure 5-2 on page 5-8 for information about the format of option information in an options buffer.)- The option value does not fall within the range of legal values for the option. The range of option values that are valid for a protocol implementation are given in the documentation provided for the protocol.
If the options buffer you pass to a function contains multiple options and one of them is illegal, the function fails as described. However, if you used the
- The
OTOptionManagementfunction returns with thekOTBadOptionErrresult.- Either the
OTAcceptorOTConnectfunction fails with akOTBadOptionErrresult, or the connection establishment aborts, depending upon the implementation and the time the illegal option is detected. If the connection aborts, the endpoint provider issues aT_DISCONNECTevent. IfOTConnectis executing synchronously, it fails with thekOTLookErrresult. TheOTAcceptfunction either succeeds, or fails with thekOTLookErrresult, depending on the implementation.- The
OTSndUDatafunction fails with thekOTBadOptionErrresult, or it returns successfully, but the endpoint provider issues aT_UDERRevent to indicate that it did not sent the datagram.
OTOptionManagementfunction to set options, it is possible that some or all of the legal options in the buffer were successfully negotiated. You can check the current status for the endpoint by calling theOTOptionManagementfunction with theT_CURRENTflag set.The
OTOptionManagementfunction fails with thekOTBadOptionErrresult if you specify an unknown value for the option protocol level. Using any other function to specify an unknown option level does not cause the function to fail, but results in the option being ignored.Specifying an option name that is unknown or unsupported by the endpoint does not cause a function to fail. The
OTOptionManagementfunction returnsT_NOTSUPPORTin thestatusfield for the option; the other endpoint functions ignore the unknown options.Obtaining the Maximum Size of an Options Buffer
Different types of endpoints support different numbers of options. For example, an ATP endpoint might support more options than a DDP endpoint and might need a larger buffer to hold the options. When you call theOTOptionManagementfunction to change option values, the function returns in theretparameter a pointer to the buffer containing the negotiated option values. You must have allocated the buffer used to store these options before calling the function. Likewise, when you call theOTListen,OTRcvUData,OTRcvURequestorOTRcvConnectfunctions, you can allocate a buffer in which current option values are to be placed when these functions return. In either case, you must specify the size of the buffer, and the buffer must be large enough to hold all of the endpoint's options. Otherwise, the function fails with akOTBufferOverflowresult. You can obtain the maximum size of a buffer used to store options for your endpoint by examining theoptionsfield of theTEndpointInfostructure for the endpoint. You can get a pointer to this structure when you open the endpoint, when you bind the endpoint, or when you call theOTGetEndpointInfofunction.Setting Option Values
You can use theOTOptionManagement,OTAccept,OTSndUData,OTSndURequest, andOTConnectfunctions to set option values. Setting option values results in a negotiation process between you (the client application) and the endpoint provider or, in the case of association-related options, between local and remote clients and their endpoint providers. The section "Initiating an Option Negotiation" on page 5-13 describes the rules that govern an option negotiation that you have initiated using theOTOptionManagement,OTConnect,OTSndUData, orOTSndURequestfunctions. The section "Retrieving Values for Connection-Oriented Endpoints," beginning on page 5-21 describes the negotiation rules that hold when you use theOTOptionManagementorOTAcceptfunctions to respond to a negotiation. This section describes ways in which you can build the options buffer used to specify the options you want to change.Specifying Option Values
No matter which function you use to set option values, you must allocate a buffer that contains the option value or values you want to change. The options in this buffer are described byTOptionstructures; the format of this structure is illustrated in Figure 5-2 on page 5-8. You can concatenate several structures in the buffer, as shown by Figure 5-3 on page 5-8, so long as each structure begins on a long-word boundary. The buffer itself is described by aTNetbufstructure that specifies the location of the buffer and its size.You can create a buffer that contains the option values you want to set in one of two ways: manually or by using the
OTCreateOptionsfunction. If you construct the buffer manually, you must do the following:
To have Open Transport create a buffer for you, you must call the
- Allocate the buffer.
- Create a
TOptionstructure for each option you want to change.- Initialize each field of the
TOptionstructure except for thestatusfield.- Place the
TOptionstructures in the buffer, making sure that each begins on a long-word boundary. This enables Open Transport to parse the buffer.- Append a null character to the end of the buffer. This enables Open Transport to tell that it has reached the end of the buffer.
OTCreateOptionsfunction and pass it a string containing one or more option values. This method saves time and trouble, but you can only use it if all the options in the buffer are for the same level and that level is the same as the top-level protocol for the endpoint provider. That is to say, you could not use this method to construct a buffer that contains DDP-level options for an ATP endpoint. In addition, this method is only guaranteed to work if you are building an options buffer for theOTOptionManagementfunction.Listing 5-1 shows how you construct an options buffer manually. The listing creates and initializes two
TOptionstructures,ddpOptandatpOpt. It allocates a buffer large enough to contain theTOptionstructures and then places those structures in the buffer. Note that the structures are quad-word aligned and that a null character is appended to the end of the buffer.Listing 5-1 Constructing an options buffer manually
TOption *ddpOpt, *atpOpt; unsigned char optionBuffer[41]; ddpOpt = (TOption*)&optionBuffer[0]; ddpOpt->len = 20; ddpOpt->level = ATK_DDP; ddpOpt->name = OPT_CHECKSUM; ddpOpt->status = 0; ddpOpt->value[0] = 1; /* turn checksumming on */ atpOpt = (TOption*)&optionBuffer[20] atpOpt->len = 20; atpOpt->level = ATK_ATP; atpOpt->name = OPT_RELTIMER; atpOpt->status = 0; atpOpt->value[0] = 2; /* purge transaction list every 2 minutes */ optionBuffer[40] = 0;/* add null character to end of buffer */Listing 5-2 shows how you construct an options buffer by using theOTCreateOptionsfunction. The code initializes a string array,myStr, to hold option values. It then creates aTOptMgmtstructure, which would later be passed to theOTOptionManagementfunction to request the option values specified in the string. Finally, it calls theOTCreateOptionsfunction to create the options buffer. TheOTCreateOptionsfunction creates theTOptionstructures and places them in the buffer, making sure that the structures are properly aligned.Listing 5-2 Constructing an options buffer using the
OTCreateOptionsfunction
char* myStr = "BaudRate = 9650 DataBits = 8 Parity = 0 StopBits = 10"; UInt8 buffer[512]; TOptMgmt cmd; cmd.opt.len = 0; cmd.opt.maxlen = sizeof(buffer); cmd.opt.buf = buffer; cmd.flags = T_NEGOTIATE err = OTCreateOptions("SerialA", &myStr, &cmd.opt)In this case, the initial value ofcmd.opt.len, which is 0, tells theOTCreateOptionsfunction at what offset it should begin to append option information in the buffer. When the function returns, this field specifies the actual length of the buffer.Setting Default Values
To set all of an endpoint's options to their default values, call theOTOptionManagementfunction, specifyingT_NEGOTIATEfor theflagsfield and allocating a buffer containing only one option namedT_ALLOPT. Doing this saves you the trouble of constructing aTOptionstructure for every option the endpoint supports. However, there is no guarantee that the provider can honor your request simply because you request default values. Therefore, you must allocate a buffer that is large enough to hold the option values returned in theretparameter.Allowing the Endpoint Provider to Select an Option Value
You can specify that an endpoint provider selects an appropriate option value by setting the endpoint's value field to the constantT_UNSPEC. This is especially useful in complex options such as ISO throughput where the option value has an internal structure.Retrieving Option Values
This section describes how you can retrieve information about options, including obtaining current and default option values for an endpoint and obtaining current option values related to a connection, transaction, or datagram.When retrieving option values, you must allocate a buffer that is large enough to contain the options when the function returns. The section "Obtaining the Maximum Size of an Options Buffer" on page 5-17 explains how you do this.
Obtaining Current and Default Values
To obtain some of an endpoint's default or current option values, you call theOTOptionManagementfunction. You specifyT_DEFAULTorT_CURRENTfor theflagsfield of thereqparameter, and you use theoption.buffield to specify the option names in which you are interested. When the function returns, it placesTOptionstructures, describing the default or current option values, in the buffer referenced by theopt.buffield of theretparameter.If you are interested in obtaining all of an endpoint's default or current values, you can use the following methods:
Using
- To obtain an endpoint's default values, call the
OTOptionManagementfunction, specifyingT_DEFAULTfor the flags field andT_ALLOPTfor the
option name.- To obtain an endpoint's current option values, call the
OTOptionManagementfunction, specifyingT_CURRENTfor theflagsfield andT_ALLOPTfor the option name.
T_ALLOPTfor the option name allows you to construct an input buffer that contains only one option. Remember, however, that you must allocate an output buffer that is large enough to hold all of an endpoint's option values when the function returns.Retrieving Values for Connection-Oriented Endpoints
When you are establishing a connection, it is possible to negotiate association-
related option values at every point in the connection process, as illustrated in Figure 5-1 on page 5-6. Both the active and passive peers might want to retrieve option values during this process.The passive peer might want to know the proposed option values under negotiation. It can retrieve these by calling the
OTListenfunction. After examining the option values returned by theOTListenfunction, the passive peer can negotiate option values by specifying the desired option values
with theOTAcceptcall used to accept the connection. Using this method,
the passive peer can examine the requested option values before proposing alternate values.The passive peer can also negotiate alternate values by using the
OTOptionManagementfunction to preset option values for the endpoint accepting the connection. This sets the current option values for the endpoint so that when the passive peer calls theOTAcceptfunction, these are the option values that are negotiated with the requested values.The passive peer can try to negotiate option values that are higher than the proposed values. The outcome depends on the protocol. If the protocol rejects the new option values, the connection fails, and the endpoint provider issues a
T_DISCONNECTevent. Depending on timing and the implementation, theOTAcceptfunction either succeeds or fails with thekOTLookErrresult.The association-related options retrieved by the passive peer are related to the incoming connection, identified by a sequence number, and are not related to the listening endpoint. Option values currently effective for the listening endpoint might affect the values retrieved by the
OTListenfunction because the endpoint is involved in the negotiation process, but these values are not the same as the option values related to the connection request. That is to say, calling theOTOptionManagementfunction to retrieve the option values that were currently effective for the listening endpoint is likely to yield a different set of values than you would find by examining the values of options passed in thecallparameter to theOTListenfunction.When you establish the connection--that is, when a synchronous call to the
OTConnectfunction returns or when the active peer calls theOTRcvConnectfunction-- all final negotiated values effective for the connection are returned in the buffer passed in thercvCallorcallparameter, respectively. These option values include all association-related options that were received with the connection response and the negotiated values of those non-association-
related options that had been specified on input. Options specified on input to theOTConnectcall that are not supported or that refer to an unknown protocol are ignored and not returned by theOTConnectorOTRcvConnectfunction when it returns.Retrieving Values for Connectionless Transactionless Endpoints
You can retrieve association-related options set for connectionless transactionless endpoints by examining the buffer passed in theudataparameter to theOTRcvUDatafunction. These options relate to the incoming datagram, not to the endpoint receiving it. For example, the IEEE 802.2 protocol uses option values to specify whether a datagram is a multicast or broadcast packet.Because the options you retrieve are related to the datagram and not to the listening endpoint, their number and values can change with every transmission.
Because you are receiving information--that is, you are simply reading the contents of the options buffer--you can ignore the
statusfield for these options.Retrieving Values for Connectionless Transaction-Based Endpoints
You can retrieve association-related options set for connectionless transaction-
based endpoints by examining the buffer passed in thereqparameter to theOTRcvURequestfunction. These options relate to the current transaction, not to the endpoint receiving the request. Consequently, options and their values can change with each transaction.Because you are receiving information--that is, you are simply reading
the contents of the options buffer--you can ignore thestatusfield for
these options.Parsing an Options Buffer
If you use theOTOptionManagementfunction to set, verify, or retrieve values, the function returns in theretparameter a pointer to a buffer containing option information. You can use theOTCreateOptionStringfunction to parse this buffer and create a string that lists all options and their current values.The code fragment shown in Listing 5-3 calls the
OTOptionManagementfunction to retrieve the option values currently effective for an endpoint. On return, theOTOptionManagementfunction stores these in thecmdstructure. Next, the code calls theOTCreateOptionStringfunction. The first input parameter,"SerialA", specifies the name of the protocol. The next input parameter,opts,is a pointer to the buffer containing the option values returned by theOTOptionManagementfunction. The expressioncmd.opt.buf + cmd.opt.len, which provides the next input parameter, specifies the length of the buffer. Using this information, theOTCreateOptionStringfunction returns a string containing each option name and its respective value. The final parameter to theOTCreateOptionStringfunction specifies the length of the string.Listing 5-3 Using the
OTCreateOptionStringfunction to parse through a buffer
TOptMgmt cmd; UINt8 myBuffer[512]; char myString[256] cmd.opt.len = sizeof(TOption); cmd.opt.maxlen = sizeof(myBuffer); cmd.opt.buf = myBuffer; ((TOption*) buffer)->len = sizeof(TOption); ((TOption*) buffer)->level = COM_SERIAL; ((TOption*) buffer)->name = T_ALLOPT; ((TOption*) buffer)->status = 0; cmd.flags = T_CURRENT; OTOptionManagement(theEndpt, &cmd, &cmd); TOption* opts = (TOption*)cmd.opt.buf; err = OTCreateOptionString("SerialA", &opts, cmd.opt.buf + cmd.opt.len, string, sizeof(string)); printf("Options = \"%s\"", string);
- Note
- The
OTCreateOptionStringfunction is supplied solely as a debugging aid. You should not include the function in a production version of your application because there is no provision made for localizing string information.![]()
Verifying Option Values
In addition to obtaining default or current values and negotiating new values, you can use theOTOptionManagementfunction to verify whether an endpoint supports one or more options. To do this, you construct a buffer containingTOptionstructures describing the options you are interested in and pass this buffer in thereqparameter to theOTOptionManagementfunction, specifyingT_CHECKfor the action flag. When the function returns, you can examine thestatusfield of theTOptionstructures for the options passed back to you in theretparameter to determine whether the specified options are supported.