Network Interface Guide

Data Transfer

After a user has bound an address to the transport endpoint, datagrams can be sent or received over the endpoint. Each outgoing message carries the address of the destination user. XTI/TLI also lets you specify protocol options to the transfer of the data unit (for example, transit delay). Each transport provider defines the set of options on a datagram. When the datagram is passed to the destination user, the associated protocol options can be passed, too.

Example 3-2 illustrates the data transfer phase of the connectionless mode server.

Example 3-2 Data Transfer Routine

	if ((ud = (struct t_unitdata *) t_alloc(fd, T_UNITDATA,T_ALL))
         == (struct t_unitdata *) NULL) {
      t_error("t_alloc of t_unitdata struct failed");
   if ((uderr = (struct t_uderr *) t_alloc(fd, T_UDERROR, T_ALL))
         == (struct t_uderr *) NULL) {
      t_error("t_alloc of t_uderr struct failed");
   while(1) {
      if (t_rcvudata(fd, ud, &flags) == -1) {
         if (t_errno == TLOOK) {
               /* Error on previously sent datagram */
               if(t_rcvuderr(fd, uderr) == -1) {
            fprintf(stderr, "bad datagram, error=%d\n",
         t_error("t_rcvudata failed");
       * Query() processes the request and places the response in
       * ud->udata.buf, setting ud->udata.len
      if (t_sndudata(fd, ud) == -1) {
         t_error("t_sndudata failed");

struct t_unitdate *ud;
   /* Merely a stub for simplicity */

To buffer datagrams, the server first allocates a t_unitdata structure, which has the following format:

struct t_unitdata {
 	struct netbuf addr;
 	struct netbuf opt;
 	struct netbuf udata;

addr holds the source address of incoming datagrams and the destination address of outgoing datagrams. opt holds any protocol options on the datagram. udata holds the data. The addr, opt, and udata fields must all be allocated with buffers large enough to hold any possible incoming values. The T_ALL argument of t_alloc(3NSL) ensures this and sets the maxlen field of each netbuf structure accordingly. The provider does not support protocol options in this example, so maxlen is set to 0 in the opt netbufstructure. The server also allocates a t_uderr structure for datagram errors.

The transaction server loops forever, receiving queries, processing the queries, and responding to the clients. It first calls t_rcvudata(3NSL) to receive the next query. t_rcvudata(3NSL) blocks until a datagram arrives, and returns it.

The second argument of t_rcvudata(3NSL) identifies the t_unitdata structure in which to buffer the datagram.

The third argument, flags, points to an integer variable and can be set to T_MORE on return from t_rcvudata(3NSL) to indicate that the user's udata buffer is too small to store the full datagram.

If this happens, the next call to t_rcvudata(3NSL) retrieves the rest of the datagram. Because t_alloc(3NSL) allocates a udata buffer large enough to store the maximum size datagram, this transaction server does not have to check flags. This is true only of t_rcvudata(3NSL) and not of any other receive primitives.

When a datagram is received, the transaction server calls its query routine to process the request. This routine stores a response in the structure pointed to by ud, and sets ud->udata.len to the number of bytes in the response. The source address returned by t_rcvudata(3NSL) in ud->addr is the destination address for t_sndudata(3NSL). When the response is ready, t_sndudata(3NSL) is called to send the response to the client.