The X/Open Transport Interface (XTI) is a transport layer application interface that consists of a series of functions designed to be independent of the specific transport provider used. In the Digital UNIX operating system XTI is implemented according to the XPG3 and XPG4 specifications. XPG4 is the default. (XPG3 is provided for backward compatibility and is available by using a compiler switch.) For more information about XPG3 and XPG4, see the X/Open Portability Guide Volume 7: Networking Services. The Digital UNIX implementation of XTI is also thread safe.
Although similar in concept to the Berkeley socket interface, XTI is based on the AT&T Transport Layer Interface (TLI). TLI, in turn, is based on the transport service definition for the Open Systems Interconnection (OSI) model.
Note
Digital UNIX includes the Transport Control Protocol (TCP) and User Datagram Protocol (UDP) transport providers. Although the information provided in this chapter applies to all transport providers that Digital UNIX XTI supports, such as DECnet/OSI, the examples are specific to TCP or UDP. For more specific information using XTI over TCP and UDP, see the xti_internet(7) reference page. For examples and information specific to other transport providers, see the documentation that accompanies their software.
This chapter contains the following information:
Figure 3-1 highlights XTI and its relationship to the Digital UNIX implementation of the Internet Protocol suite. It also shows how XTI and the Internet Protocol suite fit into the rest of the network programming environment.
XTI involves the interaction of the following entities:
A transport provider is a transport protocol, such as TCP or UDP, that offers transport layer services.
A transport user is an application program that requires the services of a transport provider to send data to or receive data from another program. A transport user communicates with a transport provider over a communications path identified by a transport endpoint.
A transport endpoint is created when an application issues a t_open library call. All of the transport user's requests to the transport provider pass through the endpoint associated with that provider.
The transport user activates a transport endpoint by binding a transport address to it. Once an endpoint is active, a transport user can send data over it. The transport provider routes the data to the appropriate peer user or other destination.
When using a connection-oriented transport service, such as TCP, the transport user must establish a connection between itself and a peer transport user with a t_connect function, specifying an active endpoint, before sending data. In a transport connection, the transport user initiating the connection is the active user, or client, and the peer transport user responding to the connection request is the passive user, or server. Figure 3-2 summarizes the relationship between transport providers, transport users, and transport endpoints.
XTI consists of library calls, header files, and the rules and restrictions elaborating how XTI processes work and interact. This section describes the library calls and header files, as well as the regulations that govern the interaction between communicating processes.
Transport users use different service modes and execution modes to determine how data is exchanged with transport providers. The following sections introduce the service modes and execution modes available in XTI.
In XTI, an endpoint can support one of the following modes of service:
A circuit-oriented service that transfers data over an established connection in a reliable, sequenced manner.
Connection-oriented transport is useful for applications that require long, order dependent and reliable, stream-oriented interactions. With connection-oriented transport, transport users and providers can negotiate the parameters and options that govern data transfer. In addition, because a connection provides identification of both parties, the transport user avoids the overhead of transmitting and resolving addresses during data transfer. A connection also provides a context that logically relates successive units of data.
A message-oriented service that transfers data in self-contained units or datagrams, which have no logical sequence with respect to one another.
Connectionless transport is best suited for applications that have the following qualities:
Each data unit is self-contained and has no relationship to previous or successive data units, so the transport provider can route it independently.
Execution modes provide a means for transport users to handle completion of functions and receipt of events. An event is an occurrence or happening that is significant to a transport user. XTI supports two execution modes:
Waits for transport primitives to complete before returning control to the transport user. Also known as blocking mode.
Synchronous mode is suited for applications that want to wait for functions to complete or maintain only a single transport connection. In synchronous mode, the transport user cannot perform other tasks while waiting for a function to complete. For example, if the transport user issues a t_rcv function in synchronous mode, t_rcv waits until data is received before returning control to the transport user.
Even while using synchronous mode, it is possible to get some event notification, which the transport user does not ordinarily expect. Such asynchronous events are returned to the user through a special error, TLOOK.
If an asynchronous event occurs while a function is executing, the function returns the TLOOK error; the transport user can then issue the t_look function to retrieve the event.
Returns control to the transport user before transport primitives complete. Also known as nonblocking mode.
Asynchronous mode is useful for applications that have long delays between completion of functions and other tasks to perform in the meantime. This mode is also useful for applications that handle multiple connections simultaneously. Many applications handle networking functions in asynchronous mode because they can perform useful work while waiting for particular networking functions to complete. For example, if a transport user issues a t_rcv function call in asynchronous mode, the function returns control to the user immediately if no data is available. The user periodically polls for data until the data arrives.
By default, all functions that process incoming events operate in synchronous mode, blocking until the task completes. To select asynchronous mode, the transport user specifies the O_NONBLOCK flag with the t_open function when the endpoint is created or before executing a function or group of functions with the fcntl operating system call.
For a full discussion of the specific events supported by XTI, see Section 3.2.3.
XTI functions are implemented as part of the XTI library, libxti.a. TLI functions are implemented in a separate TLI library, libtli.a. There are also shared versions of these libraries, libxti.so and libtli.so.
Digital UNIX provides shared library support by default when you link an XTI or TLI application with the XTI or TLI library.
For XTI or TLI applications built in the Digital UNIX Version 1.2 environment to use shared library support, you must relink the required object files with the appropriate library. You do not need to recompile source files.
The first of the following examples illustrates how to relink an XTI application's object files with the XTI shared library; the second illustrates how to relink a TLI application's object files with the TLI shared library:
%
cc -o XTI
app
XTI
appmain
.o
XTI
apputil
.o -lxti
%
cc -o TLI
app
TLI
appmain
.o
TLI
apputil
.o -ltli
To link programs statically with the XTI or TLI libraries (as was the default in Digital UNIX Version 1.2), use the non_shared option to the cc command.
The following example illustrates how to link an XTI application's object files to the XTI library statically:
%
cc -non_shared -o XTI
app
XTI
appmain
.o
\
XTI
apputil
.o -lxti
See the cc(1) reference page for more information.
To make a program thread safe, build the program with DECthreads pthreads routines. For more information, see Guide to DECthreads.
The few differences between XTI and TLI are described in Section 3.5.2, which also describes how to link your programs with the correct library at compile time.
XTI and TLI header files contain data definitions, structures, constants, macros, and options used by the XTI and TLI library calls. An application program must include the appropriate header file to make use of structures or other information a particular XTI or TLI library call requires. Table 3-1 lists the XTI and TLI header files.
File Name | Description |
<tiuser.h> | Contains data definitions and structures for TLI applications. You must include this file for all TLI applications. |
<xti.h> | Contains data definitions and structures for XTI applications. You must include this file for all XTI applications. |
<fcntl.h> | Defines flags for modes of execution for the t_open function. You must include this file for all XTI and TLI applications. |
Note
Typically, header file names are enclosed in angle brackets (< >). To obtain the absolute path to the header file, prepend /usr/include/ to the information enclosed in the angle brackets. For example, the absolute path for the tiuser.h file is /usr/include/tiuser.h.
Some of the calls apply to connection-oriented transport (COTS), some to connectionless transport (CLTS), some to connection-oriented transport when used with the orderly release feature (COTS_ORD), and some to all service modes. A small group of the calls are utility functions and do not apply to a particular service mode. Table 3-2 lists the name, purpose, and service mode of each XTI library call. Each call has an associated reference page by the same name.
Digital UNIX provides
XTI reference pages only; it does not provide TLI reference pages. For
information about TLI and for the TLI reference pages see the
UNIX System V Programmer's Guide: Networking Interfaces,
which is issued
by UNIX System Laboratories, Inc.
Digital UNIX provides reference pages for each of the functions. For
more information, see the
X/Open CAE Specification: Networking Services.
Name of Call | Purpose | Service Mode |
t_accept | Accepts a connection request | COTS, COTS_ORD |
t_alloc | Allocates memory for a library structure | All |
t_bind | Binds an address to a transport endpoint | All |
t_close | Closes a transport endpoint | All |
t_connect | Establishes a connection with another transport user | COTS, COTS_ORD |
t_error | Produces an error message | All |
t_free | Frees memory previously allocated for a library structure | All |
t_getinfo | Returns protocol-specific information | All |
t_getprotaddr |
Returns the protocol address | All |
t_getstate | Returns the current state for the transport endpoint | All |
t_listen | Listens for a connection request | COTS, COTS_ORD |
t_look | Returns the current event on the transport endpoint | All |
t_open | Establishes a transport endpoint | All |
t_optmgmt | Retrieves, verifies, or negotiates protocol options | All |
t_rcv | Receives data or expedited data over a connection | COTS, COTS_ORD |
t_rcvconnect | Receives the confirmation from a connection request | COTS, COTS_ORD |
t_rcvdis | Identifies the cause of a disconnect, and retrieves information sent with a disconnect | COTS, COTS_ORD |
t_rcvrel |
Acknowledges receipt of an orderly release indication | COTS_ORD |
t_rcvudata | Receives a data unit | CLTS |
t_rcvuderr | Receives information about an error associated with a data unit | CLTS |
t_snd | Sends data or expedited data over a connection | COTS, COTS_ORD |
t_snddis | Initiates a release on an established connection, or rejects a connection request | COTS, COTS_ORD |
t_sndrel |
Initiates an orderly release | COTS_ORD |
t_sndudata | Sends a data unit | CLTS |
t_strerror |
Produces an error message string | All |
|
||
t_sync | Synchronizes the data structures in the transport library | All |
t_unbind | Disables a transport endpoint | All |
Table notes:
XTI supports an orderly release mechanism, t_sndrel and t_rcvrel functions. (See Table 3-2 for more information.) However, if your applications need to be portable to the ISO transport layer, we recommend that you do not use this mechanism.
Finally, the XTI header file defines the following constants to identify service modes:
These service modes are returned by the transport provider in the servtype field of the info structure when you create an endpoint with the t_open function.
Each transport provider has a particular state associated with it, as viewed by the transport user. The state of a transport provider and its transition to the next allowable state is governed by outgoing and incoming events, which correspond to the successful return of specified user-level transport functions. Outgoing events correspond to functions that send a request or response to the transport provider, whereas incoming events correspond to functions that retrieve data or event information from the transport provider. This section describes the possible states of the transport provider, the outgoing and incoming events that can occur, and the allowable sequence of function calls.
XTI applications must manage asynchronous events. An asynchronous event is identified by a mnemonic which is defined as a constant in the XTI header file. Table 3-3 lists the name, purpose, and service mode for each type of asynchronous event in XTI.
Event Name | Purpose | Service Mode |
T_CONNECT | The transport provider received a connection response. This event usually occurs after the transport user issues the t_connect function. |
COTS,
COTS_ORD |
T_DATA | The transport provider received normal data, which is all or part of a Transport Service Data Unit (TSDU). |
COTS, CLTS,
COTS_ORD |
T_DISCONNECT | The transport provider received a disconnect request. This event usually occurs after the transport user issues data transfer functions, the t_accept function, or the t_snddis function. |
COTS,
COTS_ORD |
T_EXDATA | The transport provider received expedited data. |
COTS,
COTS_ORD |
T_GODATA | The flow control restrictions on the flow of normal data are lifted. The transport user can send normal data again. |
COTS, CLTS,
COTS_ORD |
T_GOEXDATA | The flow control restrictions on the flow of expedited data are lifted. The transport user can send expedited data again. |
COTS,
COTS_ORD |
T_LISTEN | The transport provider received a connection request from a remote user. This event occurs only when the file descriptor is bound to a valid address and no transport connection is established. |
COTS,
COTS_ORD |
T_ORDREL | The transport provider received a request for an orderly release. | COTS_ORD |
T_UDERR | An error was found on a datagram that was previously sent. This event usually occurs after the transport user issues the t_rcvudata or t_unbind functions. | CLTS |
XTI stores all events that occur at a transport endpoint.
If using a synchronous mode of execution, the transport user returns from the function it was executing with a value of -1 and then checks for a value of TLOOK in t_errno and retrieves the event with the t_look function. In asynchronous mode, the transport user continues doing productive work and periodically checks for new events.
Every event at a transport endpoint is consumed by a specific XTI function, or it remains outstanding. Exceptions are the T_GODATA and T_GOEXDATA events, which are cleared by retrieving them with t_look. Thus, once the transport user receives a TLOOK error from a function, subsequent calls to that function or a different function continue to return the TLOOK error until the transport user consumes the event. Table 3-4 summarizes the consuming functions for each asynchronous event.
Event | Cleared by t_look | Consuming Function(s) |
T_CONNECT | No | t_connect, t_rcvconnect |
T_DATA | No | t_rcv, t_rcvudata |
T_DISCONNECT | No | t_rcvdis |
T_EXDATA | No | t_rcv |
T_GODATA | Yes | t_snd, t_sndudata |
T_GOEXDATA | Yes | t_snd |
T_LISTEN | No | t_listen |
T_ORDREL | No | t_rcvrel |
T_UDERR | No | t_rcvuderr |
Table 3-5 lists the events that cause a specific XTI function to return the TLOOK error. This information may be useful when you structure the event checking mechanisms in your XTI applications.
Function | Events Causing TLOOK |
t_accept | T_DISCONNECT, T_LISTEN |
t_connect |
T_DISCONNECT, T_LISTEN |
t_listen |
T_DISCONNECT |
t_rcv |
T_DISCONNECT, T_ORDREL |
t_rcvconnect | T_DISCONNECT |
t_rcvrel | T_DISCONNECT |
t_rcvudata | T_UDERR |
t_snd | T_DISCONNECT, T_ORDREL |
t_snddis | T_DISCONNECT |
t_sndrel | T_DISCONNECT |
t_sndudata | T_UDERR |
t_unbind |
T_LISTEN, T_DATA |
Table notes:
Each XTI function manages one transport endpoint at a time. It is not possible to wait for several events from different sources, particularly from several transport connections at a time. The Digital UNIX implementation of XTI allows the transport user to monitor input and output on a set of file descriptors with the poll function. See poll(2) for more information.
XTI uses eight states to manage communication over a transport endpoint. Both the active and passive user have a unique state that reflects the function in process.
Table 3-6 describes the purpose of each XTI state. A service mode of COTS indicates the state occurs regardless of whether or not orderly service is implemented. A service mode of COTS_ORD indicates the state occurs only when orderly service is implemented.
State | Description | Service Mode |
T_UNINIT | Uninitialized. Initial and final state of the interface. To establish a transport endpoint, the user must issue a t_open. | COTS, CLTS, COTS_ORD |
T_UNBIND | Unbound. The user can bind an address to a transport endpoint or close a transport endpoint. | COTS, CLTS, COTS_ORD |
T_IDLE | Idle. The active user can establish a connection with a passive user (COTS), disable a transport endpoint (COTS, CLTS), or send and receive data units (CLTS). The passive user can listen for a connection request (COTS). | COTS, CLTS, COTS_ORD |
T_OUTCON | Outgoing connection pending. The active user can receive confirmations for connection requests. | COTS, COTS_ORD |
T_INCON | Incoming connection pending. The passive user can accept connection requests. | COTS, COTS_ORD |
T_DATAXFER | Data transfer. The active user can send data to and receive data from the passive user. The passive user can send data to and receive data from the active user. | COTS, COTS_ORD |
T_OUTREL | Outgoing orderly release. The user can respond to an orderly release indication. | COTS_ORD |
T_INREL | Incoming orderly release. The user can send an orderly release indication. | COTS_ORD |
If you are writing a connection-oriented application, note that your program can release a connection at any time during the connection-establishment state or data-transfer state.
The XTI library keeps track of outgoing and incoming events to manage the legal states of transport endpoints. The following sections describe these outgoing and incoming events.
Outgoing events are caused by XTI functions that send a request or response to the transport provider. An outgoing event occurs when a function returns successfully. Some functions produce different events, depending on the following values:
ocnt |
A count of outstanding connection indications (those passed to the transport
user but not yet accepted or rejected). This count is only meaningful for
the current transport endpoint
( fd ). |
fd | The file descriptor of the current transport endpoint. |
resfd | The file descriptor of the endpoint where a connection will be accepted. |
Table 3-7 describes the outgoing events available in XTI. A service mode of COTS indicates the event occurs for a connection-oriented service regardless of whether or not orderly service is implemented. A service mode of COTS_ORD indicates the event occurs only when orderly service is implemented.
Event | Description | Service Mode |
opened | Successful return of t_open function. | COTS, CLTS, COTS_ORD |
bind | Successful return of t_bind function. | COTS, CLTS, COTS_ORD |
optmgmt | Successful return of t_optmgmt function. | COTS, CLTS, COTS_ORD |
unbind | Successful return of t_unbind function. | COTS, CLTS, COTS_ORD |
closed | Successful return of t_close function. | COTS, CLTS, COTS_ORD |
connect1 | Successful return of t_connect function in synchronous execution mode. | COTS, COTS_ORD |
connect2 | The t_connect function returned the TNODATA error in asynchronous mode, or returned the TLOOK error because a disconnect indication arrived on the transport endpoint. | COTS, COTS_ORD |
accept1 | Successful return of t_accept function, where ocnt == 1 and fd == resfd. | COTS, COTS_ORD |
accept2 | Successful return of t_accept function, where ocnt == 1 and fd != resfd. | COTS, COTS_ORD |
accept3 | Successful return of t_accept function, where ocnt > 1. | COTS |
snd | Successful return of t_snd function. | COTS |
snddis1 | Successful return of t_snddis function, where ocnt <= 1. | COTS, COTS_ORD |
snddis2 | Successful return of t_snddis function, where ocnt > 1. | COTS, COTS_ORD |
sndrel | Successful return of t_sndrel function. | COTS_ORD |
sndudata | Successful return of t_sndudata function. | CLTS |
Incoming events are caused by XTI functions that retrieve data or events from the transport provider. An incoming event occurs when a function returns successfully. Some functions produce different events, depending on the value of the ocnt variable. This variable is a count of outstanding connection indications (those passed to the transport user but not yet accepted or rejected). This count is only meaningful for the current transport endpoint (fd).
The pass_conn incoming event is not associated directly with the successful return of a function on a given endpoint. The pass_conn event occurs on the endpoint that is being passed a connection from the current endpoint. No function occurs on the endpoint where the pass_conn event occurs.
Table 3-8 describes the incoming events available in XTI. A service mode of COTS indicates the event occurs regardless of whether or not orderly service is implemented. A service mode of COTS_ORD indicates the event occurs only when orderly service is implemented.
Event | Description | Service Mode |
listen | Successful return of the t_listen function | COTS, COTS_ORD |
rcvconnect | Successful return of the t_rcvconnect function | COTS, COTS_ORD |
rcv | Successful return of the t_rcv function | COTS, COTS_ORD |
rcvdis1 | Successful return of the t_rcvdis function, where ocnt == 0 | COTS, COTS_ORD |
rcvdis2 | Successful return of the t_rcvdis function, where ocnt == 1 | COTS, COTS_ORD |
rcvdis3 | Successful return of the t_rcvdis function, where ocnt > 1 | COTS, COTS_ORD |
rcvrel | Successful return of the t_rcvrel function | COTS_ORD |
rcvudata | Successful return of the t_rcvudata function | CLTS |
rcvuderr | Successful return of the t_rcvuderr function | CLTS |
pass_conn | Successfully received a connection that was passed from another transport endpoint | COTS, COTS_ORD |
This section describes the relationship among XTI functions, outgoing and incoming events, and states. Since XTI has well-defined rules about state transitions, it is possible to know the next allowable state given the current state and most recently received event. This section provides detailed tables that map the current event and state to the next allowable state.
This section excludes the t_getstate, t_getinfo, t_alloc, t_free, t_look, t_sync, and t_error functions from discussions of state transitions. These utility functions do not affect the state of the transport interface, so they can be issued from any state except the uninitialized (T_UNINIT) state.
To use Table 3-9, Table 3-10, and Table 3-11, find the row that matches the current incoming or outgoing event and the column that matches the current state. Go to the intersection of the row and column to find the next allowable state. A dash (--) at the intersection indicates an invalid combination of event and state. Some state transitions are marked by a number in parentheses that indicates an action that the transport user must take. The numbers and their meanings are listed at the end of the appropriate table.
Table 3-9 shows the state transitions for initialization and deinitialization functions, functions that are common to both the connection-oriented and connectionless modes of service. For example, if the current event and state are bind and T_UNBND, the next allowable state is T_IDLE. In addition, the transport user must set the count of outstanding connection indications to zero, as indicated by the numeral 1.
Event | T_UNINIT State | T_UNBND State | T_IDLE State |
opened | T_UNBND | -- | -- |
bind | -- |
T_IDLE |
-- |
unbind | -- | -- | T_UNBND |
closed | -- | T_UNINIT | T_UNINIT |
Table notes:
Table 3-10 shows the state transitions for data transfer functions in connectionless transport services.
Event | State T_IDLE |
sndudata | T_IDLE |
rcvudata | T_IDLE |
rcvuderr | T_IDLE |
Table 3-11 and Table 3-12 show the transitions for connection, release, and data transfer functions in connection-oriented transport services for incoming and outgoing events. For example, if the current event and state are accept2 and T_INCON, the next allowable state is T_IDLE, providing the transport user decrements the count of outstanding connection indications and passes a connection to another transport endpoint.
Event | T_IDLE State | T_OUTCON State | T_INCON State | T_DATAXFER State |
connect1 | T_DATAXFER | -- | -- | -- |
connect2 | T_OUTCON | -- | -- | -- |
rcvconnect | -- | T_DATAXFER | -- | -- |
listen |
T_INCON |
-- |
T_INCON |
-- |
accept1 | -- | -- |
T_DATAXFER |
-- |
accept2 | -- | -- |
T_IDLE |
-- |
accept3 | -- | -- |
T_INCON |
-- |
snd | -- | -- | -- | T_DATAXFER |
rcv | -- | -- | -- | T_DATAXFER |
snddis1 | -- | T_IDLE |
T_IDLE |
T_IDLE |
snddis2 | -- | -- |
T_INCON |
-- |
rcvdis1 | -- | T_IDLE | -- | T_IDLE |
rcvdis2 | -- | -- |
T_IDLE |
-- |
rcvdis3 | -- | -- |
T_INCON |
-- |
sndrel | -- | -- | -- | T_OUTREL |
rcvrel | -- | -- | -- | T_INREL |
pass_conn | T_DATAXFER | -- | -- | -- |
optmgmt | T_IDLE | T_OUTCON | T_INCON | T_DATAXFER |
closed | T_UNINIT | T_UNINIT | T_UNINIT | T_UNINIT |
Table notes:
Event | T_OUTREL State | T_INREL State | T_UNBND State |
connect1 | -- | -- | -- |
connect2 | -- | -- | -- |
rcvconnect | -- | -- | -- |
listen | -- | -- | -- |
accept1 | -- | -- | -- |
accept2 | -- | -- | -- |
accept3 | -- | -- | -- |
snd | -- | T_INREL | -- |
rcv | T_OUTREL | -- | -- |
snddis1 | T_IDLE | T_IDLE | -- |
snddis2 | -- | -- | -- |
rcvdis1 | T_IDLE | T_IDLE | -- |
rcvdis2 | -- | -- | -- |
rcvdis3 | -- | -- | -- |
sndrel | -- | T_IDLE | -- |
rcvrel | T_IDLE | -- | -- |
pass_conn | -- | -- | T_DATAXFER |
optmgmt | T_OUTREL | T_INREL | T_UNBND |
closed | T_UNINIT | T_UNINIT | -- |
In general, if you use multiple processes, you need to synchronize them carefully to avoid violating the state of the interface.
Although transport providers treat all transport users of a transport endpoint as a single user, the following situations are possible:
For a single process to manage several endpoints in synchronous execution mode, the process must manage the actions on each endpoint serially instead of in parallel. Optionally, you can write a server to manage several endpoints at once. For example, the process can listen for an incoming connection indication on one endpoint and accept the connection on a different endpoint, so as not to block incoming connections. Then, the application can fork a child process to service the requests from the new connection.
Multiple processes that share a single endpoint must coordinate actions to avoid violating the state of the interface. To do this, each process calls the t_sync function, which retrieves the current state of the transport provider, before issuing other functions. If all processes do not cooperate in this manner, another process or an incoming event can change the state of the interface.
Similarly, while several endpoints can share the same protocol address,
only one can listen for incoming connections. Other endpoints sharing the
protocol address can be in data transfer state or in
the process of establishing
a connection without causing a conflict.
This means that an address can have only one server, but multiple endpoints can call
the address at the same time.
This section presents guidelines to help you sequence functions, manage states, and use XTI options. It then describes the steps required to write both connection-oriented and connectionless programs to XTI.
Figure 3-3 shows the typical sequence of functions and state transitions for an active user and passive user communicating with a connection-oriented transport service in nonblocking mode. The solid lines in the figure show the state transitions for the active user, while the dashed lines show the transitions for the passive user. Each line represents the call of a function, while each ellipse represents the resulting state. This example does not include the orderly release feature.
Figure 3-4 shows the typical sequence of functions and transitions in state for two users communicating with the connectionless transport service. Each line in the figure represents the call of a function, while each ellipse represents the resulting state. Both users are represented by solid lines.
All transport providers take the following actions with respect to states:
The uninitialized state (T_UNINIT) serves two purposes:
Follow these steps to write a connection-mode application:
To initialize an endpoint, complete the following steps:
Note that the steps described here for initializing an endpoint for connection-oriented service are identical for connectionless service.
Both connection-oriented and connectionless applications must open a transport endpoint using the t_open function. The syntax of the t_open function is as follows:
fd = t_open (name,oflag,&info) ;
In the preceding statement:
The t_open function returns a file descriptor upon successful completion. Otherwise, t_open returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
Note
Using the special device with any mechanism other than XTI/TLI, for example, direct open, read, or write calls, is illegal and will generate undefined results.
If you are designing a protocol-independent program, you can determine data buffer sizes by accessing the information that the t_open function returns about the t_info structure. If the transport user exceeds the allowed data size, you receive an error. Alternatively, you can use the t_alloc function to allocate data buffers.
See t_open(3) for more information.
The following is an example of the t_open function for the TCP transport provider:
if ( (newfd = t_open( "/dev/streams/xtiso/tcp" , O_RDWR , NULL) ) == -1 ) { (void) t_error("could not open tcp transport"); exit (1); }
Once you open an endpoint, you need to bind a protocol address to the endpoint. By binding the address, you activate the endpoint. In connection mode, you also direct the transport provider to begin accepting connection indications or servicing connection requests on the transport endpoint. To determine if the transport provider has accepted a connection indication, you can issue the t_listen function. In connectionless mode, once you bind the address, you can send or receive data units through the transport endpoint.
To bind an address to an endpoint, issue the t_bind function with the following syntax:
t_bind (fd,req,ret) ;
In the preceding statement:
See t_bind(3) for more information.
If the transport provider supports the automatic generation of addresses, you have the following choices in binding addresses:
To determine if the transport provider generates addresses, do not specify one in the t_bind function (set req to a null pointer). If the transport provider supplies addresses, the function returns an assigned address in the ret field. If the transport provider does not supply addresses, the function returns an error of TNOADDR.
If you accept a connection on an endpoint that is used for listening for connection indications, the bound address is busy for the duration of the connection. You cannot bind any other endpoint for listening on that same address while the initial listening endpoint is actively transferring data or in T_IDLE state.
You can use the gethostbyname routine, described in Section 4.2.3.2, to obtain host information when either TCP or UDP is the underlying transport provider.
If you use a method to retrieve host information other than the gethostbyname routine, consider the following:
The t_bind function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
XPG3 and XPG4 implement option management differently.
In XPG3, option management is handled exclusively by the t_optmgmt function. In XPG4, several functions contain an opt argument which is used to convey options between a transport user and the transport provider.
For more information, see Section 3.6.6.
The connection establishment phase typically consists of the following actions:
These steps are described in the following sections.
The passive user issues the t_listen function to look for enqueued connection indications. If the t_listen function finds a connection indication at the head of the queue, it returns detailed information about the connection indication and a local sequence number that identifies the indication. The number of outstanding connection indications that can be queued is limited by the value of the qlen parameter that was accepted by the transport provider when the t_bind function was issued.
By default, the t_listen function executes synchronously by waiting for a connection indication to arrive before returning control to the user. If you set the O_NONBLOCK flag of the t_open function or the fcntl function for asynchronous execution, the t_listen function checks for an existing connection indication and returns an error of TNODATA if none is available.
To listen for connection requests, issue the t_listen function with the following syntax:
t_listen (fd,call) ;
In the preceding statement:
See t_listen(3) for more information.
The t_listen function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
A connection is initiated in either synchronous or asynchronous
mode. In synchronous mode, the active user issues the
t_connect
function, which waits for the passive user's response before returning
control to the active user. In asynchronous mode,
t_connect
initiates
a connection but returns control to the active user before a response to
the connection arrives. Then, the active user can determine the status
of the connection request by issuing the
t_rcvconnect
function. If the passive
user accepted the request, the
t_rcvconnect
function returns successfully and
the connection establishment phase is complete. If a response has not
been received yet, the
t_rcvconnect
function returns an error of TNODATA. The
active user should issue the
t_rcvconnect
function again later.
To initiate a connection, issue the t_connect function with the following syntax:
t_connect (fd,sndcall,rcvcall) ;
In the preceding statement:
See t_connect(3) for more information.
The t_connect function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
When the passive user accepts a connection indication, it can issue the t_accept function on the same endpoint (the endpoint where it has been listening with t_listen) or a different endpoint.
If the passive user accepts on the same endpoint, the endpoint can no longer receive and enqueue incoming connection indications. The protocol address that is bound to the endpoint remains busy for the duration it is active. No other transport endpoints can be bound to the same protocol address as the listening endpoint. That is, no other endpoints can be bound until the passive user issues the t_unbind function. Further, before the connection can be accepted on the same endpoint, the passive user must respond (with either the t_accept or t_snddis functions) to all previous connection indications that it has received. Otherwise, t_accept returns an error of TBADF.
If the passive user accepts the connection on a different endpoint, the listening endpoint can still receive and enqueue incoming connection requests. The different endpoint must already be bound to a protocol address and be in the T_IDLE state. If the protocol address is the same as for the endpoint where the indication was received, the qlen parameter must be set to zero (0).
For both types of endpoints, t_accept will fail and return an error of TLOOK if there are connect or disconnect indications waiting to be received.
To accept a connection, issue the t_accept function with the following syntax:
t_accept (fd,resfd,call) ;
In the preceding statement:
See t_accept(3) for more information.
The t_accept function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
Once a connection is established between two endpoints, the active and passive users can transfer data in full-duplex fashion over the connection. This phase of connection-oriented service is known as the data transfer phase. The following sections describe how to send and receive data during the data transfer phase.
Transport users can send either normal or expedited data over a connection with the t_snd function. Normally, t_snd sends successfully and returns the number of bytes accepted if the transport provider can immediately accept all the data. If the data cannot be accepted immediately, the result of t_snd depends on whether it is executing synchronously or asynchronously.
By default, the t_snd function executes synchronously and waits if flow control conditions prevent the transport provider from accepting the data. The function blocks until one of the following conditions becomes true:
If the O_NONBLOCK flag was set when the endpoint was created, t_snd executes asynchronously and fails immediately if flow control restrictions exist. In some cases, only part of the data was accepted by the transport provider, so t_snd returns a value that is less than the number of bytes that you requested to be sent. At this point, you can do one of the following:
To send data or expedited data over a connection, issue the t_snd function with the following syntax:
t_snd (fd,buf,nbytes,flags) ;
In the preceding statement:
Send the data as expedited data. The expedited data is subject to the interpretations of the transport provider. Some transport providers don't support expedited data.
Indicates that another t_snd function will follow with more data for the current TSDU or ETSDU. The end of the TSDU or ETSDU is indicated by a t_snd function without T_MORE set.
Some transport providers do not support the concept of a TSDU or ETSDU, so the T_MORE flag is not meaningful. To find out if the transport provider supports TSDUs and ETSDUs, check the info argument of the t_open or t_getinfo function. If the tsdu field of info is greater than zero (0), the transport provider supports a record-oriented mode, and the return value indicates the maximum size of a TSDU. If the tsdu field is zero, the transport provider supports a stream-oriented mode of sending data. The T_MORE flag has no bearing on how the data is packaged for transfer at layers below the transport interface.
See t_snd(3) for more information.
The t_snd function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
Transport users can receive either normal or expedited data over a connection with the t_rcv function. Typically, if data is available, t_rcv returns the data. If the connection has been disconnected, t_rcv returns immediately with an error. If data is not available, but the connection still exists, t_rcv behaves differently depending on the mode of execution:
Instead of issuing t_rcv and waiting, you can issue the t_look function and check for the T_DATA or T_EXDATA events.
To receive data, issue the t_rcv function with the following syntax:
t_rcv (fd,buf,nbytes,flags) ;
In the preceding statement:
If you retrieve part of a TSDU and expedited data arrives, the receipt of the remainder of the TSDU is suspended until you process the ETSDU. For example, if you received data with T_MORE set and then received data with T_EXPEDITED and T_MORE set, this indicates a situation where expedited data arrived in the middle of your receipt of a TSDU. After you retrieve the full ETSDU, you can retrieve the remainder of the TSDU. It is the responsibility of the application programmer to remember that the receipt of normal data has been interrupted.
See t_rcv(3) for more information.
The t_rcv function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
XTI supports two ways to release connections: abortive release and orderly release. All transport providers support abortive release. Orderly release is not provided by all transport providers. For example, the OSI transport supports only abortive release, while TCP supports abortive release and optionally, orderly release.
An abortive release, which can be requested by the transport user or the transport provider, aborts a connection immediately. Abortive releases cannot be negotiated, and once the abortive release is requested, there is no guarantee that user data will be delivered.
Transport users can request an abortive release in either the connection establishment or data transfer phases. During connection establishment, a transport user can use the abortive release to reject a connection request. In data transfer phase, either user can release the connection at any time. If a transport provider requests an abortive release, both users are informed that the connection no longer exists.
To request an abortive release or to reject a connection indication, issue the t_snddis function with the following syntax:
t_snddis (fd,call) ;
In the preceding statement:
See t_snddis(3) for more information.
Transport users are notified about abortive releases through the T_DISCONNECT event. If your program receives a T_DISCONNECT event, it must issue the t_rcvdis function to retrieve information about the disconnect and to consume the T_DISCONNECT event. The following is the syntax of the t_rcvdis function:
t_rcvdis (fd,discon) ;
In the preceding statement:
See t_rcvdis(3) for more information.
Both t_snddis and t_rcvdis return a value of 0 upon successful completion. Otherwise, they return a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
An orderly release allows for release of a connection without loss of data. Orderly release is not provided by all transport providers. If the transport provider returned a service type of T_COTS_ORD with the t_open or t_getinfo functions, orderly release is supported. Transport users can request an orderly release during the data transfer phase. The typical sequence of orderly release is as follows:
To initiate an orderly release, use the t_sndrel function which has the following syntax:
t_sndrel (fd) ;
In the preceding statement:
The transport user cannot send more data over the connection after it issues the t_sndrel function. The transport user can, however, continue to receive data until it receives an orderly release indication (the T_ORDREL event).
See t_sndrel(3) for more information.
To acknowledge the receipt of an orderly release indication, issue the t_rcvrel function with the following syntax:
t_rcvrel (fd) ;
In the preceding statement:
After a transport user receives an orderly release indication (T_ORDREL), it cannot receive more data. (If the user attempts to do so, the function blocks indefinitely.) The transport user can, however, continue to send data until it issues the t_sndrel function.
See t_rcvrel(3) for more information.
Both t_sndrel and t_rcvrel return a value of 0 upon successful completion. Otherwise, they return a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
When you are finished using an endpoint, you deinitialize it by unbinding and closing the endpoint with the t_unbind and t_close functions. Note that the steps described here for deinitializing an endpoint with connection-oriented service are identical to those for connectionless service.
When you unbind the endpoint, you disable the endpoint so that the transport provider no longer accepts requests for it. The syntax for t_unbind is as follows:
t_unbind (fd) ;
In the preceding statement:
See t_unbind(3) for more information.
By closing the endpoint, you inform the transport provider that you are finished with it and you free any library resources associated with the endpoint.
You should call t_close when the endpoint is in the T_UNBND state. However, this function does not check state information, so it may be called to close a transport endpoint from any state.
If you close an endpoint that is not in the T_UNBND state, the library resources associated with the endpoint are freed automatically, and the file associated with the endpoint is closed. If there are no other descriptors in this or any other process that references the endpoint, the transport connection is broken.
To close the endpoint, issue the t_close function. The syntax for t_close is as follows:
t_close (fd) ;
In the preceding statement:
See t_close(3) for more information.
Both t_unbind and t_close return a value of 0 upon successful completion. Otherwise, they return a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
This section describes the steps required to write a connectionless mode application:
Initializing an endpoint for connection-oriented and connectionless applications is the same. See Section 3.3.3.1 for information on how to initialize an endpoint for a CLTS application.
The data transfer phase of connectionless service consists of the following:
Note that connectionless service:
The t_sndudata function can execute synchronously or asynchronously. When executing synchronously, t_sndudata returns control to the user when the transport provider can accept another datagram. In some cases, the function blocks for some time until this occurs. In asynchronous mode, the transport provider refuses to send a new datagram if flow control restrictions exist. The t_sndudata function returns an error of TFLOW, and you must either try again later or issue the t_look function to see when the flow control restriction is lifted, which is indicated by the T_GODATA or T_GOEXDATA events.
If you attempt to send a data unit before you activate the endpoint with the t_bind function, the transport provider discards the data.
To send a data unit, issue the t_sndudata function with the following syntax:
t_sndudata (fd,unitdata) ;
In the preceding statement:
See t_sndudata(3) for more information.
The t_sndudata function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
When you call the t_rcvudata function and data is available, t_rcvudata returns immediately indicating the number of octets received. If data is not available, t_rcvudata behaves differently depending on the mode of execution, as follows:
The t_rcvudata function blocks until either a datagram, error, or signal is received. As an alternative to waiting for t_rcvudata to return, you can issue the t_look function periodically for the T_GODATA event, and then issue t_rcvudata to receive the data.
The t_rcvudata function returns immediately with an error. You then must either retry the function periodically or poll for incoming data with the t_look function.
To receive data, issue the t_rcvudata function with the following syntax:
t_rcvudata (fd,unitdata,flags) ;
In the preceding statement:
See t_rcvudata(3) for more information.
The t_rcvudata function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
If you issue the t_look function and receive the T_UDERR event, previously sent data has generated an error. To clear the error and consume the T_UDERR event, you should issue the t_rcvuderr function. This function also returns information about the data that caused the error and the nature of the error, if you want.
To receive an error indication with information about data, issue the t_rcvuderr function with the following syntax:
t_rcvuderr (fd,uderr) ;
In the preceding statement:
See t_rcvuderr(3) for more information.
The t_rcvuderr function returns a value of 0 upon successful completion. Otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
Deinitializing an endpoint for connection-oriented and connectionless applications is the same. See Section 3.3.3.6 for information on how to deinitialize an endpoint for a connectionless application.
XTI provides a number of functions that can be issued during any phase of connection-oriented or connectionless service (except the uninitialized state) and do not affect the state of the interface. Table 3-13 lists and briefly describes these functions.
Function | Description |
t_getinfo | Returns information about the characteristics of the transport provider associated with the endpoint. |
t_getprotaddr |
Returns the protocol address. |
t_getstate | Returns the current state of the endpoint. |
t_strerror |
Produces an error message string. |
t_sync | Synchronizes the data structures managed by the transport library with information from the transport provider. |
t_alloc | Allocates storage for a specified data structure. |
t_free | Frees storage for a data structure that was previously allocated by t_alloc. |
t_error | Prints a message describing the last error returned by an XTI function. (Optional) |
t_look | Returns the current event associated with the endpoint. |
Table notes:
The t_getinfo and t_getstate functions can be useful for retrieving important information. The t_getinfo function returns the same information about the transport provider as t_open. It offers the advantage that you can call it during any phase of communication, whereas you can call t_open only during the initialization phase. If a function returns the TOUTSTATE error to indicate that the endpoint is not in the proper state, you can issue t_getstate to retrieve the current state and take action appropriate for the state.
The t_sync function can do the following:
The t_alloc and t_free functions are convenient for allocating and freeing memory because you specify the names of the XTI structures rather than information about their size. If you use t_alloc and t_free to manage the memory for XTI structures, and the structures change in future releases, you will not need to change your program.
With t_error you can print a user-supplied message (explanation) plus the contents of t_errno to standard output.
Finally, t_look is an important function for retrieving the current outstanding event associated with the endpoint. Typically, if an XTI function returns TLOOK as an error to indicate a significant asynchronous event has occurred, the transport user follows by issuing the t_look function to retrieve the event. For more information about events, see Section 3.2.3.
This section provides the following:
XTI was designed to provide an interface that is independent of the specific transport protocol used. You can write applications that can modify their behavior according to any subset of the XTI functions and facilities supported by each of the underlying transport providers.
Providers do not have to provide all the features of all the XTI functions. Therefore, Application programmers should follow these guidelines when writing XTI applications:
If your application uses features that are not provided by all transport providers, it may not be able to use them with some transport providers or some XTI implementations.
For example, the orderly release facility (the t_sndrel and t_rcvrel functions) is not supported by all connection-based transport protocols; in particular it is not supported by ISO protocols. If your application runs in an environment with multiple protocols, make sure it does not use the orderly release facility.
As an alternative to using only the commonly supported features, write your application so that it modifies its behavior according to the subset of XTI functions supported by each transport provider.
Some transport providers, such as TCP, do not support the concept of a TSDU, so they ignore the T_MORE flag when used with the t_snd, t_sndudata, t_rcv, and t_rcvudata functions.
Make sure your application retrieves these limits before transferring data and adheres to the limits throughout the communication process.
Although the t_optmgmt function allows an application to access the default protocol options from the transport provider and pass them as an argument to the connection-establishment function, make sure your application avoids examining the options or relying on the existence of certain ones.
These codes depend on the underlying protocol so, to achieve protocol independence, make sure your application does not attempt to interpret the codes.
If you perform other operations, the results can vary from system to system.
The following sections explain how to port applications from different transport-level programming interfaces to XTI. Specifically, they discuss how to port from the two most common transport-level programming interfaces: Transport Layer Interface (TLI), which many UNIX System V applications use, and the 4.3BSD socket interface, which many Berkeley UNIX applications use.
The information presented in the following sections presumes that you are experienced at programming with TLI or sockets and that you understand fundamental XTI concepts and syntax.
This section discusses issues to consider before you recompile your TLI programs and explains how to recompile them. As a long-term solution, Digital recommends that you use the XTI interface instead of the TLI interface. As more applications and transport providers use XTI, you might find it advantageous to do so as well.
XTI and TLI support the same functions, states, and modes of service. Note that Digital UNIX provides shared library support by default when you link an XTI or TLI application with the XTI or TLI library. For more information on shared library support, see Section 3.2.2.
Before you recompile your TLI program, you should consider your program's current implementation of the following event management: The System V UNIX operating system provides the poll function as a tool for managing events. The Digital UNIX implementation of XTI supports the poll function, so if your application uses it, you can recompile. If your program uses a unique mechanism for managing events, you should port that mechanism to Digital UNIX or change to the polling mechanism provided with Digital UNIX.
Because the Digital UNIX implementation of TLI is compatible at the source level with AT&T TLI, you can recompile your TLI program with the Digital UNIX TLI library using the following steps:
#include <tli/tiuser.h>
cc -o name name.c -ltli
If you decide to change your TLI application to an XTI application, be aware of the following minor differences between TLI and XTI.
To make a TLI application a true XTI application, do the following:
#include <xti.h>
cc -o name name.c -lxti
This section explains the differences between the socket interface and XTI. It assumes that your applications use the standard 4.3BSD socket interface and does not account for any extensions or changes you have made to the socket interface. See Appendix B for examples of both sockets and XTI servers and clients.
Because it was designed eventually to replace the socket interface, XTI shares many common functions with the socket interface. However, you should be aware of any differences between it and your current socket interface when rewriting an application for use with XTI.
XTI provides 25 functions. Of the 13 socket functions that map onto corresponding XTI functions, 5 have subtle differences. Table 3-14 lists each XTI function, its corresponding socket function (if one exists), and whether the two functions share common semantics. Generally, socket calls pass parameters by value, while most XTI functions pass pointers to structures containing a combination of input and output parameters.
XTI Function | Socket Function | Shared Semantics |
t_accept | accept | No |
t_alloc | -- | -- |
t_bind | bind | No |
t_close | close | Yes |
t_connect | connect | Yes |
t_error | -- | -- |
t_free | -- | -- |
t_getinfo | -- | -- |
t_getstate | -- | -- |
t_listen | listen, accept |
Yes |
t_look | select | No |
t_open | socket | Yes |
t_optmgmt | setsockopt, getsockopt | No |
t_rcv | recv | Yes |
t_rcvconnect | -- | -- |
t_rcvdis | -- | -- |
t_rcvrel | -- | -- |
t_rcvudata | recvfrom | Yes |
t_rcvuderr | -- | -- |
t_snd | send | Yes |
t_snddis | shutdown | No |
t_sndrel | -- | -- |
t_sndudata | sendto | Yes |
t_sync | -- | -- |
t_unbind | -- | -- |
Table notes:
The XTI functions that do not share all semantics with their socket counterparts have the following differences:
XTI and sockets both use a series of states to control the appropriate sequence of calls, but each uses a different set of states. XTI states and socket states do not share similar semantics. For example, XTI states are mutually exclusive; socket states are not.
Few error messages are common among sockets and XTI. Table 3-15 lists the socket error messages that have comparable XTI error messages.
Socket Error | XTI Error | Description |
EBADF | TBADF | You specified an invalid file descriptor. |
EOPNOTSUPP | TNOTSUPPORT | You issued a function the underlying transport provider does not support. |
EADDRINUSE | TADDRBUSY | You specified an address that is already in use. |
EACCES | TACCES | You do not have permission to use the specified address. |
Note
XTI and TLI are implemented using STREAMS. You should use the poll function instead of the select call on any STREAMS file descriptors.
This section provides information on the differences between the XPG3 and XPG4 implementation of XTI.
In earlier versions of Digital UNIX, the XTI implementation conformed to X/Open's XPG3 specification. The current implementation conforms to SPEC1170's XTI (part of Networking Services' specification) as well as X/Open's XPG4 specification for XTI.
There are some changes in the specification of which you, as a programmer, should be aware. This section outlines these differences and the related programming issues.
Note that the implementation of Digital UNIX converges both XPG3 and XPG4 versions of XTI in a single subset. This section also provides details about the usage of the appropriate level of functionality.
In this manual, the terms SPEC1170 or SPEC1170 XTI are used to refer to the implementation of XTI available in this version of Digital UNIX. The terms XPG3 XTI refer to the implementation of XTI that conforms to X/Open's XPG3 specification. Note that the latter can be available in the current versions of Digital UNIX due to binary compatibility or source migration features.
Most of the changes between the two specifications are upwardly compatible, with the exception of the t_optmgmt function.
The following is a quick summary of the basic changes in the XTI from XPG3 to SPEC1170:
The changes to the t_optmgmt function are extensive and incompatible with the XPG3 specification. In general, an application that uses the XPG3 implementation of the t_optmgmt function cannot use the t_optmgmt function on a system running the XPG4 specification, without making some modifications to the source.
If you have an application that was developed for XPG3 XTI, you have the following choices to support it under Digital UNIX:
Which option you choose will depend on your situation. The following sections describe these conditions in details.
This choice is appropriate if the sources and features of your application are not going to change. It is useful to provide continued coverage by ensuring that older releases of your products are still functional.
This situation arises from minor changes due to correcting minor problems. Therefore, there are no changes to the structure or features or the application. In this case, you might want to compile the sources in the same manner as XPG3 development environment. In that case, compile your source code with the -DXPG3 compiler switch. This ensures that the headers automatically define the older features for you.
If you need to use the new features supported by SPEC1170 XTI, you will have to make changes in your source code. You cannot combine the features from the XPG3 and SPEC1170 XTI. Therefore, if you have large applications consisting of multiple files, you will need to recompile all files with the new features, rather than just the few you might have changed.
You need to compile your source code with the
-DXOPEN_SOURCE
compiler switch. Additionally, you must ensure that the names of the
transport protocols (as provided through the streams device special files as in
/dev/streams/xtiso/tcp)
are updated to reflect the naming convention used
in SPEC1170 XTI. For example, the names
for TCP and UDP are
/dev/streams/xtiso/tcp+
and
/dev/streams/xtiso/udp+.
Check the reference manual
for the names for the other protocols.
Application binaries developed with XPG3 XTI will run on systems running the current version of Digital UNIX. However, there are certain conditions of which you should be aware.
Under unusual circumstances, the errors in XPG3 programs may have been masked due to the way in which the programs or libraries were compiled and linked. It is feasible that the new implementation is able to flag such conditions as errors. Since the error manifested is a programming error in the application, you will have to correct it. The common programming errors that may cause these errors are pointer overruns and uninitialized variables.
Another issue to consider is the availability of SPEC1170 features through STREAMS special files. This is significant if your application accepts command line input for the specifying transport protocol or imports the protocol names from some configuration files. Since the system configured with XTI will have the file names for SPEC1170-compliant protocols as well, it is important to warn users and administrators that those special names should not be used with applications running with binary-compatibility mode. The results of such an action are undefined.
If you are planning to run an old applications without recompiling them, check them for binary compatibility to avoid these problems.
Systems running the current version of Digital UNIX and configured to run XTI support both XPG3 and SPEC1170-compliant functionality. You cannot run the XPG3 and SPEC1170 functionality separately. Therefore, you only need to ensure that XTI subsystem is configured.
You can use the XPG3 and SPEC1170 versions of XTI on the same network. If you are using compatible versions of your application, then the operation should be transparent to users.
It is possible to of convert your application in simple steps, so that you have some pieces that are XPG3 XTI compatible and some pieces that are SPEC1170 compatible. The only thing you have to ensure is that application-level protocol remains the same. Apart from that there will be no issue for interoperability of these components. Therefore, if you have client and server components of an application, you can choose to upgrade the server component for SPEC1170 compliance, while the client component is still operational in binary compatibility mode. Later on, once the server functionality is updated satisfactorily, you can choose to update the client software.
This section provides information on using XTI options in XPG4 and XPG3.
This section provides the following information on using XTI options:
The following functions contain an opt argument of the type struct netbuf as an input or output parameter. This argument is used to convey options between the transport user and the transport provider:
There is no general definition about the possible contents of options. There are general XTI options and those that are specific for each transport provider. Some options allow you to tailor your communication needs; for instance, by asking for high throughput or low delay. Others allow the fine-tuning of the protocol behavior so that communication with unusual characteristics can be handled more effectively. Other options are for debugging purposes.
All options have default values. Their values have meaning to and are defined by the protocol level in which they apply. However, their values can be negotiated by a transport user. This includes the simple case where the transport user can enforce its use. Often, the transport provider or even the remote transport user can have the right to negotiate a value of lesser quality than the proposed one, that is, a delay can become longer, or a throughput may become lower.
It is useful to differentiate between options that are association-related and those that are not. (Association-related means a pair of communication transport users.) Association-related options are intimately related to the particular transport connection or datagram transmission. If the calling user specifies such an option, some ancillary information is transferred across the network in most cases. The interpretation and further processing of this information is protocol-dependent. For instance, in an ISO connection-oriented communication, the calling user can specify quality-of-service parameters on connection establishment. These are first processed and possibly lowered by the local transport provider, then sent to the remote transport provider that may degrade them again, and finally conveyed to the called user that makes the final selection and transmits the selected values back to the caller.
Options that are not association-related do not contain information destined for the remote transport user. Some have purely local relevance; for example, an option that enables debugging. Others influence the transmission; for instance, the option that sets the IP time-to-live field or TCP_NODELAY. (See the xti_internet(7) reference page.) Local options are negotiated solely between the transport user and the local transport provider. The distinction between these two categories of options is visible in XTI through the following relationship: on output, the t_listen and t_rcvudata functions return association-related options only. The t_rcvconnect and t_rcvuderr functions may return options of both categories. On input, options of both categories may be specified with the t_accept and t_sndudata functions. The t_connect and t_optmgmt functions can process and return both categories of options.
The transport provider has a default value for each option it supports. These defaults are sufficient for the majority of communication relations. Therefore, a transport user should only request options actually needed to perform the task and leave all others at their default value.
This section describes the general framework for the use of options. This framework is obligatory for transport providers. The t_optmgmt reference page provides information on general XTI options. The xti_internet reference page provides information on the specific options that are legal with the TCP and UDP transport providers.
Options are conveyed through an opt argument of struct netbuf. Each option in the buffer specified is of the form struct t_opthdr possibly followed by an option value.
A transport provider embodies a stack of protocols. The level field of struct t_opthdr identifies the XTI level or a protocol of the transport provider as TCP or ISO 8073:1986. The name field identifies the option within the level and the len field contains the total length; that is the length of the option header t_ophdr plus the length of the option value. The status field is used by the XTI level or the transport provider to indicate success or failure of a negotiation.
Several options can be concatenated; however, The transport user has to ensure that each option starts at a long-word boundary. The macro OPT_NEXTHDR(pbuf,buflen,poptons) can be used for that purpose. The parameter pbuf denotes a pointer to an option buffer opt.buf and buflen is its length. The parameter poption points to the current options in the option buffer. OPT_NEXTHDR returns a pointer to the position of the next option or returns a null pointer if the option buffer is exhausted. The macro is helpful for writing and reading the option list.
This section describes the general rules governing the passing and retrieving of options and the error conditions that can occur. Unless explicitly restricted, these rules apply to all functions that allow the exchange of options.
When multiple options are specified in an option buffer on input, different rules apply to the levels that may be specified, depending on the function call. Multiple options specified on input to t_optmgmt must address the same option level. Options specified on input to t_connect, t_accept, and t_sndudata can address different levels.
Only legal options can be negotiated; illegal options can cause failure. An option is illegal if the following applies:
If and illegal option is passed to XTI, the following will happen:
If the transport user passes multiple options in one call and one of them is illegal, the call fails as described previously. It is, however, possible that some or even all of the submitted legal options were successfully negotiated. The transport user can check the current status by a call to the t_optmgmt function with the T_CURRENT flag set. See the t_optmgmt(3) and xti_internet(7) reference pages.
Specifying an option level unknown to or not supported by the protocol selected by the option level does not cause failure. The option is discarded in calls to the t_connect, t_accept, or t_sndudata functions. The t_opmgmt function returns T_NOTSULPORT in the level field of the option.
A transport user initiates an option negotiation when calling the t_connect, t_sndudata, or t_optmgmt functions with the T_NEGOTIATE flag set.
The negotiation rules for these functions depend on whether an option request is an absolute requirement. This is explicitly defined for each option. See the t_optmgmt(3) and xti_internet(7) reference pages. In the case of an ISO transport provider, for example, the option that requests use of expedited data is not an absolute requirement. On the other hand, the option that requests protection could be an absolute requirement.
Note
The term absolute requirement originates from the quality-of-service parameters in the ISO 8072:1986 specification. Its use is extended here to all options.
If the proposed option value is an absolute requirement, there are three possible outcomes:
If multiple options are submitted in one call and one of them is rejected, XTI behaves as just described. Although the connection establishment or the datagram transmission fails, options successfully negotiated before some option was rejected retain their negotiated values. There is no roll-back mechanism. See the Option Management of a Transport Endpoint section for more information.
The t_optmgmt function attempts to negotiate each option. The status fields of the returned options indicate success (T_SUCCESS) or failure (T_FAILURE).
If the proposed option value is not an absolute requirement, the following outcomes are possible:
When the result of the negotiation is retrieved, the status field in t_opthdr is set to T_SUCCESS if the negotiated value equals the proposed one; otherwise, it is set to T_PARTSUCCESS.
Unsupported options do not cause functions to fail or a connection to abort, since different vendors possibly implement different subsets of options. Furthermore, future enhancements of XTI might encompass additional options that are unknown to earlier implementations of transport providers. The decision whether or not the missing support of an option is acceptable for the communication is left to the transport user.
The transport provider does not check for multiple occurrences of the same options, possibly with different option values. It simply processes the options in the option buffer sequentially. However, the user should not make any assumption about the order of processing.
Not all options are independent of one another. A requested option value might conflict with the value of another option that was specified in the same call or is currently effective. See the Option Management of a Transport Endpoint section for more information. These conflicts may not be detected at once, but they might later lead to unpredictable results. If detected at negotiation time, these conflicts are resolved within the rules stated above. The outcomes may thus be quite different and depend on whether absolute or nonabsolute requests are involved in the conflict.
Conflicts are usually detected at the time a connection is established or a datagram is sent. If options are negotiated with the t_optmgmt function, conflicts are usually not detected at this time, since independent processing of the requested options must allow for temporal inconsistencies.
When called, the t_connect, and t_sndudata functions initiate a negotiation of all association-related options according to the rules of this section. Options not explicitly specified in the function calls themselves are taken from an internal option buffer that contains the values of a previous negotiation. See the Option Management of a Transport Endpoint section for more information.
In connection-oriented communication, some protocols give the peer transport users the opportunity to negotiate characteristics of the transport connection to be established. These characteristics are association-related options. With the connect indication, the called user receives (through the t_listen function) a proposal about the option values that should be effective for this connection. The called user can accept this proposal or weaken it by choosing values of lower quality; for example, longer delays than proposed. The called user can, of course, refuse the connection establishment altogether.
The called user responds to a negotiation proposal using the t_accept function. If the called transport user tries to negotiate an option of higher quality than proposed, the outcome depends on the protocol to which that option applies. Some protocols may reject the option, some protocols take other appropriate action described in protocol-specific reference pages. If an option is rejected, the following error occurs:
The connection fails; a T_DISCONNECT event occurs. In that case, whether a t_accept function can still succeed or fail with a TLOOK error depends on timing and implementation conditions.
If multiple options are submitted with the t_accept function and one of them is rejected, the connection fails as described previously. Options that could be successfully negotiated before the erroneous option was processed retain their negotiated value. There is no rollback mechanism. See the Option Management of a Transport Endpoint section for more information.
The response options can either be specified with the t_accept call or can be preset for the responding endpoint (not the listening endpoint) resfd in a t_optmgmt call (action T_NEGOTIATE) prior to the t_accept call. (See the Option Management of a Transport Endpoint section for more information.) Note that the response to a negotiation proposal is activated when the t_accept function is called. A t_optmgmt function call with erroneous option values as described previously will succeed; the connection aborts at the time the t_accept function is called.
The connection also fails if the selected option values lead to contradictions.
The t_accept function does not check for multiple specification of an option. (See the Initiating an Option Negotiation section.) Unsupported options are ignored.
This section describes how a transport user can retrieve information about options.
A transport user must be able to:
To this end, the following function take an output argument opt of the struct netbuf:
The transport user has to supply a buffer to which the options will be written; the opt.buf parameter must point to this buffer and the opt.maxlen parameter must contain the buffer's size. The transport user can set the opt.maxlen parameter to zero to indicate that no options are to be retrieved.
Which options are returned depend on the function call involved:
The functions return the values of all association-related options that were received with the connection response and the negotiated values of those nonassociation-related options that had been specified on input. However, options specified on input in the t_connect call that are not supported or refer to an unknown option level are discarded and not returned on output.
The status field of each option returned with the t_connect or t_rcvconnect function indicates if the proposed value (T_SUCCESS) or a degraded value (T_PARTSUCCESS) has been negotiated. The status field of received ancillary information (for example, IP options) that is not subject to negotiation is always set to T_SUCCESS.
The received association-related options are related to the incoming connection (identified by the sequence number), not to the listening endpoint. (However, the option values currently in effect for the listening endpoint can affect the values retrieved by the t_listen function, since the transport provider might also be involved in the negotiation process.) Therefore, if the same options are specified in a call to the t_optmgmt function with action T_CURRENT, they will usually not return the same values.
The number of received options may vary for subsequent connect
indications, since many association-related options are only transmitted on
explicit demand by the calling user; for example, IP options or ISO
8072:1986 throughput. It is even possible that no options at all are
returned.
The status field is irrelevant.
The received association-related options are related to the incoming datagram, not to the transport endpoint fd. Therefore, if the same options are specified in a call to the t_optmgmt function with action T_CURRENT, the t_optmgmt function will usually not return the same values.
The number of options received may vary from call to call.
The status field is irrelevant.
The returned options are related to the options input of the previous
t_sndudata
call that produced the error. Which options are
returned
and which values they have depend on the specific error
condition. The
status
field is irrelevant.
This call can process and return both categories of options. It acts on options related to the specified transport endpoint, not on options related to a connect indication or an incoming datagram. For more information, see the t_optmgmt(3) reference page.
Only privileged users can request privileged options, or option values. The meaning of privilege is hereby implementation-defined.
Read-only options serve for information purposes only. The transport user may be allowed to read the option value but not to change it. For instance, to select the value of a protocol timer or the maximum length of a protocol data unit may be too subtle to leave to the transport user, though the knowledge about this value might be of some interest. An option might be read-only for all users or solely for nonprivileged users. A privileged option might be inaccessible or read-only for nonprivileged users.
An option might be negotiable in some XTI states and read-only in other XTI states. For instance, the ISO quality-of-service options are negotiable in the T_IDLE and T_INCON states, and read-only in all other states (except T_UNINIT).
If a transport user requests negotiation of a read-only option, or a nonprivileged user requests illegal access to a privileged option, the following outcomes are possible:
If multiple options are submitted to the t_connect, t_accept, or t_sndudata functions and a read-only option is rejected, the connection or the datagram transmission fails as described. Options that could be successfully negotiated before the erroneous option was processed retain their negotiated values. There is no rollback mechanism. See the Option Management of a Transport Endpoint section for more information.
This section describes how option management works during the lifetime of a transport endpoint.
Each transport endpoint is (logically) associated with an internal option buffer. When a transport endpoint is created, this buffer is filled with a system default value for each supported option. Depending on the option, the default may be OPTION ENABLED, OPTION DISABLED, or denote a time span, and so on. These default settings are appropriate for most uses. Whenever an option value is modified in the course of an option negotiation, the modified value is written to this buffer and overwrites the previous one. At any time, the buffer contains all option values that are currently effective for this transport endpoint.
The current value of an option can be retrieved at any time by calling the t_optmgmt function with the T_CURRENT flag set. Calling the t_optmgmt function with the T_DEFAULT flag set yields the system default for the specified option.
A transport user can negotiate new option values by calling the t_optmgmt function with the T_NEGOTIATE flag set. The negotiation follows the rules described in the Elements of Negotiation section.
Some options may be modified only in specific XTI states and are read-only in other XTI states. Many association-related options, for instance, may not be changed in the T_DATAXFER state, and an attempt to do so fails; see the Privileged and Read-Only Options section. The legal states for each option are specified with its definition.
As usual, association-related options take effect at the time a connection is established or a datagram is transmitted. This is the case if they contain information that is transmitted across the network or determine specific transmission characteristics. If such an option is modified by a call to the t_optmgmt function, the transport provider checks whether the option is supported and negotiates a value according to its current knowledge. This value is written to the internal option buffer.
The final negotiation takes place if the connection is established or the datagram is transmitted. This can result in a degradation of the option value or even in a negotiation failure. The negotiated values are written to the internal option buffer.
Some options can be change in the T_DATAXFER state; for example, those specifying buffer sizes. Such changes might affect the transmission characteristics and lead to unexpected side effects; for example, data loss if a buffer size was shortened.
The transport user can explicitly specify both categories of options on input when calling the t_connect, t_accept, or t_sndudata functions. The options are at first locally negotiated option by option and the resulting values written to the internal option buffer. The modified option buffer is then used if a further negotiation step across the network is required; for example, in connection-oriented ISO communication. The newly negotiated values are then written to the internal option buffer.
At any stage, a negotiation failure can cause the transmission to abort. If a transmission aborts, the option buffer preserves the content it had at the time the failure occurred. Options that could be negotiated before the error occurred are written back to the option buffer, whether the XTI call fails or succeeds.
It is up to the transport user to decide which option it explicitly specifies on input when calling the t_connect, t_accept, or t_sndudata functions. The transport user need not pass options at all by setting the len field of the function's input opt argument to zero (0). The current content of the internal option buffer is then used for negotiation without prior modification.
The negotiation procedure for options at the time of a t_connect, t_accept, or t_sndudata call always obeys the rules in the Initiating an Option Negotiation section whether the options were explicitly specified during the call or implicitly taken from the internal option buffer.
The transport user should not make assumptions about the order in which options are processed during negotiation.
A value in the option buffer is only modified as a result of a successful negotiation of this option. It is, in particular, not changed by a connection release. There is no history mechanism that would restore the buffer state existing prior to the connection establishment of the datagram transmission. The transport user must be aware that a connection establishment or a datagram transmission may change the internal option buffer, even if each option was originally initialized to its default value.
Some options may not always have a fully specified value. An ISO transport provider, for instance, that supports several protocol classes might not have a preselected preferred class before a connection establishment is initiated. At the time of the connection request, the transport provider may conclude from the destination address, quality-of-service parameters, and other locally available information which preferred class it should use. A transport user asking for the default value of the preferred class option in the T_IDLE state would get the value T_UNSPEC. This value indicates that the transport provider did not yet select a value. The transport user could negotiate another value as the preferred class; for example, T_CLASS2. The transport provider would then be forced to initiate a connect request with class 2 as the preferred class.
An XTI implementation may also return the T_UNSPEC value if it currently cannot access the option value. This can happen in the T_UNBND state in systems where the protocol stacks reside on separate controller cards and not in the host. The implementation may never return T_UNSPEC if the option is not supported at all.
If T_UNSPEC is a legal value for a specific option, it can be used on input, as well. It is used to indicate that it is left to the provider to choose an appropriate value. This is especially useful in complex options as ISO throughput, where the option value has an internal structure. The transport user can leave some fields unspecified by selecting this value. If the user proposes T_UNSPEC, the transport provider is free to select an appropriate value. This might be the default value, some other explicit value, or T_UNSPEC.
For each option, it is specified whether T_UNSPEC is a legal value for negotiation purposes.
The t_open and t_getinfo functions return values representing characteristics of the transport provider in the info argument. The value of info->options is used by the t_alloc function to allocate storage for an option buffer to be used in an XTI call. The value is sufficient for all uses.
In general, info->options also includes the size of privileged options; even if these are not read-only for nonprivileged users. Alternatively, an implementation can choose to return different values in info->options for privileged and nonprivileged users.
The values in
info->etsdu,
info->connect,
and
info->discon
possibly diminish as soon as the T_DATAXFER state is entered. Calling the
t_optmgmt
function does not influence these values. For more information, see the
t_optmgmt(3)
reference page.
An application programmer who writes XTI programs has the following portability issues across the following:
Options are intrinsically coupled with a definite protocol or protocol profile. Therefore, explicit use of options degrades portability across protocol profiles.
Different vendors might offer transport providers different option support. This is due to different implementation and product policies. The lists of options on the t_optmgmt(3) reference page and in the protocol-specific reference pages are maximal sets, but do not necessarily reflect common implementation practice. Vendors implement subsets that suit their needs. Therefore, making careless use of options endangers portability across different system platforms.
Every implementation of a protocol profile accessible by XTI can be used with the default values of options. Applications can thus be written that do not care about options at all.
An application program that processes options retrieved from an XTI function should discard options it does not know to lessen its dependence from different system platforms and future XTI releases with possibly increased option support.
The Digital UNIX XPG3 implementation of XTI provides an optional function, t_optmgmt, for retrieving, verifying, and negotiating protocol options with transport providers. After you create an endpoint with t_open and bind an address to it, you can verify or negotiate options with the transport provider. To do so, issue the t_optmgmt function, with the following syntax:
t_optmgmt (fd,req,ret) ;
In the preceding statement:
Both the req and ret arguments point to a t_optmgmt structure.
Note
Although other transport providers may support the t_optmgmt function, the Digital UNIX TCP transport provider does not. See the transport provider documentation for information about option management.
See t_optmgmt(3) for more information.
The t_optmgmt function returns a value of 0 upon successful completion; otherwise, it returns a value of -1, and t_errno is set to one of the values described in Section 3.7. (For multithreaded applications, t_errno is thread specific.)
XTI returns library errors and system errors. When an XTI function encounters an error, it returns a value of -1, and can do one of the following:
Note
Since a successful call to an XTI function does not clear the contents of t_errno, check t_errno only after an error occurs.
The
<xti.h>
header file defines the
t_errno
variable as a macro as follows:
#define t_errno(*_t_errno())
For more information on errors, see the individual XTI reference pages.
Use the xtiso kernel configuration option to configure XTI transport providers. You can configure the xtiso option into your system at installation time or you can add it to your system using the doconfig command. See the Installation Guide.
You can use the doconfig command in one of the following ways:
To use the doconfig command without any options, do the following:
Enter a name for the kernel configuration file. [HOST1]:
[RETURN]
A configuration file with the name 'HOST1' already exists.
Do you want to replace it? (y/n) [n]:
y
Saving /sys/conf/HOST1 as /sys/conf/HOST1.bck
*** KERNEL CONFIGURATION AND BUILD PROCEDURE ***
*** KERNEL OPTION SELECTION ***Enter the selection number for each kernel option you want.
Selection Kernel Option -------------------------------------------------------------- 1 System V Devices 2 NTP V3 Kernel Phase Lock Loop (NTP_TIME) 3 Kernel Breakpoint Debugger (KDEBUG) 4 Packetfilter driver (PACKETFILTER) 5 Point-to-Point Protocol (PPP) 6 STREAMS pckt module (PCKT) 7 X/Open Transport Interface (XTISO, TIMOD, TIRDWR) 8 File on File File System (FFM) 9 ISO 9660 Compact Disc File System (CDFS) 10 Audit Subsystem 11 ACL Subsystem 12 Logical Storage Manager (LSM) 13 Advanced File System (ADVFS) 14 All of the above 15 None of the above 16 Help --------------------------------------------------------------
Enter the selection number for each kernel option you want. For example, 1 3 [15]: 7
When you reboot, the strsetup -i command runs automatically, creating the device special files for any new STREAMS modules.
The following example shows the output from the strsetup -c command:
#
/usr/sbin/strsetup -c
STREAMS Configuration Information...Fri Nov 3 14:23:36 1995
Name Type Major Module ID ---- ---- ----- --------- clone 32 0 dlb device 52 5010 kinfo device 53 5020 log device 54 44 nuls device 55 5001 echo device 56 5000 sad device 57 45 pipe device 58 5304 xtisoUDP device 59 5010 xtisoTCP device 60 5010 xtisoUDP+ device 61 5010 xtisoTCP+ device 62 5010 ptm device 63 7609 pts device 6 7608 bba device 64 24880 lat device 5 5 pppif module 6002 pppasync module 6000 pppcomp module 6001 bufcall module 0 null module 5002 pass module 5003 errm module 5003 ptem module 5003 spass module 5007 rspass module 5008 pipemod module 5303 timod module 5006 tirdwr module 0 ldtty module 7701
Configured devices = 15, modules = 14
To use the doconfig -c command to add the XTISO option to the kernel configuration file, do the following:
#
doconfig -c HOST1
*** KERNEL CONFIGURATION AND BUILD PROCEDURE ***
Saving /sys/conf/HOST1 as /sys/conf/HOST1.bck
Do you want to edit the configuration file? (y/n) [n]:
y
Using ed to edit the configuration file. Press return when ready,
or type 'quit' to skip the editing session:
2153
48a
options XTISO
\.
1,$w
2185
q
*** PERFORMING KERNEL BUILD ***
When you reboot, the strsetup -i command is run automatically, creating the device special files for any new STREAMS modules.
The following example shows the output from the
strsetup -c
command:
#
/usr/sbin/strsetup -c
STREAMS Configuration Information...Fri Nov 3 14:23:36 1995
Name Type Major Module ID ---- ---- ----- --------- clone 32 0 dlb device 52 5010 kinfo device 53 5020 log device 54 44 nuls device 55 5001 echo device 56 5000 sad device 57 45 pipe device 58 5304 xtisoUDP device 59 5010 xtisoTCP device 60 5010 xtisoUDP+ device 61 5010 xtisoTCP+ device 62 5010 ptm device 63 7609 pts device 6 7608 bba device 64 24880 lat device 5 5 pppif module 6002 pppasync module 6000 pppcomp module 6001 bufcall module 0 null module 5002 pass module 5003 errm module 5003 ptem module 5003 spass module 5007 rspass module 5008 pipemod module 5303 timod module 5006 tirdwr module 0 ldtty module 7701
Configured devices = 15, modules = 14
For detailed information on reconfiguring your kernel or the doconfig command see the System Administration manual.