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:
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:
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.
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).
The connection identifier is assigned on return from these subroutines:
The connection identifier is passed as a parameter to these subroutines:
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.
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.
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.
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.
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.
The counter identifier is passed as a parameter to the following subroutines:
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.
The x25_ctr_test subroutine is provided to determine the number of messages waiting to be received for a call, as follows:
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.
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).
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.
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.
The x25_listen subroutine can be used to listen for incoming calls.
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.
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.
The following information describes the processes involved in making and receiving a call.
To make a call on a switched virtual circuit (SVC) (as in example program svcxmit):
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.
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).
To accept an incoming call after receiving it (as in example program svcrcv):
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.
The following information describes the processes involved in transferring and acknowledging data.
Either the called or the calling application can send data when:
To send data (as in example program svcxmit):
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.
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.
To receive data that has arrived for a particular call (as in example program svcrcv):
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.
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.
The following information describes the processes involved in clearing, resetting, and interrupting calls.
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:
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.
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):
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).
An interrupt is placed at the beginning of the queue of incoming messages. To send an interrupt: