Chapter 4: Developing applications over IPX/SPX using TLI

Table of contents

Chapter 4

Developing applications over IPX/SPX using TLI

SCO IPX/SPX provides a means of connecting SCO systems and NetWare networks. A library of function calls and data structures supports:

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.

Internet Packet Exchange (IPX)

IPX is a datagram (connectionless) service protocol that allows individual packets to be sent to and received from user processes. It does not support the concept of a connection or reliable delivery. However, guaranteed services (like SPX) can be built on top of IPX. IPX is used in situations where a guaranteed service is not required or where an occasional lost packet is not critical.

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)''. 

t_alloc
allocate a library structure

t_bind
bind an address to a transport endpoint

t_close
close a transport endpoint

t_error
produce an error message

t_free
free a library structure

t_getinfo
get protocol-specific service information

t_getstate
get the current state

t_look
look at the current event on a transport endpoint

t_open
establish a transport endpoint

t_optmgmt
manage options for a transport endpoint

t_rcvudata
receive a data unit

t_rcvuderr
receive a unit data error indication

t_sndudata
send a data unit

t_sync
synchronize the transport library

t_unbind
disable a transport endpoint

The structures used by the TLI interface to IPX are:


Sequence Packet Exchange (SPX)

SPX is a connection-based, reliable, sequenced transport protocol which provides:

guaranteed packet delivery
ensuring that packets are received in order by the destination endpoint

flow control
regulating the speed at which packets are sent and received by both the sending and receiving processes

The TLI (Transport Layer Interface) library provides routines with which to access SPX. SPX supports the following calls from the TLI library:

t_accept
accept a connect request

t_alloc
allocate a library structure

t_bind
bind an address to a transport endpoint

t_close
close a transport endpoint

t_connect
establish a connection with another transport user

t_error
produce an error message

t_free
free a library structure

t_getinfo
get protocol-specific service information

t_getstate
get the current state

t_listen
listen for a connect request

t_look
look at the current event on a transport endpoint 

t_open
establish a transport endpoint

t_optmgmt
manage options for a transport endpoint 

t_rcv
receive data or expedited data sent over a connection

t_rcvdis
retrieve information from disconnect

t_snd
send data or expedited data over a connection

t_snddis
send user-initiated disconnect request

t_sync
synchronize transport library

t_unbind
disable a transport endpoint
``Using the SPX protocol'' describes how to use these routines to access SPX.

The structures used by the TLI interface to SPX are:


Service Advertising Protocol (SAP)

SAP is a method by which networks can advertise available network services. SAP allows service nodes (such as file servers, print servers, and application servers) to advertise their services and addresses. The Service Advertising Protocol daemon (SAPD) uses the SAP protocol to advertise these services.

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.

SCO IPX/SPX programming issues

Developers working on applications which use services offered through SCO IPX/SPX should understand certain characteristics common to NetWare networks:


A sample program is provided to illustrate these ideas. The file /usr/src/cmd/tispx/tispx.c contains source for a sample client/server program, tispx. This program shows how to use the data structures and function calls to communicate over the IPX and SPX protocols.

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. 

Table 4-1 IPX address fields

 ----------------------------------------------
 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.

network number
is a 4-byte number associated with the cabling system to which the server is attached.

For SCO IPX/SPX servers or application servers loaded on such file servers, the network number is the server's internal network number.

node number
is a 6-byte number that identifies the network adapter card in the computer. This node address is the hardware address assigned to the network adapter card by it's vendor.

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.

socket number
is a 2-byte number that identifies the process address in the computer. The process can use either a well-known, static socket number or obtain a dynamic socket number when the process binds to IPX. For more information about static and dynamic socket numbers, see ``Socket numbers''.

IPX addresses are represented by ipxAddr_t structures. The ipxAddr_t structure has the following format:

struct {
unsigned char net[ 4 ];
unsigned char node[ 6 ];
unsigned char sock[ 2 ];
} ipxAddr_t;

The types of addresses are: 

source address
The address of the sender of the packet. By definition, the sender is aware of its address.

destination address
The address of the recipient of the packet. The sender has to obtain the address of the recipient. The procedure for obtaining a destination address is described in ``Obtaining a destination address''.



Obtaining a destination address

An application can obtain the destination address of a server by:

querying SAPD
for the address of the recipient. ``Using the SAP protocol'' describes this procedure.

scanning a file server bindery
for the destination address. This method assumes that you have already established a connection to a NetWare file server. ``Using the SAP protocol'' describes this procedure.

creating a mapping table
that maps a server name to an address.

Socket numbers

IPX uses the network number and node number to identify the computer that receives the packet. IPX uses the socket number to identify the process that receives the packet.

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:

dynamic socket numbers
are assigned by IPX when an application binds to a transport provider with t_bind. A dynamic socket number is an unused socket number returned by the IPX driver and is guaranteed to be a unique unused number among the IPX endpoints. IPX keeps track of which socket number is bound to which transport endpoint. Dynamic socket numbers range from 0x4000 to 0x4FFF.

static socket numbers
can be requested in the req t_bind structure. If the socket number is unused, it is granted and returned in the ret t_bind structure. A static socket number is granted by IPX when an application requests a particular socket number and that particular socket number has not already been assigned to another process. Static socket numbers are in the range of 0x8000 to 0xFFFF, and are assigned by Novell. Contact Novell for a static socket number.
Procedures for obtaining a static socket number are described in ``Obtaining a static socket number''. Procedures for obtaining a dynamic socket number are described in ``Obtaining a dynamic socket number''. 

Obtaining a static socket number

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:

  1. allocates an ipxAddr_t structure.

  2. sets the socket value in the ipxAddr_t structure before making the t_bind call.

  3. ensures that the socket number is passed in high-to-low byte order.

  4. allocates a t_bind structure.

  5. initializes the structure's fields. (The req.addr.buf field must point to the ipxAddr_t structure allocated in step 1.)

  6. makes the t_bind call by passing the file descriptor returned by the t_open call and by passing the address of the t_bind structure allocated in step 3 as both the req and the ret values.

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. 

Obtaining a dynamic socket number

There are two methods by which an application obtains a dynamic socket number:

Novell object types

Services on a network are identified using Novell object types. Table 4-2, ``Novell object types'' lists some of Novell's common object types. If you are developing an advertising application server, contact Novell for a unique object type for your server. 

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
 -----------------------------------------------

Using the IPX protocol

Applications access IPX using(TLI (the Transport Layer Interface). This chapter assumes you are familiar with NetWare communication processes and TLI. For information on these topics, see:

Sequence of TLI functions for IPX

To access IPX, a UNIX process uses the following TLI functions in the order listed:

  1. t_open( fd )

  2. t_bind( fd, &bind, &bind )

  3. t_optmgmt( fd, &req, &ret )

  4. t_sndudata( fd, &ud ) or t_rcvudata( fd, &ud, &flags )

  5. t_unbind( fd )

  6. t_close( fd )

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:

IPX packet structure

The structure of an IPX packet is identical to the structure of a Xerox Network Standard (XNS) packet. The packet consists of a 30-byte header followed by 0 to 546 bytes of data. The minimum packet size is 30 bytes (the header only); the maximum packet size is 576 bytes (the header and 546 bytes of data). The content and structure of the data portion are entirely the responsibility of the application using IPX and can take any format.

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:

Checksum
The IPX driver sets this field to 0xFFFF. A value of 0xFFFF specifies that no checksumming is performed.

Length
The IPX driver sets this field to the length of the complete IPX packet (the header plus the data). The packet can range from 30 bytes (the header only) to 576 bytes (the header plus 546 bytes of data).

Transport control
The IPX driver sets this field to 0 before sending the packet. Each router increments the field before sending the packet on. If the packet passes through 16 routers, the 16th router discards the packet.

Packet type
The user application sets this field. Applications that use IPX should pass a packet type of 0 to indicate a regular IPX packet type. If the application is using a protocol that has been built on top of IPX, the application should pass the packet type of the protocol.

Destination address
The user application sets this field. The destination address is a 12-byte ipxAddr_t structure.

Source address
The IPX driver sets this field to the source address of the sender. The source address is a 12-byte ipxAddr_t structure.

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. 

Table 4-4 IPX packet types

 ----------------------------------------------
 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
 ----------------------------------------------

Accessing IPX

The following TLI routines are used to access the IPX protocol:

t_bind
bind an address to a transport endpoint

t_close
close a transport endpoint

t_open
establish a transport endpoint

t_optmgmt
manage options for a transport endpoint

t_rcvudata
receive a data unit

t_sndudata
send a data unit

t_unbind
disable a transport endpoint

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.

t_bind

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). 

t_open

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).
 -------------------------------------------------------------------------


t_optmgmt

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.


NOTE: The local socket number are valid only if this local endpoint has already been bound.

t_rcvudata

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.

t_sndudata

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.

t_unbind

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:


Sequence of TLI functions for SPX

Applications that use SPX can be either server applications or client applications. The application type determines the sequence and the types of TLI calls made to access SPX.

Server applications need to:

Client applications need to:

Procedures for both server and client applications are presented below.

Server application calling sequence

A synchronous server application must:

  1. Open the SPX driver (/dev/nspx) using the t_open call. The t_open call returns a file descriptor (fd).

  2. Bind fd to a well-known socket number that client connection requests will arrive on using the t_bind call.

  3. Obtain a second file descriptor (fd2) using the t_open call with the device set to the SPX driver (/dev/nspx).

  4. Bind fd2 to a dynamic socket number using the t_bind call.

  5. Listen for incoming connection requests using the t_listen call.

  6. Fork a child upon receiving a connection request.

  7. The parent should close fd2 and return to step 3. The parent continues looping through steps 3 to 7 until the parent exits (skip to step 14). The forked child performs steps 8 through 13.

  8. The forked child issues a t_accept to accept the connection request using t_accept(fd, fd2, call).

  9. The forked child should close fd with t_close.

  10. The forked child uses t_snd or t_rcv to send or receive data on fd2.

  11. The forked child listens for or sends a disconnection indication using t_rcvdis or t_snddis.

  12. On exiting, the forked child unbinds fd2 using a t_unbind call.

  13. On exiting, the forked child closes fd2 using a t_close call.

  14. On exiting, the parent unbinds fd using a t_unbind call.

  15. On exiting, the parent closes fd using a t_close call.

Client application calling sequence

A synchronous client application must:

  1. Open the SPX driver (/dev/nspx) using the t_open call. The t_open call returns a file descriptor (fd).

  2. Obtain the address of the server to which to connect. The method for obtaining the address is up to the client application. ``IPX addresses'' describes procedures for obtaining addresses.

  3. Bind to a static or dynamic socket using a t_bind call.

  4. Send a connection request to the server using a t_connect call.

  5. Use t_snd to send or t_rcv to receive data on fd.

  6. Listen for or send a disconnection request. Use t_rcvdis to receive a disconnect request or t_snddis to send a disconnect request.

  7. On exiting, use the t_unbind call to close the file descriptor obtained in step 1.

  8. On exiting, use the t_close call to close the file descriptor obtained in step 1.

SPX driver characteristics

The SPX driver is a STREAMS driver. Its general characteristics are described below.

Transport endpoint states

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. 

Connection requests

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.

Unexpected terminate connection requests

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

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.

Flow control on incoming data

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.

Flow control on outgoing data

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:

SPX packet structure

An SPX packet consists of a 42-byte SPX header followed by 0 to 534 bytes of data. The minimum packet size is 42 bytes (the header only) and the maximum size is 576 bytes (header plus 534 bytes of data). In special cases, larger data packets can be sent.

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:

Checksum
The SPX driver sets this field to 0xFFFF. This value specifies that the checksum is not used.

Length
The SPX driver sets this field to the length of the complete SPX packet (42 to 576 bytes).

Transport control
The SPX driver sets this field to 0 before sending the packet. Each router increments the field before sending the packet on. If the packet passes through 16 routers, the 16th router discards the packet.

Packet type
The SPX driver automatically fills in this field.

Destination address
The application must set this field when the application is establishing an SPX connection. The destination address is a 12-byte ipxAddr_t structure. See ``IPX addresses'' for more about the ipxAddr_t structure.

Source address
The SPX driver fills in this field with the source address of the sender. The source address is a 12-byte ipxAddr_t structure. See ``IPX addresses'' for more about the ipxAddr_t structure.

Connection control
SPX sets this field to indicate whether the packet is a system or application packet.

Data stream type
SPX sets this field to indicate the type of data found in the packet. SPX uses 0xFE to indicate an End-of-Connection packet and 0xFF to indicate an End-of-Connection-Acknowledgment. All other values in this field are ignored by SPX.

Source connection ID
SPX sets this field to the connection identification number that it assigned to the local transport endpoint.

Destination connection ID
SPX sets this field to the connection identification number that it assigned to the remote transport endpoint.

Sequence number
SPX sets this field to the number of packets exchanged in one direction on the connection. Each side of the connection keeps its own count. The number wraps to 0x0 after reaching 0xFFFF.

Acknowledge number
SPX sets this field to indicate the sequence number of the next packet SPX expects to receive. SPX drops any packet with a sequence number less than the specified acknowledge number (the packet is a duplicate). When SPX receives a duplicate packet, SPX re-sends its acknowledgment of the duplicate packet.

Allocation number
SPX uses this field to implement flow control between communicating applications. SPX only sends packets until the local sequence number equals the allocation number of the remote partner. The allocation number minus the acknowledge number indicates the number of listen buffers outstanding in one direction on the connection.

Initializing SPX

The SPX driver's link to IPX is created and held together by the NetWare Protocol Stack Daemon (NPSD). If NPSD dies, the architecture that links IPX and SPX is destroyed; SPX then reports errors and drops all outbound data. Disconnect indications are generated to all local endpoints. Use the streams trace command, strace(ADM), to monitor errors.

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:

/dev/nspxd
the controlling node for NPSD

/dev/nspx
the node that applications open to access SPX
The daemon node, /dev/nspxd, has the same device number as /dev/nspx, except that the daemon node is minor device 0 and /dev/nspx is a clonable device. The daemon node is readable and writable only by root, but the application node (/dev/nspx) is readable and writable by all users.

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:

t_accept
accept a connect request

t_bind
bind an address to a transport endpoint

t_close
close a transport endpoint

t_connect
establish a connection with another transport user

t_listen
listen for a connect request

t_open
establish a transport endpoint

t_optmgmt
manage options for a transport endpoint

t_rcv
receive data or expedited data sent over a connection

t_rcvdis
retrieve information from disconnect

t_snd
send data or expedited data over a connection

t_snddis
send user-initiated disconnect request

t_unbind
disable a transport endpoint

The following header files must be included in the order listed in any program that uses the TLI interface to SPX:

t_bind

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.

t_connect

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.

t_listen

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.

t_open

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:

ENONET
The STREAMS facility requires that a daemon be run in the background to build the protocol stack before SPX can be used. This daemon links IPX to the Ethernet driver, then links SPX to IPX. If NPSD has not been run, all attempts to open SPX fail with this error.

ESRCH
SPX has not been initialized.

ENOSPC
The SPX_MAX_CONNECTIONS parameter in the tunable file spx_tune.h sets the maximum number of simultaneous endpoints. If that number is reached, all attempts to open SPX fail with this error.

ENOSR
If no STREAMS resources are available, all attempts to open SPX fail with this error.

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).

t_optmgmt

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:

TBADOPT
The size of the structure was less than the size of an SPX_OPTMGMT structure or there has been an internal SPX/TLI error.

TBADFLAG
The specified flag is invalid.

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.

t_rcv

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. 

t_rcvdis

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:

TLI_SPX_CONNECTION_FAILED
The remote transport endpoint fails to acknowledge any transmission. This is generated by the SPX watchdog after failing to connect to the remote transport endpoint.

Alternatively, the SPX driver could not reliably deliver the data or connection request. The remote transport endpoint does not acknowledge transmissions.

ENOSTR
The SPX driver has tried the maximum number of times to send data to the stream head. Each try has been unsuccessful. This is usually caused by a very slow or deadlocked receiving local endpoint. (The number of retries is a tunable parameter in the spx_tune.h file.)

Alternatively, SPX has tried a number of times to allocate memory and has failed.

TLI_SPX_CONNECTION_TERMINATED
No error occurred. An SPX terminate connection packet was received from the remote transport endpoint.

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.


NOTE: A transmission error or a disconnect indication can arrive at any moment from the remote transport endpoint.

t_snd

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:

EPROTO
The data request was issued from a state other than T_DATAXFER. This transport endpoint is no longer valid and must be closed.

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.

These errors lock the stream and disable the local transport endpoint. Only errno is set; t_errno is not affected.

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:


If the application sets the T_MORE flag when calling t_snd, the EOF bit is not set in the SPX packet header.

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.

t_snddis

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.

t_unbind

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:

file servers
provide clients with file services, for example, reading and writing to operating system files.

application servers
provide clients with application-level services, for example, reading and writing to a database.

login servers
provide clients with the ability to act as terminals for the server's native operating system.
SCO IPX/SPX allows SCO systems to act as servers on Novell networks. IPX/SPX servers can provide clients with both application and file services. The default configuration provides clients with login 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.


NOTE: Updates to the Server Information table are not immediate.

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.

SAP agents

All NetWare file servers and routers have a SAP agent. The SAP agent for SCO IPX/SPX is SAPD. SAP agents:

All services are grouped together according to the types of services. Depending upon the type of query, a SAP agent returns one of the following: The SAP agent provides faster access to information about types of servers than does the bindery.

NetWare bindery queries

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:



Server name
Contains the name of a server that provides a service (such as file, printing, database management, archiving).

Server address
Contains the server's full IPX address: network number, node number, socket number.

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.

Server type
Contains the object type of the service. See ``Novell object types'' for more about Novell object types.

Hops to server
Contains the number of routers that must be crossed to access the server.

Time since change
Used to remove servers that go down unexpectedly without sending a "going down" packet. Every time information is received concerning a server, the field is reset. The field decrements every two seconds and times out after three minutes.

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:

sap_error_out
specifies the file or device that to be used for logging SAPD-generated error messages. The default is /etc/ipx.d/sap.error.

sap_standard_out
specifies the file or device that receive all of the messages that SAPD encounters while running. The default is /dev/console.

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.

IPX header
is 30 bytes and contains fields for: checksum, length, transport control, packet type, destination network, destination node, destination socket, source network, source node, source socket. For more information about the IPX header, see the Networking Guide or ``Using the IPX protocol''.

SAP operation
determines the format of the rest of the packet. This field supports five query/response types:

SAP data
varies in length and information depending upon the SAP operation. For example, query packets have 2 bytes of SAP data, whereas a response packet can have up to 448 bytes of SAP data.

SAP query packets

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.

SAP query type
This field is set to 0x0001 for a General Service Query (SAP_GSQ) and to 0x0003 for a Nearest Service Query (SAP_NSQ).

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.

Server type
This field follows the SAP Query Type field and is used to differentiate the types of servers. Server types are bindery object types and are assigned by Novell. See ``Novell object types'' for more about Novell object types.


SAP response packets

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.

Response Type
is set to 0x0002 (SAP_GSR) for a General Service Response or to 0x0004 (SAP_NSR) for a Nearest Server Response.

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.

Server Information Structure
contains an array of up to seven SISs. The first structure in the packet begins at offset 32. The number of Server Information Structures that are passed can be determined by the length of the IPX packet. Subtract 32 from the length of the packet (30 for the IPX header and 2 for the response type). Then divide the remainder by the size of the Server Information Structure (64).

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.

Server type
contains the object type of the advertising server. See ``Novell object types'' for more about Novell object types.

Server name
contains the name of the advertising server (up to a 48-character string)

Server IPX address
is the IPX address of the server and contains three fields: network, node, and socket. See ``IPX addresses'' for more about IPX addresses.

Intermediate networks
indicates the number of routers that exist between the client and the server. This is equivalent to the hop count.

Periodic information broadcast packets

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:

Response type
can be set to either SAP_PIB (0x0002) or SAP_GSR (0x0002).

Server Information Structure
contains the IPX address (network, node, and socket) of the server being advertised. A Periodic Broadcast packet always contains exactly one SIS (Server Information Structure).

Server network
contains the network number of the server. For application servers loaded on SCO IPX/SPX servers, the network number is the file server's internal network number.

Server node
contains the node number of the server. For application servers loaded on SCO IPX/SPX servers, the node number is always 0x000000000001.

Server socket
contains the socket number that the application server has acquired to service clients. Application servers should acquire two socket numbers, one for advertising and one for servicing client connection requests.

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:

ispx_advertise
advertises and unadvertises a network service provider

ispx_get_address
determines the network number of a given named server

ispx_service_query
performs a local query of a NetWare subnet for advertised network services

ispx_nsrvr_rqst
performs a local query of a NetWare subnet for advertised network services.


NOTE: The ispx_nsrvr_rqst function is obsolescent and is included in order to maintain backwards compatibility with previous releases. Developers are encouraged to use the ispx_service_query call when writing new applications.

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:

For more about IPX/SPX

The following books may provide additional useful information for developers of IPX/SPX applications: