Important: The information in this document is obsolete and should not be used for new development.
Using TCP/IP Services
This section describes how to use the Open Transport RawIP interface, how to implement IP multicasting, and how to use a variety of Open Transport endpoint and mapper functions with the TCP/IP protocols. TCP/IP options are described in "Options".Setting Options When Configuring a TCP/IP Provider
When you open a TCP/IP provider, you must pass a pointer to a configuration string. If you want to set an option as part of the configuration string, you should translate the option's constant name, given in the header files, into a string that the configuration functions can parse. For the TCP/IP options, Table 11-2 provides the constant name and the value to use in the configuration string.The network configuration structure and
OTCreateConfiguration
function are described in the chapter "Getting Started" in this book.Using RawIP
The Open Transport TCP/IP software modules provide a RawIP interface to the IP protocol. RawIP behaves for the most part identically to UDP, as a connectionless transactionless interface, but there are a few unique differences.You can receive RawIP datagrams using a RawIP endpoint. You can create a RawIP endpoint by passing
kRawIPName
toOTCreateConfiguration
and passing that configuration to theOTOpenEndpoint
orOTOpenEndpointAsync
function.The RawIP interface facilitates the implementation of new protocols that use IP for datagram delivery. Therefore, in order to use a RawIP endpoint, you must specify a value for the
protocol
field in the IP datagram header. RawIP endpoints default to receiving ICMP (protocol 1) packets. You can change this by setting the generic XTI optionXTI_PROTOTYPE
, described in the chapter "Option Management" in this book. The option is a longword that is the IP protocol number to be used by the RawIP endpoint.The data delivered to a RawIP endpoint includes the full IP header, which is 20 bytes long if it includes no IP options.
- WARNING
- If you open a RawIP endpoint, you are responsible for implementing the protocol that is a client of IP running over that endpoint. Because an improperly implemented protocol can cause the host to crash or cause the loss of data on the network, you should exercise caution when using Raw IP.
Receiving RawIP Datagrams
Normally, connectionless transactionless endpoints only support binding one endpoint to any given protocol address. RawIP is different in that it allows multiple endpoints to be bound to the same protocol address.With one important exception, each RawIP endpoint bound to a specific protocol receives a copy of any inbound packets destined for that protocol. For example, if several "ping" programs are using ICMP on the same host, each would receive a copy of all inbound ICMP echo datagrams. The exception is that RawIP endpoints do not receive copies of packets addressed to IP protocols TCP (protocol 6) or UDP (protocol 17). This restriction optimizes the delivery of such packets to their corresponding high-level protocols.
One unusual behavior of RawIP endpoints is that the delivered packets have their
Total Length
field modified. The RawIP module subtracts the length of the IP header from theTotal Length
field. This behavior brings Open Transport's STREAMS RawIP more in line with RawIP under BSD UNIX. Therefore, you should not rely on the value of theTotal Length
field. If you need to know the total length of the packet, use the length as returned in theTNetBuf
structure returned by theOTRcvUData
function.Sending RawIP Datagrams
You can also send RawIP datagrams using a RawIP endpoint. For sending, RawIP endpoints have two modes: a mode in which the RawIP interface generates the header for you and a mode in which you set the header yourself. The header-generated mode is the default, and it is useful if you are only interested in the payload of the RawIP packets you send.For applications such as ping (ICMP), you can let the RawIP interface generate the headers using the RawIP endpoint default behavior, such as sending ICMP packets (protocol 1). In this case, you can change the protocol and IP options (such as
IP_OPTIONS
andIP_TTL)
using option management functions, as described in the chapter "Option Management" in this book.Manually Setting the IP Header
At times, however, the level of control provided by the IP level options is not enough. If you need to set a field in the IP header that is not handled by a defined option, you can do this by switching the RawIP endpoint to what is referred to as the header-included mode and setting up the IP header manually.Internally, the RawIP module maintains a state that determines whether it should add an IP header to any outgoing packets. If the state is
false
(0), RawIP will automatically generate an IP header for any outgoing packets. If the state is true (1), RawIP expects the data you provide it to contain the IP header. (By default the state is false and RawIP generate headers for you automatically.)You can change this bit explicitly using option management. Simply set the IP option
IP_HDRINCL
to a 4-byte integer containing either 0 or 1. The IP options are listed in "IP Options".You can also change this state by changing the IP protocol (using the generic XTI option
XTI_PROTOTYPE
option) for the endpoint. If you set the IP protocol toIPPROTO_RAW
(255) orIPPROTO_IGMP
(2), the IP optionIP_HDRINCL
state will be set totrue
. If you change the IP protocol to any other value, the IP optionIP_HDRINCL
state defaults to false.
- IP protocol information sources
- The IP Protocol option values are defined in Internet Standard 1 "Assigned Numbers," which can be found at ftp://ds.internic.net/std/std1.txt. The fields in the IP header are those defined in Internet Standard 5, which can be found at ftp://ds.internic.net/std/std5.txt.
Limitations of the Header-Included Mode
If you use the header-included mode, you need to be aware of some of its limitations. A number of the fields in the IP header are automatically modified by Open Transport, regardless of what values you set them to. These field names include:
Flags. The More Fragments (MF) bit and the reserved bit are cleared. The Do Not Fragment (DF) bit is set on all outgoing IP packets. OT uses the DF bit to implement its dynamic path MTU discovery. Because this behavior is implemented below the IP layer, you cannot change this behavior using the RawIP endpoint
- Version. This field is forced to a value of 4 to reflect the fact that you're using IP version 4.
- IHL. When OT sends a RawIP packet in "header included" mode, it ignores the IHL field value you specify and instead attaches the IP options that were last specified using the IP option
IP_OPTIONS
. This prevents you from setting your own IP options by placing them in the IP header and setting IHL appropriately.- Total Length. This field is not touched by RawIP, but it must be less than the link MTU for the packet to be sent.
- Identification. This field value is set to the next ID number in the Open Transport internal sequence.
You need to be careful when setting your own IP header. Even though some fields are automatically "corrected" by Open Transport, it is still possible to generate improperly formatted IP packets using a RawIP endpoint, which can result in loss of network data.
- Fragment Offset. This field is completely overwritten by RawIP.
- Header Checksum. The field is set to the correct checksum value.
- Note
- Path MTU is described in RFC1191 (ftp://ds.internic.net/rfcl/rfc1191.txt).
Using IP Multicasting
Open Transport TCP/IP provides IP multicasting level 2, as described in RFC 1112. This feature is only relevant for RawIP and UDP endpoints.To join a multicast group, use the
IP_ADD_MEMBERSHIP
option , passing in aTIPAddMulticast
structure to specify the address and network interface of the group you wish to join. For a multihomed system, you can use the valuekOTAnyInetAddress
for the interface address to use the default multicast interface.The time-to-live value for outbound multicast data defaults to 1; you can use the
IP_MULTICAST_TTL
option to set a different value. The time-to-live value is a hop count: each router that processes the datagram decrements the time-to-live and discards the datagram if the value reaches 0. Because every router that receives a multicast packet forwards it, a high time-to-live value for a multicast packet can cause the packet to propagate widely throughout the Internet. Therefore, keep this value as low as possible.By default, Open Transport IP loops back multicast datagrams to any member of the group on the sending machine. Pass a value of
T_NO
to the optionIP_MULTICAST_LOOP
to turn off loopbacks.Querying DNS Servers
In addition to the explicit simplified functions that are provided for the most commonly made queries such as name-to-address, address-to-name, system CPU and OS, and mail exchange queries, there is a generic query function, OTInetQuery, that you can use for any DNS query.The OTInetQuery function allows you to use the Domain Name Resolver (DNR) for generic domain name service (DNS) queries. You can ask for any query type and class, and in response, Open Transport returns as many
DNSQueryInfo
structures as it can fit in the buffer you provide.There are three types of responses: answers, authority responses, and additional information, and there are typically several of each type. Each response has its own
DNSQueryInfo
structure, with all the answers first, then all the authority records, then all the additional information. Authority responses refer you to DNS servers and other sources that may have helpful information for this answer and additional information responses provide address data for the servers and sources referred to in the authority records.If, for example, you use the
OTInetQuery
function to find out the IP addresses for a name, you might get back 13DNSQueryInfo
structures in your answer buffer. Each DNS Query Information structure might then contain 2 IP address structures, 4 authority responses, and 7 additional information responses.To help you parse this huge answer buffer, Open Transport provides two optional parameters for the
OTInetQuery
function,argv
andargvlen
, that create an array of pointers to the individual responses.Avoiding Delay When Rebinding to TCP Connections
When a connection closes, TCP imposes a two-minute timeout on binding before the same port can be bound to again. This prevents stale data from corrupting a new connection. This is in strict compliance with the TCP standard.You can work around this by using the
IP_REUSEADDR
option with theOTOptionManagement
function. If you set this option on all of your listening endpoints before you bind, the limitation should disappear. TheIP_REUSEADDR
option allows you to bind multiple connected or closing endpoints to addresses with the same port number.
The sample code shown in Listing 11-2 sets an option and assigns it to the location referenced by
- IMPORTANT
- Note that even using the
IP_REUSEADDR
option, you can only bind a single endpoint in a state less than connected (that is, listening or unbound endpoints) to the same port at a given time. You can, however, bind any number of connected or closing endpoints.value
. The endpoint is assumed to be in synchronous mode. If an error occurs, the function returns a negative result. If the option could not be read, a positive result (eitherT_FAILURE, T_PARTSUCCESS
, orTREADONLY
, orT_NOTSUPPORT
) is returned.Listing 11-2 Setting an option value
static 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); }In the body of the function, we use aTOption
structure to represent the option buffer and initialize its fields to specify the option and value we want to set. Next, we initialize therequest
parameter of theOTOptionManagement
function to reference the option buffer we just initialized. Thelength
field is set to the size of the option buffer and theflags
field is set toT_NEGOTIATE
to specify that we want to set the option value specified in the option buffer.You could invoke this function and set the
IP_REUSEADDR
option as follows:
err = SetFourByteOption(ep, INET_IP, IP_REUSEADDR, true);Using General Open Transport Functions With TCP/IP
This section describes special considerations you must take into account for Open Transport functions when you use them with the Open Transport TCP/IP implementation. You should be familiar with the function descriptions in the chapters ""Endpoints Reference and "Mappers Reference"in this book before reading this section.Obtaining Endpoint Data With TCP/IP
The following values can be returned by theinfo
parameter to theOTOpenEndpoint
,OTAsyncOpenEndpoint
, andOTGetEndpointInfo
functions when used with TCP/IP protocols.
These fields and the significance of their values are described in more detail in "Endpoints Reference".
- IMPORTANT
- The preceding table shows only what values are possible for each protocol. Be sure to to use the
OTOpenEndpoint
,OTAsyncOpenEndpoint
, orOTGetEndpointInfo
functions to obtain the current values for these parameters.Using Endpoint Functions With TCP/IP
This section describes protocol-specific information about functions described in the chapter "Endpoints Reference". The functions are listed in the same order that they appear in that chapter.OTBind
TheOTBind
function associates a local protocol address with the endpoint you specify. Use this function with the TCP and UDP protocols.The
addr
field of theTBind
structure refers to the local endpoint and so must specifically include a port number. Use anInetAddress
structure, described in "Internet Address Structure", to specify this address.Because the architecture of Open Transport TCP/IP provides for multihoming (although this feature has not yet been implemented), you can specify an IP address of
kOTAnyInetAddress
for theaddr
field to indicate that your application or process will accept packets from any TCP/IP interface that the user has configured in the TCP/IP control panel.If you bind to an address of
kOTAnyInetAddress
, then theOTGetProtAddress
function always returns an IP address of 0. In that case, you must use theOTInetGetInterfaceInfo
function to determine the IP address of a running IP interface. However, if you pass in a valid address with a port number ofkOTAnyInetAddress
, the TCP/IP service provider assigns a port for you and theOTGetProtAddress
function returns the assigned port number and the IP address.You can use the
OTInetGetInterfaceInfo
function to get the IP addresses of all currently configured IP interfaces. Then, if you wish to receive packets from only a single interface, you can bind the endpoint to the address for that interface.OTLook
TheOTLook
function checks for asynchronous events such as incoming data or connection requests. Use this function with the TCP protocol.As soon as a segment with the TCP urgent pointer set (that is, expedited data) enters the TCP receive buffer, TCP posts the
T_EXDATA
event. TheT_EXDATA
event remains posted until you have retrieved all data up to the byte pointed to by the TCP urgent pointer.OTGetProtAddress
You use this function with the TCP and UDP protocols.If you bind an endpoint to an IP address of
kOTAnyInetAddress
in order to accept packets from any valid TCP/IP interface, then theOTGetProtAddress
function always returns an IP address of 0. This is because in a multihomed machine, there is a separate IP address for each interface, and there's no way for Open Transport to know which one you want. In that case, you must use theOTInetGetInterfaceInfo
function to determine the IP address of a running IP interface. On the other hand, if you bind an endpoint to a specific interface, theOTGetProtAddress
function returns the address of that interface, as expected.OTConnect
TheOTConnect
function requests a connection to a specified remote endpoint. You can use this function with TCP.The
rcvcall->addr
field returns a copy of theTNetbuf
structure you specify in thesndcall->addr
field. Thediscon->reason
field contains a positive error code that indicates why the connection was rejected.Because TCP does not allow you to send any application-specific data during the connection establishment phase, you must set the
sndcall->udata.len
field to 0. TCP ignores the value of thesndcall->udata.buf
field.Note that TCP, not the receiving application, confirms the connection.
As mentioned in the X/Open Transport Interface (XTI) specification, because TCP cannot refuse a connection,
t_listen()
andt_accept()
have a semantic which is slightly different from that for ISO providers."As a result, an Open Transport TCP server will accept a TCP connection request if the current number of pending connections is less than the queue length (
qlen
) for the passive endpoint. Basically, what happens is that TCP connects even before you accept a connection.The client, whether in synchronous or asynchronous mode, will immediately receive notice that the connection has been established. For synchronous endpoints, TCP completes the 3-way connection handshake. For asynchronous endpoints, the
OTRcvConnect
function must be called to complete the handshake.This can result in situations like this: You send an
OTConnect
from a TCP client to a TCP server that passively awaits incoming connections, but even before the server responds with theOTListen
andOTAccept
calls, theOTConnect
call completes with no error. At this point, if you examine the client endpoint's state, you will find that it is in theT_DATAXFER
state, which is correct.OTRcvConnect
TheOTRcvConnect
function reads the status of a previously issued connection request. You can use this function with TCP.Because TCP does not allow you to send any application-specific data during the connection establishment phase, you must set the
call->udata.maxlen
field to 0. TCP ignores the value of thecall->udata.buf
field.On return, the
call->addr
field points to the Internet address of the endpoint that accepted the connection.OTListen
TheOTListen
function listens for an incoming connection request. You can use this function with TCP.When the
OTListen
function successfully completes execution (that is, when you receive theT_LISTEN
event), thecall
parameter describes a connection that has already been completed at the TCP level. You use theOTAccept
function to complete a connection at the application level. If you wish to reject a connection, you must call theOTSndDisconnect
function after theOTListen
function successfully completes execution.Because TCP does not allow you to send any application-specific data during the connection establishment phase, you must set the
call->udata.maxlen
field to 0. TCP ignores the value of thecall->udata.buf
field.OTAccept
TheOTAccept
function accepts an incoming connection request. You can use this function with TCP.Because TCP does not allow you to send any application-specific data during the connection establishment phase, you must set the
call->udata.len
field to 0. TCP ignores the value of thecall->udata.buf
field.If you wish to send either of the association-related options (
IP_OPTIONS
orIP_TOS
) with the connection confirmation, you must use theOTOptionManagement
function to set the values of these options before you receive theT_LISTEN
event. TCP has already established a connection when you receive theT_LISTEN
event, and it is too late for theOTAccept
function to negotiate these options.OTSndUData
TheOTSndUData
function sends data through a connectionless transactionless endpoint. You can use this function with UDP.The current value for the maximum size of a RawIP or UDP datagram is returned in the
info->tsdu
parameter of theOTOpenEndpoint
,OTAsyncOpenEndpoint
, andOTGetEndpointInfo
functions.OTSnd
TheOTSnd
function sends data through a connection-oriented transactionless endpoint. You can use this function with TCP.Because it does not support TSDU's, TCP ignores the
OTSnd
function'sT_MORE
flag.If you set the
T_EXPEDITED
flag, you must send at least 1 byte of data. If you call theOTSnd
function with more than 1 byte specified and theT_EXPEDITED
flag set, the TCP urgent pointer points to the last byte of the buffer.OTRcv
TheOTRcv
function receives data through a connection-oriented endpoint. You can use this function with TCP.Because TCP ignores the
T_MORE
flag when it is sending data and does not transmit the flag, you should ignore theT_MORE
flag when receiving normal data. However, if a byte in the data stream is pointed to by the TCP urgent pointer, TCP receives this byte and as many bytes as possible preceding the marked byte with theT_EXPEDITED
flag set. If your buffer is too small to receive all of the expedited data, TCP sets theT_MORE
flag as well. Note that this situation might result in the number of bytes received as expedited data not being equal to the number of bytes sent by the originator as expedited data.OTSndDisconnect
TheOTSndDisconnect
function initiates an abortive disconnect or rejects a connection request. You can use this function with TCP.Because TCP does not allow you to send any application-specific data during a disconnect, you must set the
call->udata.len
field to 0. TCP ignores any data in thecall->udata.buf
field.OTRcvDisconnect
TheOTRcvDisconnect
function returns information about why a connection attempt failed or an established connection was terminated. You can use this function with TCP.Because TCP does not allow you to send any application-specific data during a disconnection, you must set the
discon->udata.len
field to 0. TCP ignores the value of thediscon->udata.buf
field.This function returns a positive error code. To obtain the negative error code, subtract that positive value from -3199.
Using Mapper Functions With TCP/IP
This section describes protocol-specific information about functions described in the chapter "Mappers Reference" in this book. The functions are listed in the same order that they appear in that chapter.OTRegisterName
Because the TCP/IP domain name system does not include a method for clients to register their names on the network, the Open Transport domain name resolver (DNR) does not support theOTRegisterName
function. If you call this function for a TCP/IP mapper, it will return thekOTNotSupportedErr
result code.OTDeleteName
This function is not supported by the TCP/IP domain name resolver (DNR). If you call this function for a TCP/IP mapper, it will return thekOTNotSupportedErr
result code.OTLookupName
You can use theOTLookupName
function to resolve a domain name to an Internet address. Specify the name as a character string pointed to by therequest->udata.buf
parameter. The name can be just a host name ("otteam"), a partially qualified domain name ("otteam.ssw"), a fully qualified domain name ("otteam.ssw.apple.com."), or an Internet address in dotted-decimal format ("17.202.99.99"), and can optionally include the port number ("otteam.ssw.apple.com:25" or "17.202.99.99:25").The function returns a pointer to the address in the
reply->udata.buf
parameter. The address is in the format of anInetAddress
structure , which includes the address type, the port number, and the IP address. If you don't specify a port number, the returnedInetAddress
structure contains a port number of 0. You can use this address directly in all Open Transport functions that require an Internet address, such asOTConnect
,OTSndUData
, andOTBind
.The
OTLookupName
function returns only a single address, regardless of how many addresses are known for a single multihomed host. To obtain a list of up to 10 addresses for a multihomed host, use theOTInetStringToAddress
function .
Subtopics
- Setting Options When Configuring a TCP/IP Provider
- Using RawIP
- Receiving RawIP Datagrams
- Sending RawIP Datagrams
- Manually Setting the IP Header
- Limitations of the Header-Included Mode
- Using IP Multicasting
- Querying DNS Servers
- Avoiding Delay When Rebinding to TCP Connections
- Using General Open Transport Functions With TCP/IP
- Obtaining Endpoint Data With TCP/IP
- Using Endpoint Functions With TCP/IP
- Using Mapper Functions With TCP/IP