Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
7.  Programming With XTI and TLI Advanced XTI/TLI Topics Advanced XTI/TLI Programming Example  Previous   Contents   Next 
   
 

The arguments in Example 7-4 are a number (slot) and a file descriptor (fd). A slot is the index into the global array calls, which has an entry for each transport endpoint. Each entry is an array of t_call structures that hold incoming connect requests for the endpoint.

The do_event module calls t_look(3NSL) to identify the XTI/TLI event on the endpoint specified by fd. If the event is a connect request (T_LISTEN event) or disconnect request (T_DISCONNECT event), the event is processed. Otherwise, the server prints an error message and exits.

For connect requests, do_event scans the array of outstanding connect requests for the first free entry. A t_call structure is allocated for the entry, and the connect request is received by t_listen(3NSL). The array is large enough to hold the maximum number of outstanding connect requests. The processing of the connect request is deferred.

A disconnect request must correspond to an earlier connect request. The do_event module allocates a t_discon structure to receive the request. This structure has the following fields:

struct t_discon {
 	struct netbuf udata;
 	int reason;
 	int sequence;
}

The udata structure contains any user data sent with the disconnect request. The value of reason contains a protocol-specific disconnect reason code. The value of sequence identifies the connect request that matches the disconnect request.

The server calls t_rcvdis(3NSL) to receive the disconnect request. The array of connect requests is scanned for one that contains the sequence number that matches the sequence number in the disconnect request. When the connect request is found, its structure is freed and the entry is set to NULL.

When an event is found on a transport endpoint, service_conn_ind is called to process all queued connect requests on the endpoint, as the following example shows.


Example 7-5 Process All Connect Requests

service_conn_ind(slot, fd)
{
   int i;

	for (i = 0; i < MAX_CONN_IND; i++) {
      if (calls[slot][i] == (struct t_call *) NULL)
         continue;
      if((conn_fd = t_open( "/dev/tivc", O_RDWR,
            (struct t_info *) NULL)) == -1) {
         t_error("open failed");
         exit(15);
      }
      if (t_bind(conn_fd, (struct t_bind *) NULL,
            (struct t_bind *) NULL) == -1) {
         t_error("t_bind failed");
         exit(16);
      }
      if (t_accept(fd, conn_fd, calls[slot][i]) == -1) {
         if (t_errno == TLOOK) {
            t_close(conn_fd);
            return;
         }
         t_error("t_accept failed");
         exit(167);
      }
      t_free(calls[slot][i], T_CALL);
      calls[slot][i] = (struct t_call *) NULL;
      run_server(fd);
   }
}

For each transport endpoint, the array of outstanding connect requests is scanned. For each request, the server opens a responding transport endpoint, binds an address to the endpoint, and accepts the connection on the endpoint. If another connect or disconnect request arrives before the current request is accepted, t_accept(3NSL) fails and sets t_errno to TLOOK. You cannot accept an outstanding connect request if any pending connect request events or disconnect request events exist on the transport endpoint.

If this error occurs, the responding transport endpoint is closed and service_conn_ind returns immediately, saving the current connect request for later processing. This activity causes the server's main processing loop to be entered, and the new event is discovered by the next call to poll(2). In this way, the user can queue multiple connect requests.

Eventually, all events are processed, and service_conn_ind is able to accept each connect request in turn.

Asynchronous Networking

This section discusses the techniques of asynchronous network communication using XTI/TLI for real-time applications. The SunOS platform provides support for asynchronous network processing of XTI/TLI events using a combination of STREAMS asynchronous features and the non-blocking mode of the XTI/TLI library routines.

Networking Programming Models

Like file and device I/O, network transfers can be done synchronously or asynchronously with process service requests.

Synchronous networking proceeds similar to synchronous file and device I/O. Like the write(2) interface, the send request returns after buffering the message, but might suspend the calling process if buffer space is not immediately available. Like the read(2) interface, a receive request suspends execution of the calling process until data arrives to satisfy the request. Because there are no guaranteed bounds for transport services, synchronous networking is inappropriate for processes that must have real-time behavior with respect to other devices.

Asynchronous networking is provided by non-blocking service requests. Additionally, applications can request asynchronous notification when a connection might be established, when data might be sent, or when data might be received.

Asynchronous Connectionless-Mode Service

Asynchronous connectionless mode networking is conducted by configuring the endpoint for non-blocking service, and either polling for or receiving asynchronous notification when data might be transferred. If asynchronous notification is used, the actual receipt of data typically takes place within a signal handler.

Making the Endpoint Asynchronous

After the endpoint has been established using t_open(3NSL), and its identity established using t_bind(3NSL), the endpoint can be configured for asynchronous service. Use the fcntl(2) interface to set the O_NONBLOCK flag on the endpoint. Thereafter, calls to t_sndudata(3NSL) for which no buffer space is immediately available return -1 with t_errno set to TFLOW. Likewise, calls to t_rcvudata(3NSL) for which no data are available return -1 with t_errno set to TNODATA.

Asynchronous Network Transfers

Although an application can use poll(2) to check periodically for the arrival of data or to wait for the receipt of data on an endpoint, receiving asynchronous notification when data arrives might be necessary. Use ioctl(2) with the I_SETSIG command to request that a SIGPOLL signal be sent to the process upon receipt of data at the endpoint. Applications should check for the possibility of multiple messages causing a single signal.

In the following example, protocol is the name of the application-chosen transport protocol.

#include <sys/types.h>
#include <tiuser.h>
#include <signal.h>
#include <stropts.h>

int				fd;
struct t_bind				*bind;
void				sigpoll(int);

	fd = t_open(protocol, O_RDWR, (struct t_info *) NULL);

	bind = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
	...     /* set up binding address */
	t_bind(fd, bind, bin

	/* make endpoint non-blocking */
	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

	/* establish signal handler for SIGPOLL */
	signal(SIGPOLL, sigpoll);

	/* request SIGPOLL signal when receive data is available */
	ioctl(fd, I_SETSIG, S_INPUT | S_HIPRI);

	...

void sigpoll(int sig)
{
	int					flags;
	struct t_unitdata					ud;

	for (;;) {
		... /* initialize ud */
		if (t_rcvudata(fd, &ud, &flags) < 0) {
			if (t_errno == TNODATA)
				break;  /* no more messages */
			... /* process other error conditions */
	}
	... /* process message in ud */
}
 
 
 
  Previous   Contents   Next