Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Connectionless service using an example transaction system

&pagelevel(4)&pagelevel

The connectionless service is explained in more detail using an example transaction system: The server waits for incoming requests and then processes and answers them.

Local management using an example transaction system

As with the connection-oriented service, the user has to execute the local management before transferring data. The user has to call an appropriate connectionless service with t_open() and then bind his address to the transport endpoint with t_bind().

The user can employ the t_optmgmt() function to change the protocol features. As with the connection-oriented service, each transport provider has its own features. Using t_optmgmt() therefore makes the programs dependent on the protocol used.

The server executes the local management with the following definitions and calls:

#include <stdio.h>
#include <fcntl.h>
#include <xti.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SRV_ADDR 0x7F000001
#define SRV_PORT 8888
main()
{
   int fd;
   nt flags;
   struct t_bind *bind;
   struct t_unitdata *ud;
   struct t_uderr *uderr;
   struct sockaddr_in *sin
   if ((fd = t_open("/dev/udp", O_RDWR, NULL)) < 0) {
      t_error("The transport provider cannot be opened");
      exit(1);
   }
   if ((bind = (struct t_bind *)t_alloc(fd,T_BIND, T_ADDR)) == NULL) {
      t_error("t_alloc() of the t_bind structure failed");
      exit(2);
   }
   bind->addr.len=sizeof(struct sockaddr_in);
   sin=(struct sockaddr_in *)bind->addr.buf;
   sin->sin_family=AF_INET;
   sin->sin_port=htons(SRV_PORT);
   sin->sin_addr.s_addr=htonl(SRV_ADDR);
   bind->qlen = 0;
   if (t_bind(fd, bind, bind) < 0) {
      t_error("t_bind() failed");
      exit(3);
   }

The server creates a transport endpoint by calling t_open().

The server uses t_bind() to bind a specific address to the transport endpoint, to enable potential clients to recognize and access the server. The server uses t_alloc() to create an object of data type t_bind and supplies the buf and len components with appropriate values in the addr component of the t_bind object. The address itself is structured according to the address structure of the Internet communications domain.

One important difference between the connection-oriented and connectionless services is that the contents of the t_bind qlen component are meaningless in the connectionless service: all user datagrams can be received as soon as the t_bind() call has ended. During connection setup with the connection-oriented service, the transport provider defines a client/server relationship. Such a relationship does not exist with the connectionless mode. In this example, it is not the transport provider that defines a client/server relationship, but rather the application type.

Data transfer using an example transaction system

As soon as the user has bound an address to the transport endpoint, he can send and receive datagrams. Each message sent is accompanied by the address of the receiver.

The following series of calls show the server in the data transfer phase:

   if ((ud = (struct t_unitdata *)t_alloc(fd,T_UNITDATA, T_ALL)) == NULL) {
      t_error("t_alloc() of the t_unitdata structure failed");
      exit(5);
   }
   if ((uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL)) == NULL) {
      t_error("t_alloc() of the t_uderr structure failed");
      exit(6);
   }
   for(;;) {
      if (t_rcvudata(fd, ud, &flags) < 0) {
         if (t_errno == TLOOK) {
                 /*
                  *  Error with a previously sent datagram
                  */
                 if (t_rcvuderr(fd, uderr) < 0) {
                 t_error(„t_rcverr failed“);
                 exit(7);
                 }
                 fprintf(stderr,
                 "Faulty datagram, error = %d \n",
                 uderr->error);
                 continue;
         }
      t_error("t_rcvudata() failed");
      exit(8);
      }
      /*
       * query() processes the request and writes the reply
       * in ud->udata.buf and the length in ud->udata.len
       */
      query(ud);
      if (t_sndudata(fd, ud, 0) < 0) {
         t_error("t_sndudata() failed");
         exit(9);
      }
   }
}
query()
{
/* Only an extract, for simplification reasons */
}

To store datagrams, the server must first create an object of data type struct t_unitdata with t_alloc().

The t_unitdata structure is declared in <xti.h> as follows:

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

addr contains the address of the sender for incoming datagrams and the address of the receiver for outgoing datagrams. opt specifies possible options of the employed protocol that are to be used on this datagram. udata contains the user data. addr, buf and udata must be provided with buffers of sufficient size to store incoming datagrams. As described in section "Connection-oriented service", this is ensured by specifying T_ALL with the t_alloc() call. The maxlen component of each component (of type struct netbuf) of the created t_unitdata object is supplied with an appropriate value by t_alloc().

The server also creates an object of type struct t_uderr for processing datagram errors (see below).

The server runs in an endless loop. It receives requests, processes them and replies to the clients. t_rcvudata() is called first to receive the next request. t_rcvudata() receives the next possible datagram. If no datagrams are available, t_rcvudata() blocks the process until a datagram is received. The second parameter of the t_rcvudata() call specifies the t_unitdata object in which the datagram is to be stored.

The third parameter (flags) must be a pointer to an integer value. This value can be set to T_MORE when t_rcvudata() is ended to indicate that the udata buffer was not large enough to accept the complete datagram. In this case, additional t_rcvudata() calls supply the remaining part of the datagram.

Since the buffer in this example was created with t_alloc(), this case cannot occur and the server does not need to test flags.

Once a datagram has been successfully received, the server calls query() to process the request.

Datagram errors

If the transport provider cannot process a datagram passed with t_sndudata(), a T_UDERR error is reported to the user. With this error, the datagram address and options are returned together with a protocol-dependent error value. The described condition can, for example, occur if the transport provider does not find the specified destination address.

It is expected that each protocol defines all causes for a datagram not being sent.

The error indication does not provide information as to whether the datagram was successfully sent. The transport protocol decides how the error indication is used. It must be emphasized once more at this point that the connectionless service does not guarantee reliable data delivery.

The server is informed of the error as soon as it tries to receive a datagram. The t_rcvudata() call fails and t_errno is set to TLOOK. If t_errno is set to TLOOK, only an T_UDERR can have occurred so the server calls t_rcvuderr() to determine the cause of the error. The second parameter of the t_rcvuderr() call is a previously created object of data type struct t_uderr. This object is supplied with values by the t_rcvuderr() call.

The t_uderr structure is declared in <xti.h> as follows:

struct t_uderr {
   struct netbuf addr;
   struct netbuf opt;
   long error;};

addr and opt specify the destination address and the options set for this datagram. error indicates a protocol-dependent error value which specifies why the datagram was not processed. The server outputs the error value and then returns to the normal loop.