After highlighting some key ``SCO IPX/SPX programming issues'', this chapter provides detailed instructions on:
to create client-server applications using TLI, and to provide an introduction to the SAPD library routines.The TLI (Transport Layer Interface) library provides routines with which to access IPX. ``Using the IPX protocol'' describes how to use these routines to access IPX. See also ``Transport Layer Interface and X/Open Transport Interface (NET)''.
The structures used by the TLI interface to IPX are:
The TLI (Transport Layer Interface) library provides routines with which to access SPX. SPX supports the following calls from the TLI library:
The structures used by the TLI interface to SPX are:
SCO supplies the following SAP library routines with which to access SAPD:
``Accessing SAP'' provides a brief overview of these routines and how to include them in application programs. See ``Service Advertising Protocol Daemon library'' to find the manual pages for these routines.tispx can be run as either a sender or a receiver of data, using either IPX or SPX as the underlying protocol. The sending instance of tispx sends a specified number of packets to the receiver, and the receiving instance reports the receipt of the packets. (In the case of the connection-based SPX protocol, the receiver acknowledges receipt of the packets to the sender, and the sender reports the receipt of the acknowledgement.)
For a list of command-line options, run tispx -?.
For further details, examine the source provided.
Network byte ordering
Some of the fields in packet headers are byte order sensitive;
the data must be sent in high-to-low order.
Figure 4-1, ``Byte order''
illustrates this.

Figure 4-1 Byte order
You must account for this byte order when writing an
application that communicates with an unknown machine type.
For example,
if an application running on an Intel® 80386
CPU does a t_sndudata,
the data portion of the IPX packet is sent
over the wire in 80386 (low-to-high) order.
This presents a problem if the receiving CPU
(for example, a Motorola® 68030) does not use the same
low-to-high byte order.
IPX addresses
IPX addresses are used to identify
clients and servers on an IPX network.
Table 4-1, ``IPX address fields''
describes the fields that make up an address.
---------------------------------------------- Field Type* Byte order ---------------------------------------------- Network number uint8[4] high-to-low Node number uint8[6] high-to-low Socket number uint8[2] high-to-low ---------------------------------------------- * A uint8 is an unsigned char.
For SCO IPX/SPX servers
or application servers loaded on such file servers,
the network number is the server's internal network number.
For SCO IPX/SPX servers,
this field is always set to 0x000000000001.
A value of 0xFFFFFFFFFFFF can be placed in this field
to indicate a broadcast to the local network.
net[ 4 ];
node[ 6 ];
sock[ 2 ];
An application can obtain the destination address of a server by:
The IPX driver maintains a socket table
that maps the socket number to a specific process.
Each process must request a unique socket number;
the driver does not assign the same socket number
to two processes.
If the application is using a protocol that has been built on top of IPX, the IPX driver identifies the process by first using the protocol's packet type. It then proceeds as follows:
There are two types of socket numbers:
Static socket numbers are requested as part of the t_bind routine which must follow a t_open call, as described in ``Using the IPX protocol'' and ``Using the SPX protocol''. To obtain a static socket number, an application:
The IPX/SPX driver looks at the socket field in the ipxAddr_t structure for the desired socket number. The socket number must be passed using a high-to-low byte order. If the socket number desired is not currently being used, the driver returns the local network number, local node number, and the allocated or requested socket number in the corresponding fields of the ipxAddr_t structure of the ret.addr.buf field.
Only one IPX/SPX endpoint can bind to a given socket number at a time. If an application tries to bind to a socket that has already been bound, an error results and the bind fails.
Services written to run over IPX/SPX generally have well-known or static socket numbers associated with them. Static socket numbers ensure that server and client application types match.
Another method to coordinate servers and clients is to use SAP (the Service Advertising Protocol). ``Using the SAP protocol'' describes this method.
There are two methods by which an application obtains a dynamic socket number:
sock field of the ipxAddr_t
structure is set to 0, the IPX/SPX
driver attempts to allocate a dynamic socket number.
Table 4-2 Novell object types
----------------------------------------------- Description Object type (hex) ----------------------------------------------- User 1 User group 2 Print queue 3 File server 4 Job server 5 Gateway 6 Print server 7 Archive queue 8 Archive server 9 Job queue A Administration B NAS SNA gateway 21 NACS 23 Remote bridge server 24 Bridge server 26 TCP/IP gateway 27 Gateway 29 Time synchronization server 2D Archive server SAP 2E Advertising print server 47 BTrieve VAP 5.0 48 SQL VAP 4C Xtree network version 4D Btrieve VAP 4.11 50 Print queue user 53 WANcopy utility 72 TES - NetWare for VMS 7A NetWare access server 98 NVT server 9E NetWare 386 107 Communications executive 130 NNS domain 133 NetWare 386 print queue 137 Wildcard FFFF -----------------------------------------------
The t_optmgmt function is optional; if used, it must be called after t_bind and before t_unbind.
``Using the IPX protocol'' presents a discussion of using these routines with the IPX protocol.
The IPX driver generates
unitdata error messages.
The t_rcvuderr call works as specified
t_rcvuderr(NET).
General characteristics of IPX
The following should be taken into
consideration before using IPX:
Some of the fields in the header are byte-order sensitive; the data must be sent in high-to-low order. See ``Network byte ordering'' for more information. Table 4-3, ``Fields in an IPX packet header'' summarizes the contents of an IPX header.
Table 4-3 Fields in an IPX packet header
------------------------------------------------------------------ Offset Field Type* Byte order ------------------------------------------------------------------ 0 Checksum uint8 [2] high-to-low 2 Length uint8 [2] high-to-low 4 Transport control uint8 N/A 5 Packet type uint8 N/A 6 Destination address ipxAddr_t structure N/A 18 Source address ipxAddr_t structure N/A ------------------------------------------------------------------ * A uint8 is an unsigned char.The fields contain the following values:
The application must set the ``Packet type'' and the ``Destination address'' fields to send a packet; the IPX driver sets the remaining fields. ``IPX addresses'' describes the fields in an ipxAddr_t structure and methods of obtaining destination network addresses. Table 4-4, ``IPX packet types'' lists IPX packet types and gives brief descriptions of each.
---------------------------------------------- Packet type Description ---------------------------------------------- 0 Regular IPX packet type 1 Routing Information Packet (RIP) 2 Echo packet 3 Error packet 4 Packet Exchange Packet (PEP) 5 Sequence Packet Exchange (SPX) 17 NetWare Core Protocols (NCP) 20 NetBIOS name packet ----------------------------------------------
For more information about these functions, see ``Transport Layer Interface and X/Open Transport Interface (NET)''.
The following header files must be included in the order listed in any program that uses the TLI interface to access IPX:
Except where otherwise stated, all functions return 0 if successful or -1 if unsuccessful. These functions may also set errno and t_errno.
The t_bind call works as specified in t_bind(NET), with the following additions:
The t_bind call allows an application to bind to a socket number, which can be either dynamic or static. ``Socket numbers'' describes procedures for obtaining both static and dynamic socket numbers.
IPX does not use the qlen field in the t_bind structure. It should be set to 0.
The t_bind call requires that a pointer to an ipxAddr_t structure be passed in the req t_bind structure (req.addr.buf field).
The t_open call works as specified in t_open(NET), with the following additions:
On input, path passes a pointer to the path of the IPX driver. The path is /dev/ipx.
On output, info receives the initialized t_info structure. The t_open function returns a file descriptor and a TLI information structure (of type t_info) when the file is opened successfully. Table 4-5, ``Fields in a t_info structure'' describes the contents of the fields in this structure.
Table 4-5 Fields in a t_info structure
-------------------------------------------------------------------------
Field Value Description
-------------------------------------------------------------------------
Addr 12 The 12 byte IPX address consisting of: network
number (4 bytes), node number (6 bytes), and socket
number (2 bytes).
options 1 IPX packet type in IPX packet header.
tsdu 546 The maximum transport service data unit is 546 bytes.
etsdu -2 Not supported.
connect -2 Not supported.
discon -2 Not supported.
servtype T_CLTS The service type is always T_CLTS (connectionless-
mode service).
-------------------------------------------------------------------------
The t_optmgmt call works as specified in t_optmgmt(NET), with the following additions:
The t_optmgmt function cannot be used to negotiate any of the values listed in Table 4-5, ``Fields in a t_info structure''.
The t_optmgmt (option management) call enables the user to obtain the local IPX address. IPX does not support any negotiable options.
On input, ret passes a pointer to (or the address of) the structure that is initialized to the local IPX address.
On output, ret receives the local IPX address in the ipxAddr_t structure
IPX does not use the flags field in the t_optmgmt structure; it should be set to 0.
The len and maxlen fields in the netbuf structure must be initialized to the size of an ipxAddr_t structure. The buf field returns all the local information about this transport endpoint: source network number, source node number, and source socket number.
The req.buf and ret.buf fields must point to a structure large enough to hold an ipxAddr_t (12 bytes). Upon successful completion, ret.buf contains the source information: the first 4 bytes contain the local network number, the next 6 bytes contain the node number, and the last 2 bytes contain the local socket number. All these numbers are in high-to-low byte order.
The t_rcvudata call works as specified in t_rcvudata(NET), with the following additions:
On input, flags passes a pointer to an integer. The flag should be set to 0. Even though IPX does not use this flag, a pointer to the flag must be passed.
On output, ud receives the information in the t_unitdata structure. The ud.udata.buf field points to the data that was sent with the IPX packet.
The address (addr.buf field of the t_unitdata structure) must point to an ipxAddr_t structure.
The t_rcvudata call is the reverse of t_sndudata. The address of the sender is returned to the ud.addr field. The packet type is in the ud.opt field, and the packet data is in the ud.udata field.
The len field of opt, udata, and addr are set according to the incoming packet. The amount of data received in the IPX packet is in ud.udata.len.
There is no flow control on incoming data
because IPX is a datagram service.
If the IPX application cannot service the
incoming data as fast as the sender
generates it, the IPX driver
drops the excess incoming packets.
The t_sndudata call works as specified in t_sndudata(NET), with the following additions:
On completion, the t_sndudata call returns 0 if successful or -1 if unsuccessful. Errors can also cause the error field of the t_uderr structure to be set. See t_rcvuderr(NET) for more information on how to receive these error messages.
The address (addr.buf field of the t_unitdata structure) must point to an ipxAddr_t structure.
The destination address network number, node number, and socket number must be filled in by the user program. The numbers must be in high-to-low byte order. See ``Network byte ordering'' for more information.
The IPX user sets the packet type of the outgoing IPX packet by passing 1 byte specifying the packet type in the options (opt) field. The other fields in the outgoing IPX packet (``Checksum'', ``Length'', ``Transport control'', ``Network number'', ``Node number'', and ``Socket number'') are filled in by the IPX driver.
IPX does not support EXPEDITED data. All data is sent on a first-come, first-served basis.
A successful return by the t_sndudata call does not guarantee that the data has been sent; it guarantees only that the data has been queued up to be sent.
Because the largest number of bytes that can be sent with any t_sndudata is 546, any attempt to send more than 546 bytes results in an error.
If ud.udata.len equals 0, no packet is sent.
The t_unbind call works as specified in t_unbind(NET), with the following additions:
This call releases the IPX socket number used by this transport endpoint for future use. The t_close function calls t_unbind.
This call places the transport endpoint in a T_UNBND state,
allowing the process to bind to a new socket number.
Using the SPX protocol
Because SPX is a connection-based service,
it reliably delivers data and notifies the user
if any errors occur during data transmission.
Upon encountering a data transmission error,
SPX retries a certain number of times before
closing the connection and notifying the connection user.
SPX also notifies the user if a
disconnection indication is received from the
remote connection endpoint.
SPX functions in both synchronous and asynchronous modes. The application developer determines the mode.
Applications access SPX using TLI (the Transport Layer Interface). This chapter assumes that you are familiar with NetWare communication processes and TLI. For information on these topics, see:
Server applications need to:
Client applications need to:
Procedures for both server and client
applications are presented below.
A synchronous server application must:
A synchronous client application must:
The SPX driver checks the state of the transport endpoint when the state is relevant to the action it is to perform. For example, a listen/connect request cannot be performed without a bind, and data cannot be sent without both a bind and a listen/connect request. However, a connection can be closed or unbound in any state.
An outstanding connection request is a connection request that has arrived and been delivered to the application, but to which the application has not yet responded with either a connection request acknowledge (t_accept) or connection request reject (t_snddis).
SPX allows up to a specified number of outstanding connection requests per transport endpoint (the number is the SPX_MAX_LISTENS_PER_SOCKET parameter in the spx_tune.h file). This parameter is currently set to 10. If the application requests more than 10, only 10 are given.
Although the SPX_MAX_LISTENS_PER_SOCKET parameter allows an application to have more than one outstanding connection request, it is recommended that there be only one. If a value greater than 1 is specified in the qlen field during a t_bind, a connection request can arrive from a remote transport endpoint, making the t_listen unblock. If another connection request arrives between the time the t_listen unblocks and the t_accept is issued, the t_accept fails, saying an event has occurred. You cannot call t_accept to accept the connection requests until all pending connection requests have been retrieved off the stream head using t_listen. A t_bind with qlen equal to 1 should be issued to avoid this problem.
If a local transport endpoint receives a disconnection request, the SPX driver sends a disconnection indication to the endpoint with reason set to TLI_SPX_CONNECTION_TERMINATED. SPX then changes the state of the stream to T_IDLE. All data that was queued for or in transit is lost, and the connection is broken.
The SPX watchdog wakes up every two minutes (this value is tunable) to check for dead connections. The SPX watchdog looks for two types of dead connections:
The SPX watchdog begins watching connections when the first device (excluding the NPSD) is opened. The SPX watchdog stops checking connections after the last SPX device is closed.
The system overhead for the SPX watchdog varies with the maximum number of connections, which is tunable. In the best case, it is the time SPX takes to check the maximum number of connection pointers against NULL. In the worst case, it is the time SPX takes to close down all the SPX connections because they have all frozen at the same time.
The SPX watchdog checks only the connections in the T_DATAXFER state.
SPX periodically awakens the watchdog. When the watchdog awakens, it checks how long each connection has been inactive. If a connection has been inactive for a specified time (the default is one minute), the watchdog sends the connection a watchdog packet.
A connection can remain open indefinitely if the remote transport endpoint always acknowledges SPX watchdog packets. This functionality is part of the definition of an SPX connection.
If an application cannot receive data as fast as the sender is sending it, the SPX driver (on the receiving side) acknowledges the last received packet, then queues up a readside-retry procedure that will try again. This time interval is tunable; the default is 0.5 seconds.
If SPX still cannot deliver packets on the second try, it increases the time interval for subsequent retries. It multiplies the previous retry time by 1.5. One of the following values is then used:
The maximum read retry time is tunable. By default, SPX retries five times before generating a disconnect indication with reason set to ENOSTR. This disconnect indication flushes the stream read and write queues before it reaches the stream head.
If the SPX driver is sending data faster than a remote transport endpoint can receive data, the SPX driver stops sending data. The driver then monitors the connection for one of the following conditions:
The content and structure of the packet's data portion are entirely the responsibility of the application using SPX and can follow any format.
Some of the fields in the header are byte order sensitive and the data must be sent in high-to-low order. See ``Network byte ordering'' for more information.
The SPX header consists of an IPX header and seven additional fields. Table 4-6, ``SPX packet header'' describes the fields in an SPX header.
When the application is establishing a connection with SPX, it must pass the destination address to SPX. After the connection has been established, the application does not need to set any fields in the header. The SPX driver automatically sets all fields to the appropriate values.
An application can define a value for one field in the header: the ``Data stream type'' field. Because there is no standard for its use, using this field is not recommended.
Table 4-6 SPX packet header
---------------------------------------------------------------------- Offset Field Type* Byte order ---------------------------------------------------------------------- 0 Checksum uint8 [2] high-to-low 2 Length uint8 [2] high-to-low 4 Transport control uint8 N/A 5 Packet type uint8 N/A 6 Destination address ipxAddr_t structure N/A 18 Source address ipxAddr_t structure N/A 30 Connection control uint8 N/A 31 Data stream type uint8 N/A 32 Source connection ID uint8 [2] high-to-low 34 Destination connection ID uint8 [2] high-to-low 36 Sequence number uint8 [2] high-to-low 38 Acknowledge number uint8 [2] high-to-low 40 Allocation number uint8 [2] high-to-low ---------------------------------------------------------------------- * A uint8 is an unsigned char.
The fields in the SPX packet header are:
The SPX driver is a STREAMS driver that you must link into the kernel. You must also install:
NPSD must be running to enable the use of SPX. NPSD reads the NPSConfig file as it initializes. That file contains a flag that tells NPSD whether or not to activate SPX. The flag should be set to "active" so that NPSD activates SPX and links SPX to the stack. If NPSD is not running and the flag is not set to ``active'', the t_open call that opens SPX fails.
The SPX driver is accessed through two devices:
There is no read/write interface for SPX.
The tunable parameters for SPX
are in a file called spx_tune.h.
These parameters are described in the
Networking Guide .
Accessing SPX
The following TLI routines
are used to access SPX:
The following header files must be included in the order listed in any program that uses the TLI interface to SPX:
The t_bind call works as specified in t_bind(NET), with the following additions:
The qlen field of the t_bind structure is used to indicate the total number of outstanding connection requests allowed on this endpoint. Applications that do not service connection requests should set this field to 0. Applications that service connection requests should set this field to 1. See ``Connection requests'' for more information .
The t_bind call allows an endpoint to bind to a socket number. The socket number can be either dynamic or static. SPX keeps track of which socket number is bound to which transport endpoint. The net and node fields do not need to be filled in the ipxAddr_t structure, but the sock field must be initialized to either a static or dynamic socket value. ``Socket numbers'' presents procedures for obtaining both static and dynamic socket numbers.
The t_connect call works as specified in t_connect(NET), with the following additions:
SPX supports both synchronous and asynchronous modes.
On input, sndcall passes a pointer to a t_call structure that contains the IPX address of the server with which the SPX client wants to connect; rcvcall passes a pointer to a t_call structure that contains the server's connection information upon successful completion of the call.
On output, rcvcall receives the server's connection information: network number, node number, socket number, connection ID, and allocation number.
The SPX driver tries a certain number of times (as specified in the spx_tune.h file) to connect with the remote transport endpoint. After trying the specified number of times without receiving an acknowledgment, the SPX driver generates a disconnect indication of TLI_SPX_CONNECTION_FAILED -- see ``t_rcvdis''. If this error occurs, the state of the stream is set to T_IDLE.
See t_connect(NET) for other possible errors.
The SPX driver does not use the udata structure in the t_call structure; its fields should be initialized. You must set the udata.len and udata.maxlen fields to 0 and the udata.buf field to NULL.
The SPX driver does not use the sequence field in the t_call structure.
All information passed in the ipxAddr_t structure must be in high-to-low byte order. See ``Network byte ordering'' for more information.
The sndcall.opt.len and sndcall.opt.maxlen fields must be initialized to the size of an SPX_OPTS or equivalent structure. The sndcall.opt.buf field must point to an SPX_OPTS structure, which is returned by the service provider.
The t_connect call uses two t_call structures: sndcall and rcvcall.
The t_connect call sends an SPX connection request to the SPX address specified in sndcall.addr. The sndcall.addr.len and sndcall.addr.maxlen fields must be initialized to the size of an ipxAddr_t or equivalent structure. The sndcall.addr.buf field must point to an ipxAddr_t structure. The ipxAddr_t structure must be initialized to the server's IPX address.
If the rcvcall structure is passed in t_connect, the server's address and connection information is returned. If a rcvcall structure is passed, maxlen, len, and buf must be set appropriately to receive the ipxAddr_t and SPX_OPTS structures. The server's IPX address is returned in the rcvcall.addr.buf field. The server's connection ID and allocation number is passed back in the rcvcall.opt.buf field.
The state after a successful connection establishment is T_DATAXFER for both the client and server. The state after an unsuccessful connection establishment is T_BND.
The t_listen call works as specified in t_listen(NET), with the following additions:
The udata fields in the t_call structure are not used but must be initialized. Set the udata.len and udata.maxlen fields to 0, and set the udata.buf to NULL. A value is placed in the sequence field when the t_listen receives a connection request. The application uses the sequence value to reject the connection request with a t_snddis call or to accept the connection request with a t_accept.
The addr.len and addr.maxlen fields must be initialized to the size of an ipxAddr_t structure. The addr.buf field must point to an ipxAddr_t structure.
The opt.len and opt.maxlen fields must be initialized to the size of an SPX_OPTS structure. The opt.buf field must point to an SPX_OPTS structure.
If t_listen returns successfully, call.addr points to an ipxAddr_t structure that contains the net, node, and sock of the remote transport endpoint requesting the connection. The net, node, and sock are in high-to-low byte order. The call.opt points to an SPX_OPTS structure that contains the remote transport endpoint's connection ID and allocation number. The call.udata contains nothing.
The t_listen call retrieves any connection requests residing on the stream head. The t_listen call can function synchronously or asynchronously.
SPX ensures that each connection indication is unique by dropping any duplicate connection requests. A duplicate request is a request that comes from the same network, node, socket, and source connection ID as a previous request.
When a t_connect call has been received from a client, the SPX server can either accept or reject the connection request.
The client issuing the connection request learns that the connection request has been rejected by retrying the connection request and eventually timing out. This differs from the DOS/SPX/TLI library in that DOS sends terminate connection indication if the application issues a t_snddis after a t_listen return.
This call can be issued only from the T_BND state.
The t_open call works as specified in t_open(NET), with the following additions:
On input, path passes a pointer to the path of the SPX driver. The path is /dev/nspx.
On output, spxInfo receives the SPX protocol information as a t_info structure. The t_open call returns a value greater than or equal to 0 if successful, or -1 if not. If the t_open call is successful, the value returned is a file descriptor that identifies the local transport endpoint. This document uses the variable fd to refer to this value. If t_open returns an error, errno may be set to:
SPX may be used either synchronously or asynchronously.
The path and name of the clonable SPX device is /dev/nspx.
The t_open call returns a file descriptor and a TLI information structure (of type t_info) upon the successful return of an open call. Table 4-7, ``t_info structure fields'' describes the fields in the t_info structure.
Table 4-7 t_info structure fields
---------------------------------------------------------
Field Value Description
---------------------------------------------------------
addr 12 The address is 12 bytes and consists
of: network number (4 bytes), node
number (6 bytes), and socket number
(2 bytes).
options 4 SPX supports 4 bytes of options data.
tsdu -1 There is no limit on the amount of
data that can be sent during a
connection.
etsdu -2 Not supported.
connect -2 Not supported.
discon -2 Not supported.
servtype T_COTS The service type is always T_COTS.
SPX is a connection-oriented service
with a disorderly release.
---------------------------------------------------------
t_open changes the state of the service
connection to T_UNBND (unbound).
The t_optmgmt call works as specified in t_optmgmt(NET), with the following additions:
The t_optmgmt call enables the SPX user to set the maximum number of retries for a connection request or for a data unit delivery.
On input, req passes the address of the t_optmgmt structure that contains the requested retry count value for a connection request or for a data unit delivery; ret passes the address of a t_optmgmt structure that contains the granted retry count value.
On output, ret receives the granted retry count value in the t_optmgmt structure.
On completion, the t_optmgmt call returns 0 if successful or -1 if unsuccessful. If t_optmgmt returns an error, t_errno may be set to one of the following:
This call has one negotiable option. It enables the SPX user to set the maximum number of retries when the SPX driver tries to deliver data reliably to the opposite transport endpoint.
The req.opt.buf field and ret.opt.buf field must point to an SPX_OPTMGMT structure.
The SPX driver does not support spxo_watchdog_flag or spxo_min_retry_delay.
The value in spxo_retry_count becomes the new maximum number of retries unless its value exceeds the maximum retry value in spx_tune.h (the SPX_MAX_TRETRIES parameter).
The flags field in the t_optmgmt
structure must be initialized to the appropriate value.
The flags supported are:
T_NEGOTIATE, T_CHECK,
and T_DEFAULT.
The t_rcv call works as specified in t_rcv(NET), with the following additions:
The T_EXPEDITED flag is never set. On input, flags passes the address of an integer that indicates whether there is more data to receive. SPX does not support the T_EXPEDITED flag.
The SPX watchdog in the SPX driver prevents transport endpoints from blocking forever waiting for a packet. For example, suppose a local transport endpoint blocks waiting for an incoming packet. While the local transport blocks, the remote transport endpoint goes down before sending the packet. In this situation, the local transport endpoint could block forever. The SPX watchdog solves this problem by periodically checking all active connections. If the SPX watchdog determines that the remote transport endpoint is no longer participating in the connection, the SPX watchdog generates a disconnect indication, causing t_rcv to return with an error. (See ``t_rcvdis'' for more information.)
SPX does flow control. If SPX determines that the remote endpoint is sending data faster than the application can receive the data, SPX sends a packet notifying the remote endpoint to stop sending data. When the application receives all of the data queued for it, SPX notifies the remote endpoint to begin sending data again.
t_rcv can be called only if SPX is in the T_DATAXFER state. This state does not change on successful completion of the call.
The t_rcvdis call works as specified in t_rcvdis(NET), with the following additions:
On completion, the t_rcvdis call
returns 0 if successful or -1 if unsuccessful.
If any of the following conditions occur,
a disconnect indication is generated and
passed to the stream head.
The reason integer of the
t_discon structure (described below)
is set accordingly in the following situations:
Alternatively, the SPX driver could not reliably deliver the data or connection request. The remote transport endpoint does not acknowledge transmissions.
Alternatively, SPX has tried a number of times to allocate memory and has failed.
The SPX driver does not use the udata field in the t_discon structure. SPX does not support the transmission of user data with a disconnect request.
Upon receiving a disconnect request, SPX sets the stream to the T_IDLE state.
The t_snd call works as specified in t_snd(NET), with the following additions:
A known problem with TLI is its inability to notify the user within a reasonable amount of time that a call to t_snd has failed. The t_snd call does not check for disconnect indications before and after doing the t_snd. If the remote transport endpoint has gone down or fails to acknowledge the transmitted data, the SPX driver generates a disconnect indication and changes the state of the local transport endpoint to T_IDLE. Following the TLI specification, any t_snd issued in the T_IDLE state is dropped by the SPX driver. This indication is not detected by the application until a routine other than t_snd is called. The application should check the return code in the disconnect indication to make sure it is TLI_SPX_CONNECTION_TERMINATED.
The following errors can occur during the send request:
Alternatively, the size of the data request header or data portion of the message received by SPX was invalid (too small or too large). This transport endpoint is no longer valid and must be closed.
All data is sent on a first-come, first-served basis. The application must take care not to close the connection before all the data is sent. The t_snd call returns before the data has actually been transmitted.
When writing an application that communicates with an unknown machine type, consider the byte order of data sent. See ``Network byte ordering'' for more information.
During the connection, SPX uses the most recent round trip delay multiplied by 1.5 as the timeout for the next transmission.
The T_MORE flag is supported by SPX as follows:
TLI breaks any large send request into a sequence of maximum packets for the given connection.
The SPX driver does not send empty SPX packets. If nbytes is 0, no data or packet is sent.
t_snd can be called only if
SPX is in the T_DATAXFER state.
If errors occur, the state changes to T_IDLE.
The t_snddis call works as specified in t_snddis(NET), with the following additions:
SPX does not support the TLI concept of an orderly release. The correct procedure for aborting or terminating a connection is to use the combination of t_snddis and t_rcvdis.
A t_snddis call sends a connection termination request to the remote transport endpoint. This call is used to abort or break a connection. t_snddis generates an SPX terminate connection request, and releases all outstanding data messages on both the local and remote transport endpoints. The terminate request is not delivered reliably and only one terminate request is sent. After an application calls t_snddis, the application can call t_unbind and t_close without waiting.
SPX does not allow sending address options or user data along with a disconnect request.
The correct procedure for terminating an SPX connection is for both transport endpoints to correlate the moment that the connection is no longer needed, then call t_snddis and t_rcvdis to terminate the connection.
Regardless of the outcome of the call to t_snddis, the transport endpoint remains in the T_UNBND state.
The t_unbind call works as specified in t_unbind(NET), with the following additions:
This call releases the socket number used by the transport endpoint for future use. This allows the callng process to bind to a new socket number.
This call places the transport endpoint
in the T_UNBND state.
Using the SAP protocol
Novell networks consist of clients and servers.
Servers provide clients on the network with a variety of services:
A network needs a method of advertising available services. NetWare uses the Service Advertising Protocol (SAP). SAP allows service nodes such as file servers, print servers, and application servers to advertise their services and addresses.
With SCO IPX/SPX, you can use the Service Advertising Protocol daemon (SAPD) to advertise an application's services. Applications using SAPD's services are called application servers because they have services to offer clients on the network. These applications are loaded on computers running NetWare or SCO IPX/SPX. You can also query SAPD to initiate a session between an advertising service and a client application.
To use SAPD, you should already
be familiar with the IPX protocol
and understand IPX addresses.
SAP services
SAP provides a way for service nodes
to register their services and addresses
in a Server Information table.
This table is maintained by SAPD.
Clients can query this table
for available services and their addresses.
SAP is always up to date because it supports the dynamic registering of services. As services are booted up, they register themselves using SAP. When they are brought down, they use SAP to indicate that their services are no longer available. SAP removes those services from the Server Information table.
NetWare clients cannot initiate a session with a service without first knowing the address of that service. SAP provides methods for obtaining these addresses. Clients can either query a SAP agent or the bindery of a file server.
All NetWare file servers and routers have a SAP agent. The SAP agent for SCO IPX/SPX is SAPD. SAP agents:
SCO IPX/SPX can be used to query a NetWare server's bindery, but a general programmatic interface to Novell's bindery or NetWare Directory Services (NDS) is not currently part of IPX/SPX. Information regarding the structure of the bindery or NDS queries and responses can be obtained from Novell.
The Service Advertising Protocol daemon SAPD
When the Service Advertising Protocol daemon
(SAPD) is initialized by
the NetWare Protocol Stack Daemon (NPSD),
SAPD binds to the IPX socket 0x0452,
and sends a request for all SAP agents
to send their server information.
SAPD then builds a Server Information
table from the returned packets.
Some of the more pertinent fields in the Server Information table of the SAP Agent are:
The network number is the number associated with the cabling system the server is attached to. For SCO IPX/SPX file servers or application servers loaded on such file servers, the network number is the file server's internal network number.
The node number is the station number of the network board installed in the server. For SCO IPX/SPX file servers, this number is always set to 0x000000000001. The SCO IPX/SPX server is the only node on the network (the network is the server's internal network number).
The socket number is the number of the socket that the server binds to when it is initialized and is ready to provide service by listening on this socket.
If no server information is received within the three minutes for a particular server, the SAP agent presumes that the server is down and removes the server from the table. SAPD then broadcasts a SAP packet to indicate that the server is down.
SAPD handles the ``Time since change'' field in a slightly different way from other NetWare SAP agents. SAPD's timeout interval for the ``Time since change'' field is tunable in a header file. The current default is four minutes.
Every minute, SAPD sends local broadcasts of all its server information. When a new server sends out a SAP packet saying that it is available, SAPD verifies that this server is not in its Server Information table. SAPD then adds this server to its Server Information table and echoes this information to all connected networks.
When a SCO IPX/SPX server is initialized, the server
sends a special SAP packet to SAPD.
This special SAP packet tells SAPD
which socket to use to inform the SCO IPX/SPX
server about new server information.
Configuring and testing SAPD
For SAPD to be loaded and initialized,
the server must be running the NetWare
protocol stack daemon (NPSD).
The NPSD initializes the
NetWare IPX/SPX protocols and sets up the stack.
See the Networking Guide for instructions
on loading and configuring NPSD.
SAPD has two tunable parameters in /etc/ipx.d/NPSConfig which can be used to observe SAPD activity:
SCO IPX/SPX is provided with a command, track,
that can be used to view SAPD traffic and
verify that applications are communicating with
and being advertised by SAPD.
This facility acts similarly to the native NetWare
TRACK ON and TRACK OFF facilities.
See the Networking Guide for more
information on using track.
SAP packets
SAP is implemented using Novell's
IPX datagram protocol.
The SAP information for querying
or broadcasting servers becomes the data portion
of the IPX packet.
Some of the fields in the packet are byte-order sensitive, and the data must be sent in high-to-low byte order. See ``Network byte ordering'' for more information.
The structure of a SAP packet is described in Table 4-8, ``Fields in a SAP packet''.
Table 4-8 Fields in a SAP packet
-------------------------------------------------------- Offset Field Type* Byte order -------------------------------------------------------- 0 IPX header uint8[30] N/A 30 SAP operation uint16 high-to-low 32 SAP data varies -------------------------------------------------------- * A uint8 is an unsigned char. A uint16 is an unsigned short.
SAP query packets are used to determine the identities of servers on the network. Client applications for SCO IPX/SPX use SAP queries to obtain the addresses of available servers. With the address, the client application can establish a session with a server.
Application servers usually do not use SAP queries. However, if the application server needs to establish a session with another server, the application server would use a SAP query to obtain the address of another server.
The structure of a SAP query packet is described in Table 4-9, ``SAP query packet structure''.
Table 4-9 SAP query packet structure
-------------------------------------------------------- Offset Field Type* Byte order -------------------------------------------------------- 0 IPX header uint8[30] N/A 30 SAP query type uint16 high-to-low 32 Server Type uint16 high-to-low -------------------------------------------------------- * A uint8 is an unsigned char. A uint16 is an unsigned short.
A General Service Query (SAP_GSQ 0x0001) is used to query all local servers and routers. The query can be for any server or for a server of a particular type.
A Nearest Server Query (SAP_NSQ 0x0003) is used to query for the nearest server. The query can be for all servers or for all servers of a particular type.
There are two types of SAP responses: a General Service Response and a Nearest Server Response. Each type of response packet has a SAP response type and at least one SAP SIS (Server Information Structure). The packet can have up to seven SISs.
The structure of a SAP response packet is described in Table 4-10, ``SAP response packet structure''.
Table 4-10 SAP response packet structure
---------------------------------------------------------------- Offset Field Type* Byte order ---------------------------------------------------------------- 0 IPX header uint8[30] N/A 30 Response type uint16 high-to-low 32 Server Information Structures SIS[7] high-to-low ---------------------------------------------------------------- * A uint8 is an unsigned char. A uint16 is an unsigned short.
The General Service Response packet
is sent to answer a General Service Query packet.
SAPD responds to all General Service Query packets
on behalf of all SCO IPX/SPX servers
and all application servers that use SAPD.
The Nearest Server Response packet is sent to answer a Nearest Server Query packet. This packet usually contains just one SIS. SAPD finds the nearest server of the requested type. If SAPD determines it is the best source for information about the server, it responds to the query.
Each Server Information Structure contains information for a particular advertising server. The structure of an SIS is described in Table 4-11, ``The format of a Server Information Structure''.
Table 4-11 The format of a Server Information Structure
-------------------------------------------------------- Offset Field Type* Byte order -------------------------------------------------------- 0 Server type uint16 high-to-low 2 Server name char[48] N/A 50 Server IPX address uint8[12] high-to-low 62 Intermediate networks uint16 high-to-low -------------------------------------------------------- * A uint8 is an unsigned char. A uint16 is an unsigned short.
Periodic broadcast packets are used to advertise that a service is available and to remove services that are no longer available. When a server first comes up, it sends out one of these packets to let the SAP agents know that its services are now available. The SAP agents use this first broadcast to add the server to their Server Information tables and to echo the new server information to all their networks.
The server then sends out a periodic broadcast every 60 seconds to let the SAP agents know that its services are still available. SAP agents use these broadcasts to keep their Server Information tables up-to-date. Any server or service that does not send a broadcast for 3 minutes is presumed to be ``down''. That server's information is then removed from the SAP agent's table, and the SAP agent sends out a broadcast indicating that the server is down.
When a server is going down, the server sends a broadcast packet with the ``Intermediate networks'' field set to 16. This value signals SAP agents to remove that server from their tables.
A Periodic Broadcast packet has the same format as a General Service Response packet. See ``SAP response packets'' for more information. The fields in a Periodic Broadcast packet are:
Figure 4-2, ``An application server's address'' illustrates such an application server loaded on a SCO IPX/SPX server.

Figure 4-2 An application server's address
Using the values given in
Figure 4-2, ``An application server's address'',
the application server would set the server IPX
address in its Periodic Broadcast packets to:
Server network: 0x00D0C000
Server node: 0x000000000001
Server socket: 0x4002
Accessing SAP
SCO IPX/SPX provides a library interface to SAPD.
The SAPD library includes:
These routines are described in ``Service Advertising Protocol Daemon library''.
The following header files must be included in the order listed in any program that uses the SAPD routines: