[ Previous | Next | Contents | Search ]
AIXLink/X.25 1.1 for AIX: Guide and Reference

Processing Calls with the X.25 API

This API-level overview tells you how to use the application programming interface through the emulation port for both switched and permanent virtual circuits. The following refer to the example programs and discuss how the subroutines are used:

Initializing and Terminating

The application programming interface (API) must be initialized for a specific X.25 port before any other subroutines can be used on that port. If the program uses more than one X.25 port, the API must be initialized for each. Use the x25_init subroutine (as in example program svcxmit).

If the application uses a permanent virtual circuit (PVC), you must use the x25_pvc_alloc subroutine to allocate the PVC, identifying it by its logical channel number and X.25 port name (as in example program pvcxmit). Use SMIT to find out which logical channel numbers are valid.

A PVC must be freed, using the x25_pvc_free subroutine, before the program is terminated (as in example program pvcxmit).

You must terminate the API for each X.25 port, using the x25_term subroutine (as in example program svcxmit). However, before terminating the API for a port, do the following:

  1. Clear any calls, using x25_call_clear.
  2. Remove any counters, using x25_ctr_remove.
  3. Stop listening for calls, using x25_deafen.
  4. Free any permanent virtual circuits, using x25_pvc_free.

Using the Connection Identifier for Calls

Because the API or a single application can simultaneously control multiple virtual circuits, there must be a way of identifying a call uniquely. To do this, the API assigns to each call a positive integer known as the connection identifier.

The conn_id parameter is used by the API subroutines to pass the connection identifier.

Obtaining a Connection Identifier

On a switched virtual circuit, for an outgoing call, the connection identifier is returned by the x25_call subroutine (as in example program svcxmit). When receiving an incoming call the connection identifier is allocated by the x25_receive subroutine to the first of its parameters (as in example program svcrcv).

On a permanent virtual circuit, the connection identifier is returned by the x25_pvc_alloc subroutine (as in example program pvcxmit).

Using a Connection Identifier

The connection identifier is assigned on return from these subroutines:

The connection identifier is passed as a parameter to these subroutines:

Restrictions on the Use of the Connection Identifier

A connection identifier can be used only by the process that made the call, established the permanent virtual circuit, or received the call, and by that process' child processes. Any attempt to use the connection identifier of another process results in the X25BADCONNID error code.

Using Counters to Correlate Messages

Many applications use the network at once and each application may have several calls active at one time. An application may also be listening for calls for several different routing list names. How does the application know when a message has arrived on a particular virtual circuit, or for a particular call? A counter, supplied by the API, is incremented when a message arrives. The application issues an x25_ctr_wait subroutine, which returns when the counter has been incremented. The counter is decremented when the message has been received (using the x25_receive subroutine).

Counters allow an application to wait for messages on several virtual circuits at one time; it is the responsibility of the application to correlate counters with particular virtual circuits. Optionally, an application can use the x25_ctr_wait subroutine to accumulate several messages against a particular counter before being notified.

Counter Identifiers

Each counter has a counter identifier. The ctr_id parameter is used by some of the API subroutines to pass the counter identifier. The x25_ctr_wait subroutine uses an array of structures (ctr_array_struct) each of which contains a counter identifier and a value. This allows an application to wait for any of a number of counters to change.

Counters in Applications

You must decide how to use counters in your application depending on what the application has to do. Use of counters is not required, but the use of the x25_ctr_wait subroutine is the recommended way of notifying the application that a message has arrived.

For an application that makes calls, use a separate counter for each call. For an application that listens for and receives calls, use one counter to listen for incoming calls and then use a separate counter to accept each call and receive its subsequent messages. For an application that receives messages from any one of a number of connected calls, use a single counter.

The application is responsible for ensuring that it gets enough counters.

Obtaining a Counter

The application gets a counter from the API by calling the x25_ctr_get subroutine (as in example program svcxmit). This subroutine returns a counter identifier that is unique across the system.

The two applications (the one that makes a call and the one that receives it) each use a different counter for the call. Each tracks the messages independently.

Using a Counter

The counter identifier is passed as a parameter to the following subroutines:

Waiting for an Incoming Call or a Message

Normally, the x25_ctr_wait subroutine notifies an application program that a message has arrived. The program invokes the x25_ctr_wait subroutine, passing it a pointer to an array of counter structures. This enables an application to wait for messages from more than one call.

The example programs show the x25_ctr_wait subroutine being used in several situations, but always with only one counter. If you want to wait for messages using multiple counters, you must assign them all to the ctr_array_struct structure before invoking the x25_ctr_wait subroutine.

Note: If you are writing a program that uses multiple counters to identify multiple calls, you are responsible for storing the counter identifiers with their corresponding connection identifiers.
Example Uses of the x25_ctr_wait Subroutine
  1. Set up the ctr_array_struct structure and wait for an incoming call (as in example program svcrcv).
  2. Wait for an acknowledgement indicating that the ctr_array_struct structure was set up earlier in the program (as in example program svcxmit).
Determining How Many Messages Are Waiting to Be Received for a Call

The x25_ctr_test subroutine is provided to determine the number of messages waiting to be received for a call, as follows:

  1. Assign the counter identifier to the ctr_id parameter.
  2. Invoke the x25_ctr_test subroutine, passing ctr_id as a parameter.
  3. The return value is the number of messages waiting to be received.

However, if you use the x25_ctr_wait subroutine when expecting a message to arrive and receive every message when it arrives, you should not need to use the x25_ctr_test subroutine.

Removing a Counter

Before an application terminates, it must remove all counters in use. A counter cannot be removed while its value is greater than 0, indicating that there is a message to be received. First, receive any messages, and then use the x25_ctr_remove subroutine, passing it the counter identifier as a parameter (as in example program svcxmit).

Restrictions on the Use of Counters

Any application can test the value of a counter or wait for it to change. Only the application that requested the counter with the x25_ctr_get subroutine, or a root user, can remove the counter using use the x25_ctr_remove subroutine.

Listening for Incoming Calls

When it is listening for calls, the x25_listen subroutine uses a positive integer, the listen identifier, to identify an incoming call. After the call has been received and accepted, the listen identifier is used again to listen for subsequent incoming calls.

Obtaining a Listen Identifier

The x25_listen subroutine can be used to listen for incoming calls.

  1. Get a counter.
  2. Invoke the x25_listen subroutine, passing it two parameters: the counter identifier and the name of an entry in the X.25 routing list (as in example program svcrcv).
  3. The x25_listen subroutine returns a listen identifier.

Using the Listen Identifier

After obtaining a listen identifier, the application must wait for an incoming call. When an incoming call arrives for that listen identifier, the application assigns the listen identifier to the conn_id parameter and uses the x25_receive subroutine to receive the incoming call.

Removing the Listen Identifier (Stop Listening)
  1. Remove the counter associated with this listening process.
  2. Invoke the x25_deafen subroutine, passing it the listen identifier as a parameter. Always do this before terminating a program that has been listening for incoming calls (as in example program svcrcv).
Restrictions on the Use of the Listen Identifier

The use of this variable is restricted to the user who received the listen_id from the x25_listen subroutine. The user may have one application that listens and notifies the user of an incoming call, and another application that actually receives the call.

Making and Receiving a Call

The following information describes the processes involved in making and receiving a call.

Making an Outgoing Call

To make a call on a switched virtual circuit (SVC) (as in example program svcxmit):

  1. Set up the cb_call_struct with the relevant information.
  2. Invoke the x25_call subroutine, passing two parameters: a pointer to cb_call_struct and a counter identifier.
  3. The x25_call subroutine returns a connection identifier, which the application must use to identify the call.
  4. Store a counter identifier with the connection identifier.

When using a permanent virtual circuit (PVC), do not make any calls. Once you have allocated a PVC, you can send and receive data until you free the PVC.

After making a call, the calling application must wait for the called application's response, using the x25_ctr_wait subroutine, and then receive it, using the x25_receive subroutine (as in example program svcxmit). The response can be either a call-connected message or the clear-indication message.

Receiving an Incoming Call

When you know there is an incoming call waiting because the counter associated with the listen identifier has been incremented, you must use the listen identifier to receive the incoming call (as in example program svcrcv).

  1. Assign the listen identifier to the conn_id parameter.
  2. Invoke the x25_receive subroutine, passing two parameters:
  3. On return, the x25_receive subroutine assigns the connection identifier of the incoming call to the conn_id. (The listen identifier is still valid for further incoming calls.)
  4. On return from the x25_receive subroutine, the message control block includes the msg_type, which indicates the type of message (for example, X25_INCOMING_CALL) . You do not need to check it because it is the only message that can be received using the listen identifier. The cb_call_struct control block contains the incoming-call message, which may include call user data.
  5. Free any structures allocated by the x25_receive subroutine (as in example program svcrcv).

Accepting or Rejecting an Incoming Call

To accept an incoming call after receiving it (as in example program svcrcv):

  1. Get a new counter, to be used for accepting the call and receiving any subsequent messages for it. (This allows the counter that was used for listening to continue to be used to listen for calls.)
  2. Optionally, set up cb_call_struct with the relevant information.
  3. Invoke the x25_call_accept subroutine, passing the connection identifier, the counter identifier, and cb_call_struct as parameters.
  4. The x25_call_accept subroutine sends an X25_CALL_CONNECTED message, which must be received by the caller.

At this point, after accepting a call, you should deal with the call user data if necessary. After dealing with the call user data, free the storage used (as in example program svcrcv).

Instead of accepting an incoming call, you can reject it, using the x25_call_clear subroutine to clear it.

Transferring and Acknowledging Data

The following information describes the processes involved in transferring and acknowledging data.

Sending Data

Either the called or the calling application can send data when:

To send data (as in example program svcxmit):

  1. Ensure that any data sent previously with the D-bit set to a value of 1 has been acknowledged. Otherwise, this x25_send subroutine will fail.
  2. Assign to the data variable in cb_data_struct a pointer to the data you want to send.
  3. Assign to the data_len variable in cb_data_struct the length of the data.
  4. Invoke the x25_send subroutine, passing two parameters: the connection identifier and a pointer to cb_data_struct.

Asking for Receiver Acknowledgment of Data Sent

To ask for the receiver to acknowledge the data, set the flags to X25FLG_DBIT in cb_data_struct, before using the x25_send subroutine (as in example program svcxmit). The application must then wait for and receive the X25_DATA_ACK message that is sent back.

Note: To allow the use of the D-bit, it should also be set on the x25_call subroutine (as in example program svcxmit) or the x25_call_accept subroutine.

Long Messages

If the data length is greater than the packet size, the API automatically splits the data into packets which it sends separately. It sets on the M-bit in each packet to indicate that there is more data. Only the final packet has the D-bit set and only one acknowledgment is expected.

To allow better recovery in the event of a transmission failure, avoid sending data longer than the packet size. Specify as large a packet size as possible in the maximum transmit packet size attribute (for an SVC) or PVC maximum transmit packet size. Otherwise specify as large a packet size as possible in the psiz_cld or psiz_clg field in the cb_fac_struct. If necessary, split up the data yourself in the application, if you want to receive an acknowledgment for each packet, and thus maintain data integrity. Otherwise, if one piece of the data does not arrive, all of the data may need to be sent again.

Receiving Data

To receive data that has arrived for a particular call (as in example program svcrcv):

  1. Ensure that you have acknowledged any data received previously with the D-bit set to a value of 1. Otherwise this x25_receive subroutine will return X25NODATA.
  2. Invoke the x25_receive subroutine subroutine, passing the address of the connection identifier and the address of the message structure (cb_msg_struct) as parameters.
  3. The x25_receive subroutine receives a complete packet sequence. That is to say, if a long message was split up when it was sent, the X.25 API attempts to rebuild it before notifying the application that there is a message waiting. If any packet (other than data or interrupt) arrives before the sequence is completed, the attempt to rebuild is either abandoned and the sequence made available to the application up to its current position, or the incoming packet is made available to the application ahead of the as-yet-unfinished sequence.
  4. On return from the x25_receive subroutine, the message structure (cb_msg_struct) includes the msg_type, which indicates the type of message. In this case it is X25_DATA , indicating that the message is available in the cb_data_struct control block.
  5. The counter that indicated the waiting message is decremented when the message is received.

To receive data from any call that is currently connected, assign a value of 0 to the conn_id parameter and invoke the x25_receive subroutine, passing the address of conn_id as a parameter. On return from the x25_receive subroutine, the conn_id parameter contains the connection identifier of the call whose data was returned by x25_receive subroutine.

Acknowledging Data Packets

For each data packet that was sent with the D-bit set to 1, invoke the x25_ack subroutine to confirm that it arrived (as in example program svcrcv).

The application should ensure that the acknowledgment is given as soon as possible after receiving a message with the D-bit set to 1.

Clearing, Resetting, and Interrupting Calls

The following information describes the processes involved in clearing, resetting, and interrupting calls.

Clearing a Call

Clearing removes the call from the network. You can send a clear-request message to reject a call, after receiving fast-select data, to terminate a call, or to clear a call.

If you clear a call without ever accepting it, you are, in effect, rejecting it.

If it is a fast-select call, the fast-select data is in the incoming-call packet. You can clear the call immediately after receiving this or you can receive further messages on the call.

Clearing is the normal way of terminating a call. Either the caller or the called application can clear a call. To clear a call:

  1. Optionally, assign any data you want to send to the user_data field in the cb_clear_struct control block, and set the user-data flag.
  2. Optionally, assign a cause code and a diagnostic code to the appropriate fields in the cb_clear_struct control block, and set the appropriate flags.
  3. Invoke the x25_call_clear, passing the connection identifier and a pointer to cb_clear_struct as parameters. The third parameter can be used for return data. If you do not need this, set the third parameter to null.

Example program svcxmit shows how a call is cleared.

Note: Example program svcrcv could have cleared the call after receiving the data; the svcxmit program is therefore prepared for the call to be cleared by the other application. A call does not have to be cleared by the application that made it.

Resetting a Call

A reset flushes any data being sent from the network at the time of the reset. To reset a call (as in example program pvcxmit):

  1. Optionally, assign a cause code and a diagnostic code to the appropriate fields in the cb_res_struct control block and set the appropriate flags.
  2. Invoke the x25_reset subroutine, passing it the connection identifier and a pointer to the cb_res_struct control block.
  3. Wait for and receive the reset-confirmation message.

When an application receives a message of X25_RESET_INDICATION , it must send a reset-confirmation message immediately by invoking the x25_reset_confirm subroutine (as in example program pvcrcv).

Interrupting a Call

An interrupt is placed at the beginning of the queue of incoming messages. To send an interrupt:

  1. Assign the connection identifier to the conn_id parameter.
  2. Invoke the x25_interrupt subroutine, passing it the conn_id parameter and a pointer to the cb_int_data_struct control block.
  3. Wait for and receive the interrupt-confirmation message. (Using this X.25 API, the interrupt-confirmation message is sent automatically.)

[ Previous | Next | Contents | Search ]