|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 50792 (0xc668) Types: TextFile Names: »tsap.tex«
└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« └─⟦d3ac74d73⟧ └─⟦this⟧ »isode-5.0/doc/manual/tsap.tex«
% run this through LaTeX with the appropriate wrapper \f \chapter {Transport Services}\label{libtsap} At the heart of this distribution is the \man libtsap(3n) library. This library contains a set of routines which implement the transport services access point (TSAP). As with most models of OSI services, the underlying assumption is one of a symmetric, asynchronous environment. That is, although peers exist at a given layer, one does not necessarily view a peer as either a client or a server. Further, the service provider may generate events for the service user without the latter entity triggering the actions which led to the event. For example, in a synchronous environment, an indication that data has arrived usually occurs only when the service user asks the service provider to read data; in an asynchronous environment, the service provider may interrupt the service user at any time to announce the arrival of data. The \verb"tsap" module in this release initially uses a client/server paradigm to start communications. Once the connection is established, a symmetric view is taken. In addition, initially the interface is synchronous; however once the connection is established, an asynchronous interface may be selected. All of the routines in the \man libtsap(3n) library are integer-valued. They return the manifest constant \verb"OK" on success, or \verb"NOTOK" otherwise. \f \section {Addresses}\label{tsap:addresses} Addresses at the transport service access point are represented by the \verb"TSAPaddr" structure. \begin{quote}\index{TSAPaddr}\small\begin{verbatim} struct TSAPaddr { #define NTADDR 4 struct NSAPaddr ta_addrs[NTADDR]; int ta_naddr; #define TSSIZE 64 int ta_selectlen; char ta_selector[TSSIZE]; }; #define NULLTA ((struct TSAPaddr *) 0) \end{verbatim}\end{quote} This structure contains two elements: \begin{describe} \item[\verb"ta\_addrs"/\verb"ta\_nadr":] a list of network addresses, as described in the Section~\ref{nsap:addresses} on page~\pageref{nsap:addresses}; \item[\verb"ta\_selector"/\verb"ta\_selectlen":] the transport selector, as described in the \man isoservices(5) database in Chapter~\ref{isoservices}, for the service provider \verb"tsap". \end{describe} In Figure~\ref{getSSprovider}, an example of how one constructs the TSAP address for the session provider on host \verb"RemoteHost" is presented. The routine \verb"is2taddr" takes a host and service, and then consults the \man isoentities(5) file described in Chapter~\ref{isoentities} of \volone/ to construct a transport address. \begin{quote}\index{is2taddr}\small\begin{verbatim} struct TSAPaddr *is2taddr (host, service, is) char *host, *service; struct isoservent *is; \end{verbatim}\end{quote} \tagrind[tp]{grind6-1}{Constructing the TSAP address for the Session provider}% {getSSprovider} \subsection {Calling Address} Certain users of the transport service might need to know the name of the local host when they initiate a connection. The routine \verb"TLocalHostName" has been provided for this reason. \begin{quote}\index{TLocalHostName}\small\begin{verbatim} char *TLocalHostName () \end{verbatim}\end{quote} \subsection {Address Encodings} It may be useful to encode a transport address for viewing. Although a consensus for a standard way of doing this has not yet been reached, the routines \verb"taddr2str" and \verb"str2taddr" may be used in the interim. \begin{quote}\index{taddr2str}\small\begin{verbatim} char *taddr2str (ta) struct TSAPaddr *ta; \end{verbatim}\end{quote} The parameter to this procedure is: \begin{describe} \item[\verb"ta":] the transport address. \end{describe} If \verb"taddr2str" fails, it returns the manifest constant \verb"NULLCP". The routine \verb"str2taddr" takes an ascii string encoding and returns a transport address. \begin{quote}\index{str2taddr}\small\begin{verbatim} struct TSAPaddr *str2taddr (str) char *str; \end{verbatim}\end{quote} The parameter to this procedure is: \begin{describe} \item[\verb"str":] the ascii string. \end{describe} If \verb"str2taddr" fails, it returns the manifest constant \verb"NULLTA". \f \section {Connection Establishment} Until the connection has been fully established, the implementation distinguishes between clients and servers, which are more properly referred to as {\em initiators\/} and {\em responders}, to use the OSI terminology. \subsection {Connection Negotiation} From the user's perspective, there are two parameters which are negotiated by the transport providers during connection establishment: {\em expedited data transfer}, and the {\em maximum size\/} of transport service data units. \subsubsection {Expedited Data} If the transfer of expedited data is negotiated, then small amounts of data may be sent out-of-band once the connection has been established. The size of the largest discrete unit to be sent is \verb"TX_SIZE" (which is non-negotiable). This parameter is negotiated downward; that is, both the initiator and responder must agree to the use of expedited data. \subsubsection {Maximum TSDU Size} The transport provider will accept arbitrarily large transport service data units (TSDUs) and transparently fragment and re-assemble them during transit. Hence, the actual TSDU is of unlimited size. However, for efficiency reasons, it may be desirable for the user to send TSDUs which are no larger than a certain threshold. When a connection has been established, the service providers inform the initiator and responder as to what this threshold is. \[\fbox{\begin{tabular}{lp{0.8\textwidth}}\label{TSDU:atomic} \bf NOTE:& In the current implementation, TSDUs which are no larger than the maximum atomic TSDU size are handled very efficiently. For optimal performance, users of the transport service should strive to avoid sending TSDUs which are larger than this threshold. \end{tabular}}\] \subsection {Server Initialization} The \man tsapd(8c) daemon, upon accepting a connection from an initiating host, consults the ISO services database to determine which program on the system implements the desired TSAP entity. For efficiency reasons, the \pgm{tsapd} program contains the bootstrap for several providers (e.g., session). Once the program has been ascertained, the daemon runs the program with any arguments listed in the database. In addition, it appends some {\em magic arguments\/} to the argument vector. Hence, the very first action performed by the responder is to re-capture the TSAP state contained in these magic arguments. This is done by calling the routine \verb"TInit", which on a successful return, is equivalent to a {\sf T-CONNECT.INDICATION\/} event from the transport service provider. \begin{quote}\index{TInit}\small\begin{verbatim} int TInit (vecp, vec, ts, td) int vecp; char **vec; struct TSAPstart *ts; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"vecp":] the length of the argument vector; \item[\verb"vec":] the argument vector; \item[\verb"ts":] a pointer to a \verb"TSAPstart" structure, which is updated only if the call succeeds; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If \verb"TInit" is successful, it returns information in the \verb"ts" parameter, which is a pointer to a \verb"TSAPstart" structure. \begin{quote}\index{TSAPstart}\small\begin{verbatim} struct TSAPstart { int ts_sd; struct TSAPaddr ts_calling; struct TSAPaddr ts_called; int ts_expedited; int ts_tsdusize; struct QOStype ts_qos; #define TS_SIZE 32 int ts_cc; char ts_data[TS_SIZE]; }; \end{verbatim}\end{quote} The elements of this structure are: \begin{describe}\label{TSAPstart} \item[\verb"ts\_sd":] the transport-descriptor to be used to reference this connection; \item[\verb"ts\_calling":] the address of peer initiating the connection; \item[\verb"ts\_called":] the address of the peer being asked to respond; \item[\verb"ts\_expedited":] whether initiator requests the use of expedited data; \item[\verb"ts\_tsdusize":] the largest atomic TSDU size that can be used on the connection (see the note on page~\pageref{TSDU:atomic}); \item[\verb"ts\_qos":] the quality of service on the connection (see Section~\ref{tsap:qos}); and, \item[\verb"ts\_data"/\verb"ts\_cc":] any initial data (and the length of that data). \end{describe} If the call to \verb"TInit" is not successful, then the user is informed that a {\sf T-DISCONNECT.INDICATION\/} event has occurred, and the relevant information is returned in a \verb"TSAPdisconnect" structure. \begin{quote}\index{TSAPdisconnect}\small\begin{verbatim} struct TSAPdisconnect { int td_reason; #define TD_SIZE 64 int td_cc; char td_data[TD_SIZE]; }; \end{verbatim}\end{quote} The elements of this structure are:\label{TSAPdisconnect} \begin{describe} \item[\verb"td\_reason":] reason for disconnect (codes are listed in Table~\ref{TSAPreasons}); and, \item[\verb"td\_data"/\verb"td\_cc":] any disconnect data (and the length of that data) from the peer. \end{describe} \tagtable[tp]{6-1}{TSAP Failure Codes}{TSAPreasons} After examining the information returned by \verb"TInit" on a successful call (and possibly after examining the argument vector), the responder should either accept or reject the connection. If accepting, the \verb"TConnResponse" routine is called (which corresponds to the {\sf T-CONNECT.RESPONSE\/} action). \begin{quote}\index{TConnResponse}\small\begin{verbatim} int TConnResponse (sd, responding, expedited, data, cc, qos, td) int sd; struct TSAPaddr *responding; int expedited, cc; char *data; struct QOStype *qos; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"responding":] the TSAP address of the responder (defaulting to the called address, if not present); \item[\verb"expedited":] whether expedited data is to be permitted (this value must be \verb"0" unless the {\sf T-CONNECT.INDICATION\/} event indicated a willingness on the part of the initiator to support expedited data transfer); \item[\verb"data"/\verb"cc":] any initial data (and the length of that data, which may not exceed \verb"TC_SIZE" octets); \item[\verb"qos":] the quality of service on the connection (see Section~\ref{tsap:qos}); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TConnResponse" is successful, then connection establishment has completed and the users of the transport service now operate as symmetric peers. Otherwise, if the call fails and the reason is not an interface error (see Table~\ref{TSAPreasons} on page~\pageref{TSAPreasons}), then the connection is closed. If instead, the responder wishes to reject the connection, it should fire the {\sf T-DISCONNECT.REQUEST\/} action by calling the \verb"TDiscRequest" routine. \begin{quote}\index{TDiscRequest}\small\begin{verbatim} int TDiscRequest (sd, data, cc, td) int sd; char *data; int cc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe}\label{TDiscRequest} \item[\verb"sd":] the transport-descriptor; \item[\verb"data"/\verb"cc":] any disconnect data (and the length of that data, which may not exceed \verb"TD_SIZE" octets); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} After a return from this call, the responder may exit. \subsection {Client Initialization} A program wishing to connect to another user of transport services calls the \verb"TConnRequest" routine, which corresponds to the {\sf T-CONNECT.REQUEST\/} action. \begin{quote}\index{TConnRequest}\small\begin{verbatim} int TConnRequest (calling, called, expedited, data, cc, qos, tc, td) struct TSAPaddr *calling, *called; int expedited, cc; char *data; struct QOStype *qos; struct TSAPconnect *tc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"calling":] the TSAP address of the initiator; (need not be present); \item[\verb"called":] the TSAP address of the responder; \item[\verb"expedited":] whether expedited data is to be permitted; \item[\verb"data"/\verb"cc":] any initial data (and the length of that data, which may not exceed \verb"TS_SIZE" octets); \item[\verb"qos":] the quality of service on the connection (see Section~\ref{tsap:qos}); \item[\verb"tc":] a pointer to a \verb"TSAPconnect" structure, which is updated only if the call succeeds; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TConnRequest" is successful (a successful return corresponds to a {\sf T-CONNECT.CONFIRMATION} event), then information is returned in the \verb"tc" parameter, which is a pointer to a \verb"TSAPconnect" structure. \begin{quote}\index{TSAPconnect}\small\begin{verbatim} struct TSAPconnect { int tc_sd; struct TSAPaddr tc_responding; int tc_expedited; int tc_tsdusize; struct QOStype tc_qos; #define TC_SIZE 32 int tc_cc; char tc_data[TC_SIZE]; }; \end{verbatim}\end{quote} The elements of this structure are: \begin{describe} \item[\verb"tc\_sd":] the transport-descriptor to be used to reference this connection; \item[\verb"tc\_responding":] the responding peer's address (which is the same as the \verb"called" address given as a parameter to \verb"TConnRequest"); \item[\verb"tc\_expedited":] whether expedited data will be supported; \item[\verb"tc\_tsdusize":] the largest atomic TSDU size that can be used on the connection (see the note on page~\pageref{TSDU:atomic}); \item[\verb"tc\_qos":] the quality of service on the connection (see Section~\ref{tsap:qos}); and, \item[\verb"tc\_data"/\verb"tc\_cc":] any initial data (and the length of that data). \end{describe} If the call to \verb"TConnRequest" is successful, then connection establishment has completed and the users of the transport service now operate as symmetric peers. Otherwise, if the call fails then the connection is not established, and the \verb"TSAPdisconnect" structure has been updated. \subsubsection {Asynchronous Connections}\label{tsap:async} Normally \verb"TConnRequest" returns only after a connection has succeeded or failed. This is termed a {\em synchronous\/} connection initiation. If the user desires, an {\em asynchronous\/} connection may be initiated. The routine \verb"TConnRequest" is really a macro which calls the routine \verb"TAsynConnRequest" with an argument indicating that a connection should be attempted synchronously. \begin{quote}\index{TAsynConnRequest}\small\begin{verbatim} int TAsynConnRequest (calling, called, expedited, data, cc, qos, tc, td, async) struct TSAPaddr *calling, *called; int expedited, cc, async; char *data; struct QOStype *qos; struct TSAPconnect *tc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The additional parameter to this procedure is: \begin{describe} \item[\verb"async":] whether the connection should be initiated asynchronously. \end{describe} If the \verb"async" parameter is non-zero, then \verb"TAsynConnRequest" returns one of three values: \verb"NOTOK", which indicates that the connection request failed; \verb"DONE", which indicates that the connection request succeeded; and, \verb"OK", which indicates that the connection request is still in progress. In the first two cases, the usual procedures for \verb"TConnRequest" are employed (i.e., a \verb"NOTOK" return from \verb"TAsynConnRequest" is equivalent to a \verb"NOTOK" return from \verb"TConnRequest", and, a \verb"DONE" return from \verb"TAsynConnRequest" is equivalent to a \verb"OK" return from \verb"TConnRequest"). In the final case, when \verb"OK" is returned, only the \verb"tc_sd" element of the \verb"tc" parameter has been updated; it reflects the transport-descriptor to be used to reference this connection. Note that the \verb"data" parameter is still being referenced by \man libtsap(3n) and should not be tampered with until the connection attempt has been completed. To determine when the connection attempt has been completed, the routine \verb"xselect" (consult Section~\ref{acs:select} of \volone/) should be used after calling \verb"TSelectMask". In order to determine if the connection attempt was successful, the routine \verb"TAsynRetryRequest" is called: \begin{quote}\index{TAsynRetryRequest}\small\begin{verbatim} int TAsynRetryRequest (sd, tc, td) int sd; struct TSAPconnect *tc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"tc":] a pointer to a \verb"TSAPconnect" structure, which is updated only if the call succeeds; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} Again, one of three values are returned: \verb"NOTOK", which indicates that the connection request failed; \verb"DONE", which indicates that the connection request succeeded; and, \verb"OK", which indicates that the connection request is still in progress. In order to make efficient use of the asychronous connection facility, it is necessary to understand a bit of its underlying mechanisms. From a temporal perspective, connection establishment consists of two parts: \begin{enumerate} \item establishing a reliable end-to-end connection; and, \item exchanging connection establishment information. \end{enumerate} In some cases, the underlying transport mechanisms accomplish both simultaneously (when the end-to-end connection is built, connection establishment information is also exchanged). Thus, in order to to perform asynchronous connections effectively, use of \verb"TAsynConnRequest" and \verb"TAsynRetry" should reflect this two-step process: \begin{enumerate} \item Call \verb"TAsynConnRequest" with the \verb"async" parameter taking the value~1. If the return value was either \verb"NOTOK" (the connection was not established), or \verb"DONE" (the connection was established), then terminate this algorithm. Otherwise, a return value of \verb"OK" indicates that connection establishment process has begun. \item At some point in the future, call \verb"TSelectMask" to get an argument for \verb"xselect". Then call \verb"xselect" checking to see if writing is permitted. If either call returns \verb"NOTOK", then a catastrophic error has occurred. Repeat this step as often as necessary until \verb"xselect" says that writing is permitted. \item Call \verb"TAsynRetry". If the return value was either \verb"NOTOK" (the connection was not established), or \verb"DONE" (the connection was established), then terminate this algorithm. Otherwise, a return value of \verb"OK" indicates that connection establishment is {\em still\/} in progress. Go forward to the next step. \item At some point in the future, call \verb"TSelectMask" to get an argument for \verb"xselect". Then call \verb"xselect" checking to see if reading is permitted. If either call returns \verb"NOTOK", then a catastrophic error has occurred. Repeat this step as often as necessary until \verb"xselect" says that reading is permitted. \item Call \verb"TAsynRetry". If the return value was either \verb"NOTOK" (the connection was not established), or \verb"DONE" (the connection was established), terminate this algorithm. Otherwise, a return value of \verb"OK" indicates that connection establishment is {\em still\/} in progress. Go back to the previous step. \end{enumerate} Although this seems complicated, implementation of these rules is actually straight-forward. In most cases, your code will do some work unrelated to the connection Note that this procedure is equally applicable to the higher-layers (session, presentation, and association control) which also provide asynchronous connection facilities. For example, at the application layer, the routines \verb"AcAsynAssocRequest" and \verb"AcAsynRetryRequest" would be used. \f \section {Data Transfer} Once the connection has been established, a transport-descriptor is used to reference the connection. This is usually the first parameter given to any of the remaining routines in the \man libtsap(3n) library. Further, the last parameter is usually a pointer to a \verb"TSAPdisconnect" structure (as described on page~\pageref{TSAPdisconnect}). If a call to one of these routines fails, then the structure is updated. Otherwise, if the value of the \verb"td_reason" element is associated with a fatal error, then the connection is closed. That is, a {\sf T-DISCONNECT.INDICATION\/} event has occurred. The \verb"DR_FATAL" macro can be used to determine this. \begin{quote}\index{DR\_FATAL}\small\begin{verbatim} int DR_FATAL (r) int r; \end{verbatim}\end{quote} For protocol purists, the \verb"DR_OFFICIAL" macro can be used to determine if the error is an ``official'' error as defined by the specification, or an ``unofficial'' error used by the implementation. \begin{quote}\index{DR\_OFFICIAL}\small\begin{verbatim} int DR_OFFICIAL (r) int r; \end{verbatim}\end{quote} \subsection {Sending Data} There are three routines that may be used to send data. A call to the \verb"TDataRequest" routine is equivalent to a {\sf T-DATA.REQUEST\/} action on the part of the user. \begin{quote}\index{TDataRequest}\small\begin{verbatim} int TDataRequest (sd, data, cc, td) int sd; char *data; int cc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"data"/\verb"cc":] the data to be written (and the length of that data); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TDataRequest" is successful, then the data has been queued for sending. Otherwise, the \verb"td" parameter indicates the reason for failure. The \verb"TWriteRequest" routine is similar in nature to the \verb"TDataRequest" routine, but uses a different set of parameters. The invocation is: \begin{quote}\index{TWriteRequest}\small\begin{verbatim} int TWriteRequest (sd, uv, td) int sd; struct udvec *uv; struct TSAPdisconnect *td; \end{verbatim}\end{quote} While the parameters are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"uv":] the data to be written, described in a null-terminated array of scatter/gather elements: \begin{quote}\index{udvec}\small\begin{verbatim} struct udvec { caddr_t uv_base; int uv_len; }; \end{verbatim}\end{quote} The elements of the structure are: \begin{describe} \item[\verb"uv\_base":] the base of an element; and, \item[\verb"uv\_cc":] the length of an element. \end{describe} and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TWriteRequest" is successful, then the data has been queued for sending. Otherwise, the \verb"td" parameter indicates the reason for failure. A call to the \verb"TExpdRequest" routine is equivalent to a {\sf T-EXPEDITED-DATA.REQUEST\/} action on the part of the user. \begin{quote}\index{TExpdRequest}\small\begin{verbatim} int TExpdRequest (sd, data, cc, td) int sd; char *data; int cc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"data"/\verb"cc":] the data to be written (and the length of that data, which may not exceed \verb"TX_SIZE" octets); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TExpdRequest" is successful, then the data has been queued for expedited sending. Otherwise, the \verb"td" parameter indicates the reason for failure. \subsection {Receiving Data} There is one routine that is used to read data, \verb"TReadRequest", a call to which is equivalent to waiting for a {\sf T-DATA.INDICATION\/} or {\sf T-EXPEDITED-DA\-TA.IN\-DI\-CA\-TION} event. \begin{quote}\index{TReadRequest}\small\begin{verbatim} int TReadRequest (sd, tx, secs, td) int sd; struct TSAPdata *tx; int secs; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"tx":] a pointer to the \verb"TSAPdata" structure to be given the data; \item[\verb"secs":] the maximum number of seconds to wait for the data (a value of \verb"NOTOK" indicates that the call should block indefinitely, whereas a value of \verb"OK" indicates that the call should not block at all, e.g., a polling action); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TReadRequest" is successful, then the data has been read into the \verb"tx" parameter. \begin{quote}\index{TSAPdata}\small\begin{verbatim} struct TSAPdata { int tx_expedited; int tx_cc; struct qbuf tx_qbuf; }; \end{verbatim}\end{quote} The elements of a \verb"TSAPdata" structure are: \begin{describe} \item[\verb"tx\_expedited":] whether the data was received via expedited transfer (i.e., an {\sf T-EXPEDITED-DATA.INDICATION\/} event occurred); \item[\verb"tx\_cc":] the total number of octets that was read; and, \item[\verb"tx\_qbuf":] the data that was read, in a buffer-queue form. \begin{quote}\index{qbuf}\small\begin{verbatim} struct qbuf { struct qbuf *qb_forw; struct qbuf *qb_back; int qb_len; char *qb_data; char qb_base[1]; }; \end{verbatim}\end{quote} The elements of a \verb"qbuf" structure are:\label{tsap:qbuf} \begin{describe} \item[\verb"qb\_forw"/\verb"qb\_back":] forward and back pointers; \item[\verb"qb\_data"/\verb"qb\_len":] the user data (and the length of that data); and, \item[\verb"qb\_base":] the extensible array containing the data. \end{describe} \end{describe} Note that the data contained in the structure was allocated via \man malloc(3), and should be released by using the \verb"TXFREE" macro when no longer referenced. The \verb"TXFREE" macro, which is used for this purpose, behaves as if it was defined as:\label{TXFREE} \begin{quote}\index{TXFREE}\small\begin{verbatim} void TXFREE (tx) struct TSAPdata *tx; \end{verbatim}\end{quote} The macro frees only the data allocated by \verb"TDataRequest", and not the \verb"TSAPdata" structure itself. Further, \verb"TXFREE" should be called only if the call to the \verb"TDataRequest" routine returned \verb"OK". \[\fbox{\begin{tabular}{lp{0.8\textwidth}} \bf NOTE:& Because the \verb"TSAPdata" structure contains a \verb"qbuf" element, care must be taken in initializing and copying variables of this type. The routines in \man libtsap(3n) library will correctly initialize these structures when given as parameters. But, users who otherwise manipulate \verb"TSAPdata" structures should take great care. \end{tabular}}\] Otherwise if the call to \verb"TReadRequest" did not succeed, the \verb"td" parameter indicates the reason for failure. \subsection {Asynchronous Event Handling} The data transfer events discussed thus far have been synchronous in nature. Some users of the transport service may wish an asynchronous interface. The \verb"TSetIndications" routine is used to change the service associated with a transport-descriptor to or from an asynchronous interface. \begin{quote}\index{TSetIndications}\small\begin{verbatim} int TSetIndications (sd, data, disc, td) int sd; int (*data) (), (*disc) (); struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"data":] the address of an event-handler routine to be invoked when data has arrived (either a {\sf T-DATA.INDICATION\/} or {\sf T-EXPEDITED-DATA.INDICATION} event occurs); \item[\verb"disc":] the address of an event-handler routine to be invoked when the connection has been closed (a {\sf T-DISCONNECT.INDICATION\/} event occurs); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the service is to be made asynchronous, then both \verb"data" and \verb"disc" are specified; otherwise, if the service is to be made synchronous, neither should be specified (use the manifest constant \verb"NULLIFP"). The most likely reason for the call failing is \verb"DR_WAITING", which indicates that an event is waiting for the user. When an event-handler is invoked, future invocations of the event-hander are blocked until it returns. The return value of the event-handler is ignored. Further, during the execution of a synchronous call to the library, the event-handler will be blocked from being invoked. When an event associated with data arriving occurs, the event-handler routine is invoked with two parameters: \begin{quote}\small\begin{verbatim} (*data) (sd, tx); int sd; struct TSAPdata *tx; \end{verbatim}\end{quote} The parameters are: \begin{describe} \item[\verb"sd":] the transport-descriptor; and, \item[\verb"tx":] a pointer to a \verb"TSAPdata" structure containing the data. \end{describe} Note that the data contained in the structure was allocated via \man malloc(3), and should be released with the \verb"TXFREE" macro (described on page~\pageref{TXFREE}) when no longer needed. Similarly, when an event associated with connection release occurs, the event-handler is also invoked with two parameters: \begin{quote}\small\begin{verbatim} (*disc) (sd, td); int sd; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters are \begin{describe} \item[\verb"sd":] the transport-descriptor; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure indicating why the connection was released. \end{describe} Note that the transport-descriptor is no longer valid at the instant the call is made. \[\fbox{\begin{tabular}{lp{0.8\textwidth}} \bf NOTE:& The \man libtsap(3n) library uses the SIGEMT signal to provide these services. Programs using asynchronous transport-descriptors should NOT use SIGEMT for other purposes. \end{tabular}}\] \subsection {Synchronous Event Multiplexing} A user of the transport service may wish to manage multiple transport-descriptors simultaneously; the routine \verb"TSelectMask" is provided for this purpose. This routine updates a file-descriptor mask and associated counter for use with \verb"xselect". \begin{quote}\index{TSelectMask}\small\begin{verbatim} int TSelectMask (sd, mask, nfds, td) int sd; fd_set *mask, int *nfds; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"mask":] a pointer to a file-descriptor mask meaningful to \verb"xselect"; \item[\verb"nfds":] a pointer to an integer-valued location meaningful to \verb"xselect"; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call is successful, then the \verb"mask" and \verb"nfds" parameters can be used as arguments to \verb"xselect". The most likely reason for the call failing is \verb"DR_WAITING", which indicates that an event is waiting for the user. If \verb"xselect" indicates that the transport-descriptor is ready for reading, \verb"TReadRequest" should be called with the \verb"secs" parameter equal to \verb"OK". If the network activity does not constitute an entire event for the user, then \verb"TReadRequest" will return \verb"NOTOK" with error code \verb"DR_TIMER". \f \section {Connection Release} The \verb"TDiscRequest" routine is used to release a connection. Note, that the TSAP makes no guarantee that any queued data will be received before the connection closes. \begin{quote}\index{TDiscRequest}\small\begin{verbatim} int TDiscRequest (sd, data, cc, td) int sd; char *data; int cc; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to the procedure are described on page~\pageref{TDiscRequest}. \f \section {State Saving and Restoration} Some users of the transport service, and in particular the session provider, require the ability to \man execve(2) another process image and have that process use the transport connection. Since the \man libtsap(3n) library is not kernel-resident, special provisions are necessary to support this behavior. \subsection {Saving the State} The routine \verb"TSaveState" is used to record the state of the TSAP for a given transport-descriptor. \begin{quote}\index{TSaveState}\small\begin{verbatim} int TSaveState (sd, vec, td) int sd; char **vec; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"sd":] the transport-descriptor; \item[\verb"vec":] a pointer to the first free slot in the argument vector for \man execve(2); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call succeeds, then an extra {\em magic argument\/} has been placed in the argument vector. The most likely reason for the call failing is \verb"DR_WAITING", which indicates that an event is waiting for the user. \[\fbox{\begin{tabular}{lp{0.8\textwidth}} \bf NOTE:& Once a successful call to \verb"TSaveState" is made on a transport descriptor, that descriptor may no longer be referenced until a corresponding call to \verb"TRestoreState" is successful. \end{tabular}}\] \subsection {Restoring the State} The routine \verb"TRestoreState" is used to re-initialize the state of the TSAP. \begin{quote}\index{TRestoreState}\small\begin{verbatim} int TRestoreState (buffer, ts, td) char *buffer; struct TSAPstart *ts; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"buffer":] the {\em magic argument\/} constructed by \verb"TSaveState"; \item[\verb"ts":] a pointer to a \verb"TSAPstart" structure, which is updated only if the call succeeds; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If \verb"TRestoreState" is successful, it returns information in a \verb"TSAPstart" structure, as defined on page~\pageref{TSAPstart}. There is one exception however: in the current implementation the \verb"ts_cc" and \verb"ts_data" elements are undefined on a successful return from \verb"TRestoreState". \f \section {Cookie Parameters} There are two {\em cookie\/} parameters: network addresses and quality of service. \subsection {Network Addresses}\label{nsap:addresses} Network addresses can vary greatly. In this software distribution, a ``unified'' format has been adopted in the \verb"NSAPaddr" structure: \begin{quote}\index{NSAPaddr}\small\begin{verbatim} struct NSAPaddr { long na_type; #define NA_NSAP 0 #define NA_TCP 1 #define NA_X25 2 #define NA_BRG 3 #define SUBNET_X25 1 #define SUBNET_JANET 2 #define SUBNET_INTERNET 3 long na_subnet; union { struct na_nsap { #define NASIZE 64 char na_nsap_address[NASIZE]; char na_nsap_addrlen; } un_na_nsap; struct na_tcp { #define NSAP_DOMAINLEN 63 char na_tcp_domain[NSAP_DOMAINLEN + 1]; u_short na_tcp_port; u_short na_tcp_tset; #define NA_TSET_TCP 0x0001 #define NA_TSET_UDP 0x0002 } un_na_tcp; struct na_x25 { #define NSAP_DTELEN 15 char na_x25_dte[NSAP_DTELEN + 1]; char na_x25_dtelen; #define NPSIZE 4 char na_x25_pid[NPSIZE]; char na_x25_pidlen; #define CUDFSIZE 16 char na_x25_cudf[CUDFSIZE]; char na_x25_cudflen; #define FACSIZE 6 char na_x25_fac[FACSIZE]; char na_x25_faclen; } un_na_x25; } na_un; #define na_address na_un.un_na_nsap.na_nsap_address #define na_addrlen na_un.un_na_nsap.na_nsap_addrlen #define na_domain na_un.un_na_tcp.na_tcp_domain #define na_port na_un.un_na_tcp.na_tcp_port #define na_dte na_un.un_na_x25.na_x25_dte #define na_dtelen na_un.un_na_x25.na_x25_dtelen #define na_pid na_un.un_na_x25.na_x25_pid #define na_pidlen na_un.un_na_x25.na_x25_pidlen #define na_cudf na_un.un_na_x25.na_x25_cudf #define na_cudflen na_un.un_na_x25.na_x25_cudflen #define na_fac na_un.un_na_x25.na_x25_fac #define na_faclen na_un.un_na_x25.na_x25_faclen }; #define NULLNA ((struct NSAPaddr *) 0) \end{verbatim}\end{quote} As shown, this structure is really a discriminated union (a structure with a tag element followed by a union). Based on the value of the tag (\verb"na_type"), a different structure is selected. For a ``real network service'', the value of the tag is \verb"NA_NSAP", and the following elements are meaningful: \begin{describe} \item[\verb"na\_address"/\verb"na\_addrlen":] the network address (and its length), binary-valued. \end{describe} For emulation of the OSI transport service over some other transport stack, a pseudo-OSI network addressing scheme is used, as described in \cite{Interim.Addresses}. The \verb"na_subnet" field is used for the subnetwork prefix for these transport stacks. In order to normalize such an address into a ``real'' OSI addres,s the routine \verb"na2norm" is used: \begin{quote}\index{na2norm}\begin{verbatim} char *na2norm (na) struct NSAPaddr *na; \end{verbatim}\end{quote} The parameter to this procedure is: \begin{describe} \item[\verb"na"]: the network address to be normalized. \end{describe} A new network address is returned from a static area which contains the normalized form. For emulation of the OSI transport service on top of the TCP, the value of the tag is \verb"NA_TCP", and the following elements are meaningful: \begin{describe} \item[\verb"na\_domain":] the null-terminated domain name (e.g., ``gonzo.twg.com'') or dotted-quad (e.g., ``128.99.0.17''); \item[\verb"na\_port":] the TCP-port number offering the service (if zero, the service on port~102 is used); and, \item[\verb"na\_tset":] the set of IP-based transport services available at the address (if zero, the TCP service is used). \end{describe} For use of a single-subnet X.25, the value of the tag is \verb"NA_X25", and the following elements are meaningful: \begin{describe} \item[\verb"na\_dte"/\verb"na\_dtelen":] the X.121 address (and its length), ascii-valued, possibly null-terminated; \item[\verb"na\_pid"/\verb"na\_pidlen":] the protocol id (and its length), binary-valued; \item[\verb"na\_cudf"/\verb"na\_cudflen":] the call user data (and its length), binary-valued; and, \item[\verb"na\_fac"/\verb"na\_faclen":] the negotiated facilities proposed in the call request packet (and its length), binary-valued. \end{describe} For use of a TP0-bridge between the TCP and X.25, the value of the tag is \verb"NA_BRG", and the elements above are meaningful. The routine \verb"na2str" takes a network address and returns a null-ter\-mi\-na\-ted ascii string suitable for viewing: \begin{quote}\index{na2str}\begin{verbatim} char *na2str (na) struct NSAPaddr *na; \end{verbatim}\end{quote} The parameter to this procedure is: \begin{describe} \item[\verb"na"]: the network address to be printed. \end{describe} \subsection {Quality of Service}\label{tsap:qos} Currently, quality of service is largely uninterpreted by the software. However, the quality of service structure contains those parameters which are supported: \begin{quote}\index{QOStype}\small\begin{verbatim} struct QOStype { /* transport QOS */ int qos_reliability; #define HIGH_QUALITY 0 #define LOW_QUALITY 1 /* session QOS */ int qos_sversion; int qos_extended; }; #define NULLQOS ((struct QOStype *) 0) \end{verbatim}\end{quote} The elements of this structure are: \begin{describe} \item[\verb"qos\_reliability":] the ``reliability'' level of the connection, either high- or low-quality; \item[\verb"qos\_sversion":] the session version requested/negotiated on this connection (only applicable above the transport layer, obviously); and, \item[\verb"qos\_extended":] the extended control (if non-zero, extended control is used by the session layer). \end{describe} \f \section {Listen Facility}\label{tsap:listen} The \man libtsap(3n) library, supports a facility which permits a process to {\em listen\/} for certain connections. This can be useful for implementing an application which requires that a single server process handle multiple clients, or for connection recovery. These routines return the manifest constant \verb"NOTOK" on error, and \verb"OK" on success, they also update the \verb"td" parameter given to the routine. This parameter is a pointer to a \verb"TSAPdisconnect" structure. Although this facility is described in terms of the \man libtsap(3n) library, it will function at any other higher-layer in the system (e.g., the listen facility can be used for session or application-entities). A program starts listening for an particular connection by calling the routine \verb"TNetListen". \begin{quote}\index{TNetListen}\small\begin{verbatim} int TNetListen (ta, td) struct TSAPaddr *ta; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"ta":] the transport address (0 or more network addresses) to listen on; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call is successful, then the program is now listening for incoming connections on that network address. Otherwise, the \verb"td" parameter indicates the reason for failure. A variant of \verb"TNetListen" is the \verb"TNetUnique" routine, which starts the process listening on a set of unique network (sub)addresses. \begin{quote}\index{TNetUnique}\small\begin{verbatim} int TNetUnique (ta, td) struct TSAPaddr *ta; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"ta":] a transport address containing one or more partially filled-in network addresses; and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call is successful, each network address in the \verb"ta" parameter is fully filled-in, the program is now listening for incoming connections on the resulting transport. Otherwise, the \verb"td" parameter indicates the reason for failure. To check when a new connection is waiting, or when existing connections have activity on them, the routine \verb"TNetAccept" is used.\label{tsap:accept} \begin{quote}\index{TNetAccept}\small\begin{verbatim} int TNetAccept (vecp, vec, nfds, rfds, wfds, efds, secs, td) int *vecp, char **vec; int nfds; fd_set *rfds, *wfds, *efds; int secs; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"vecp"/\verb"vec":] the initialization vector for the new connection. \item[\verb"nfds"/\verb"rfds"/\verb"wfds"/\verb"efds":] connection-descriptors for use with \verb"xselect"; \item[\verb"secs":] the maximum number of seconds to wait for activity (a value of \verb"NOTOK" indicates that the call should block indefinitely, whereas a value of \verb"OK" indicates that the call should not block at all, e.g., a polling action); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call to \verb"TNetAccept" succeeds then the value of \verb"vecp" should be checked. If \verb"vecp" is greater than zero, a new connection has been accepted, and \verb"TInit" should be called, presumably followed by \verb"TConnResponse".% \footnote{Actually, any service addressable via a transport selector can use this service, e.g., if appropriate, a call to \verb"AcInit", followed by a call to \verb"AcAssocResponse", can be made.} Regardless of the value of \verb"vecp", the value of \verb"rfds" and \verb"wfds" should be checked to see which connections have activity pending. For these connections, any reads should probably be done with a \verb"secs" argument indicating a polling operation (i.e., a value of \verb"OK"). Otherwise, if the call to \verb"TNetAccept" fails, then the \verb"td" parameter indicates the reason for failure. \verb|Caveat|: The \verb|TNetAccept| procedure when first called arranges to clean up dead child processes. If the program will run any sub-processes and check their exit status, the automatic collection of zombie process should be disabled, by first calling \verb|TNetAccept| with a timeout of \verb|OK| and then setting the child signal handler to it's default state. Prior to exiting, the user should call \verb"TNetClose" to stop listening for connections. \begin{quote}\index{TNetClose}\small\begin{verbatim} int TNetClose (ta, td) struct TSAPaddr *ta; struct TSAPdisconnect *td; \end{verbatim}\end{quote} The parameters to this procedure are: \begin{describe} \item[\verb"ta":] the transport address to stop listening on (use the manifest constant \verb"NULLTA" to stop listening on all addresses); and, \item[\verb"td":] a pointer to a \verb"TSAPdisconnect" structure, which is updated only if the call fails. \end{describe} If the call is successful, then the program has stopped listening for incoming connections on that network address. Otherwise, the \verb"td" parameter indicates the reason for failure. \f \section {Error Conventions} All of the routines in this library return the manifest constant \verb"NOTOK" on error, and also update the \verb"td" parameter given to the routine. The \verb"td_reason" element of the \verb"TSAPdisconnect" structure can be given as an parameter to the routine \verb"TErrString" which returns a null-terminated diagnostic string. \begin{quote}\index{TErrString}\small\begin{verbatim} char *TErrString (c) int c; \end{verbatim}\end{quote} \f \section {Compiling and Loading} Programs using the \man libtsap(3n) library should include \verb"<isode/tsap.h>". These programs should also be loaded with \verb"-ltsap" and, for reasons explained momentarily, \verb"-lcompat". \f \section {An Example} Let's consider how one might construct a loopback entity that resides on the TSAP. This entity will use a synchronous interface. First, we must decide at what address the entity will reside. For simplicity's sake, we'll say that the location is \verb"tsap/echo", as defined in the \man isoservices(5) database. Next, we actually code the loopback entity. There are two parts to the program: initialization and data transfer; release will occur whenever data transfer fails. In our example, we assume that the routine \verb"error" results in the process being terminated after printing a diagnostic. In Figure~\ref{initTSloopback}, the initialization steps for the loopback entity, including the outer {\em C\/} wrapper, is shown. The entity does not examine any of its arguments, but could do so after the call to \verb"TInit". After examining the arguments, it could decide to reject the connection attempt, by using \verb"TDiscRequest". Instead, it uses \verb"TConnResponse" with the exact negotiated parameters with which it was supplied. Hence, if the initiator wanted to use expedited data transfer, the loopback entity responding to the connection would honor that. In Figure~\ref{dataTSloopback} on page~\pageref{dataTSloopback}, the data transfer loop is realized. The loopback entity awaits an event from the service provider, which either indicates that data has arrived or that the connection has been closed. If a disconnection occurred (a {\sf T-DISCONNECT.INDICATION\/} event is reported), then the reason is checked. If the event did not occur because the initiator performed a {\sf T-DISCONNECT.REQUEST\/} indication, then an error is signaled. Otherwise, the inner-loop is terminated and the process will gracefully terminate. If instead data arrived, it is echoed back to the initiator. \clearpage \tagrind[tp]{grind6-2}{Initializing the loopback entity}{initTSloopback} \clearpage \tagrind[tp]{grind6-3}{Data Transfer for the loopback entity}{dataTSloopback} \f \section {Compatibility Issues} The \man libcompat(3) library is used as an aid for porting the software from one system to another. This library contains generic service routines, which are in turn composed of the native facilities available on the target host. All of the higher layer \verb"#include" files automatically reference parts of this library as appropriate. Hence, when loading the the portions of the software independently, the loader must be given the \verb"-lcompat" flag. The problem of this approach, of course, is that not all facilities can be precisely emulated. To misquote M.A.~Padlipsky\cite{Gateways.Heffalumps}: \begin{quote}\em Sometimes when you try to make an apple look like an orange you get back something that smells like a lemon. \end{quote} \f \section {For Further Reading} The ISO specification for transport services is defined in \cite{ISO.TP.Service}. The corresponding CCITT recommendation is defined in \cite{CCITT.TP.Service}. The document describing how these services can be implemented on top of the TCP\cite{TCP} is \cite{TSAP.on.TCP}. \f \section {Changes Since the Last Release}\label{tsap:changes} A brief summary of the changes between \verb"tsap"~\tsaprevrsn/ and \verb"tsap"~\tsapvrsn/ are now presented. These are the user-visible changes only; changes of a strictly internal nature are not discussed. The routines \verb"taddr2str" and \verb"str2taddr" were modified to support multiple network addresses.